SDK Frame.io для Python — руководство по аутентификации

В этом руководстве объясняется, как выполнять аутентификацию с помощью API-интерфейса Frame.io, используя SDK Frame.io для Python (frameio). API-интерфейс Frame.io V4 использует службу Adobe Identity Management Service (IMS) — платформу идентификации Adobe на базе протокола OAuth 2.0. Это отдельное справочное руководство для Python-разработчиков. Все приведенные ниже примеры кода и рабочие процессы относятся исключительно к пакету frameio.


Типы аутентификации в SDK для Python

SDK для Python поддерживает четыре варианта аутентификации.

МетодПример использованияТребуется взаимодействие с пользователем?Требуется секретный ключ клиента?
Статический токенБыстрые сценарии, тестирование или если у вас уже есть токенНетНет
Межсерверная аутентификацияСерверные службы, задачи планировщика, автоматизацияНетДа
Веб-приложениеСерверные приложения (Flask, Django, FastAPI)ДаДа
Одностраничное приложение (PKCE)Браузерные приложения, интерфейсы CLI или любые приложения, которые не могут хранить секретный ключДаНет
Межсерверная аутентификация позволяет приложению действовать как сервисная учетная запись без участия пользователя. Доступна только для учетных записей Frame.io V4, управляемых через Adobe Admin Console. Процессы веб-приложения и одностраничного приложения позволяют приложению действовать от имени конкретного пользователя. Оба процесса используют архитектуру Adobe IMS: пользователь авторизует приложение, после чего SDK обменивает полученный код на токены. SDK для Python полностью берет на себя выполнение процессов IMS /authorize/v2 и /token/v3. Для веб-приложения требуется секретный ключ клиента, а для одностраничного приложения используется PKCE.

Учетные данные встроенного приложения Adobe требуют настройки пользовательских обработчиков схем URI (например, adobe+<hash>://…</hash>), которые перехватывают перенаправления на уровне ОС. В Python нет стандартного способа регистрации таких обработчиков, поэтому в SDK для Python отсутствует класс NativeAppAuth. Для интерактивных приложений Python используйте WebAppAuth с локальным сервером обратного вызова (например, Flask или FastAPI). Для неинтерактивных рабочих нагрузок используйте ServerToServerAuth.


Пользователи сервисных учетных записей

При использовании межсерверной аутентификации ваше приложение выступает в роли пользователя сервисной учетной записи — отдельного типа учетной записи, которая может выполнять действия от имени сервиса. Эти действия видны другим пользователям в Frame.io: когда сервисная учетная запись выполняет какое-либо действие, ее имя отображается в интерфейсе. Вы можете предоставлять и отзывать права доступа сервисных учетных записей через Adobe Admin Console и Developer Console. Управление именами сервисных учетных записей осуществляется через интерфейс Frame.io. По умолчанию ваше первое межсерверное подключение (S2S) называется Service Account User, второе — Service Account User 2 и так далее.


Быстрый старт

Предварительные требования

  1. Учетные данные из Adobe Developer Console
  • Client ID — требуется для всех процессов OAuth - секретный ключ клиента — требуется для процессов S2S и веб-приложения - URI перенаправления — требуется для процессов веб-приложения и одностраничного приложения (SPA); должен быть зарегистрирован в вашем проекте Adobe
  1. Установка SDK
$pip install frameio

Выбор метода

  • Пользователь не участвует? Используйте межсерверную аутентификацию (ServerToServerAuth).
  • Пользователь участвует и вы можете хранить секретный ключ? Используйте веб-приложение (WebAppAuth).
  • Пользователь участвует, но вы не можете хранить секретный ключ? Используйте одностраничное приложение (SPAAuth).

Токен доступа

Если у вас уже есть токен доступа, полученный из другой системы OAuth или в результате предыдущего обмена (например, через наш API-интерфейс Explorer), вы можете передать его напрямую.

1from frameio import Frameio
2
3client = Frameio(token="YOUR_ACCESS_TOKEN")

Это самый простой подход, но срок действия токена со временем истечет, и SDK не будет обновлять его автоматически.

Устаревшие токены разработчика

Для учетных записей, переведенных на версию V4, которые еще не управляются через Adobe Admin Console, можно продолжать использовать устаревшие токены разработчика с сайта Frame.io Developer. При этом необходимо добавить заголовок x-frameio-legacy-token-auth и установить его значение на true.

1from frameio import Frameio
2
3client = Frameio(
4 token="YOUR_LEGACY_DEVELOPER_TOKEN",
5 headers={"x-frameio-legacy-token-auth": "true"},
6)

Устаревшие токены разработчика не истекают, но они являются переходным механизмом. Для новых интеграций и производственных нагрузок мы рекомендуем использовать один из приведенных ниже процессов OAuth 2.0. Подробнее — в руководстве по миграции.


Межсерверная аутентификация (учетные данные клиента)

Используйте этот метод для серверных сервисов и сценариев, которым нужен доступ к Frame.io без участия пользователя. Этот процесс доступен только для учетных записей Frame.io V4, управляемых через Adobe Admin Console. Ваше приложение проходит аутентификацию как пользователь сервисной учетной записи без участия человека.

1 from frameio import Frameio
2 from frameio.auth import ServerToServerAuth
3
4 auth = ServerToServerAuth(
5 client_id="YOUR_CLIENT_ID",
6 client_secret="YOUR_CLIENT_SECRET",
7 )
8
9 client = Frameio(token=auth.get_token)

Готово. auth.get_token — это вызываемый объект, который SDK запускает при каждом запросе. Если текущий токен все еще действителен, он возвращается мгновенно. Если срок его действия подходит к концу, метод сначала запрашивает новый токен без всякого вашего участия.

Как это работает

Ваши учетные данные клиента (идентификатор клиента + секретный ключ) не имеют срока действия. Вы меняете их только вручную в целях безопасности. Метод S2S обеспечивает фактически бессрочный и бесперебойный доступ к API-интерфейсу без какого-либо ручного вмешательства.

Архитектура процесса

  1. При первом вызове API-интерфейса метод get_token запрашивает новый токен доступа от Adobe IMS, используя тип разрешения client_credentials.
  2. Токен кэшируется в памяти. Срок действия отдельных токенов доступа ограничен (обычно 24 часа), но SDK берет управление этим процессом на себя.
  3. При попадании кэшированного токена в буфер обновления (по умолчанию за 60 секунд до истечения) SDK автоматически получает новый токен, используя те же учетные данные клиента.
  4. Токены обновления не используются. Сами учетные данные клиента являются долговременным секретным ключом, который всегда можно использовать для выпуска нового токена доступа.

Явная аутентификация

Если вы хотите получить токен заранее (например, чтобы быстро выявить ошибку на этапе запуска, если учетные данные неверны), используйте следующий метод.

1auth = ServerToServerAuth(client_id="...", client_secret="...")
2auth.authenticate() # raises AuthenticationError if credentials are invalid
3client = Frameio(token=auth.get_token)

Веб-приложение (код авторизации)

Используйте этот метод для серверных приложений, в которых пользователи выполняют вход с помощью Adobe ID. В этом процессе требуется секретный ключ клиента, который должен безопасно храниться на вашем сервере.

1

Перенаправление пользователя в Adobe IMS

1 auth.refresh() # fetches a new access token using the refresh token
2

Обработка обратного вызова

Когда Adobe IMS перенаправляет пользователя обратно на ваш redirect_uri, извлеките параметры code и state. Убедитесь в соответствии состояния тому, что вы сохранили, затем обменяйте код на токены.

1 auth.refresh() # fetches a new access token using the refresh token

Этот процесс производит обмен кода авторизации на токен доступа и токен обновления, сохраняя их оба во внутренней памяти.

3

Использование клиента

1 from frameio import Frameio
2
3 client = Frameio(token=auth.get_token)

Готово. С этого момента метод get_token автоматически управляет жизненным циклом токена. Когда срок действия токена доступа подходит к концу, SDK использует токен обновления для получения нового. Участия пользователя не требуется.

Полный пример реализации на Flask

1import secrets
2from flask import Flask, redirect, request, session
3from frameio import Frameio
4from frameio.auth import WebAppAuth
5
6app = Flask(__name__)
7app.secret_key = secrets.token_bytes(32)
8
9auth = WebAppAuth(
10 client_id="YOUR_CLIENT_ID",
11 client_secret="YOUR_CLIENT_SECRET",
12 redirect_uri="http://localhost:5000/callback",
13)
14
15@app.route("/login")
16def login():
17 state = secrets.token_urlsafe(32)
18 session["oauth_state"] = state
19 return redirect(auth.get_authorization_url(state=state))
20
21@app.route("/callback")
22def callback():
23 if request.args.get("state") != session.pop("oauth_state", None):
24 return "Invalid state parameter", 403
25
26 auth.exchange_code(code=request.args["code"])
27
28 client = Frameio(token=auth.get_token)
29 accounts = client.accounts.index()
30 return f"Authenticated — {len(accounts.data)} account(s) accessible."

Одностраничное приложение / PKCE (код авторизации + PKCE)

Используйте этот метод для браузерных приложений, программ для ПК или инструментов командной строки (CLI), которые не могут безопасно хранить секретный ключ клиента. В этом процессе используется расширение PKCE (RFC 7636), чтобы защитить обмен кода авторизации. <Steps>

<Step title=“Создание URL-адреса авторизации”>

<Tabs>

1 from frameio.auth import SPAAuth
2
3 auth = SPAAuth(
4 client_id="YOUR_CLIENT_ID",
5 redirect_uri="https://yourapp.com/callback",
6 )
7
8 import secrets
9 state = secrets.token_urlsafe(32)
10
11 result = auth.get_authorization_url(state=state)
12 # result.url -> redirect the user here
13 # result.code_verifier -> store this securely until the callback
1 from frameio.auth import AsyncSPAAuth
2
3 auth = AsyncSPAAuth(
4 client_id="YOUR_CLIENT_ID",
5 redirect_uri="https://yourapp.com/callback",
6 )
7
8 # get_authorization_url is synchronous (no I/O needed)
9 import secrets
10 state = secrets.token_urlsafe(32)
11
12 result = auth.get_authorization_url(state=state)

</div>Метод

get_authorization_url возвращает объект AuthorizationUrlResult, содержащий полный URL-адрес (с встроенной строкой PKCE code_challenge) и строку code_verifier, которая понадобится вам на следующем шаге. </Step>

1

Обмен кода с проверочной строкой

Когда пользователь перенаправляется обратно, используется следующий метод.

1 from frameio import Frameio
2
3 client = Frameio(token=auth.get_token)

Готово. Обновление работает так же, как и в процессе веб-приложения — SDK использует токен обновления автоматически. Разница заключается в том, что при обновлении не отправляется секретный ключ клиента, поскольку сценарий SPA разработан специально для публичных клиентов.

</Steps>


Асинхронное использование

Каждому классу аутентификации соответствует его асинхронный аналог с префиксом Async. Приведенные выше примеры кода содержат вкладки Синхронный и Асинхронный, где это применимо.

СинхронныйАсинхронный
ServerToServerAuthAsyncServerToServerAuth
WebAppAuthAsyncWebAppAuth
SPAAuthAsyncSPAAuth
API-интерфейс полностью идентичен. Метод get_authorization_url остается синхронным (без операции ввода-вывода), в то время как exchange_code, refresh, revoke и get_token являются асинхронными (async). Используйте асинхронные классы с AsyncFrameio.

Ручное обновление токена

В процессах веб-приложения и одностраничного приложения SDK обновляет токены автоматически с помощью метода get_token. Если вам нужен явный контроль над этим процессом, вы можете вызвать метод refresh() напрямую.

1 auth.refresh() # fetches a new access token using the refresh token

Это полезно, когда нужно принудительно обновить токен перед выполнением критически важной операции, вместо того чтобы полагаться на автоматический буфер обновления.


Сохранение токенов

Все классы аутентификации поддерживают методы export_tokens() и import_tokens() для сохранения состояния токенов между перезапусками приложения. Для процессов веб-приложения и одностраничного приложения это особенно важно, поскольку токены доступа и обновления по умолчанию хранятся в памяти. Если ваше приложение перезапустится, пользователям придется проходить аутентификацию заново, если только вы не сохранили токены. Для межсерверной аутентификации сохранение необязательно (учетные данные клиента всегда могут выпустить новый токен), но импорт кэшированного токена позволяет избежать лишнего цикла запроса-ответа при запуске.

Экспорт и импорт

1# After exchange_code(), save the token state
2token_data = auth.export_tokens()
3# token_data is a dict: {"access_token": "...", "refresh_token": "...", "expires_at": 1234567890.0}
4# Save it to your database, file, or secret store
5
6# On next startup, restore it
7auth.import_tokens(token_data)
8client = Frameio(token=auth.get_token)
9# The SDK will automatically refresh if the token is near expiry

Автоматическое сохранение с помощью функции on_token_refreshed

Чтобы автоматически сохранять токены при каждом их обновлении, используйте функцию обратного вызова on_token_refreshed.

1import json
2from pathlib import Path
3
4TOKEN_FILE = Path("tokens.json")
5
6def save_tokens(tokens: dict):
7 TOKEN_FILE.write_text(json.dumps(tokens))
8
9auth = WebAppAuth(
10 client_id="...",
11 client_secret="...",
12 redirect_uri="...",
13 on_token_refreshed=save_tokens,
14)
15
16# On startup, restore if available
17if TOKEN_FILE.exists():
18 auth.import_tokens(json.loads(TOKEN_FILE.read_text()))

Функция обратного вызова принимает словарь того же формата, что и export_tokens(), и срабатывает после каждого успешного обновления токена. Для асинхронных классов on_token_refreshed может быть как обычной функцией, так и асинхронной (async). Поддерживаются оба варианта.


Отзыв токенов

Чтобы выполнить выход пользователя из системы и аннулировать его токены в Adobe IMS, используется следующий метод.

1auth.revoke()

Этот метод отправляет в Adobe IMS запрос на аннулирование токена доступа и токена обновления по принципу наилучших усилий, а затем очищает все локальные данные о состоянии токенов. После отзыва токенов пользователю потребуется пройти аутентификацию заново.

Для асинхронных классов используйте await auth.revoke().


Обработка ошибок

Все ошибки аутентификации наследуются от FrameioAuthError, поэтому вы можете перехватывать их в общем блоке или обрабатывать конкретные случаи отдельно.

1from frameio.auth import (
2 FrameioAuthError,
3 AuthenticationError,
4 TokenExpiredError,
5 ConfigurationError,
6 NetworkError,
7 RateLimitError,
8)
9
10try:
11 auth.exchange_code(code="...")
12except TokenExpiredError:
13 # The refresh token has expired; redirect the user to sign in again
14 pass
15except AuthenticationError as e:
16 # Token exchange failed
17 print(f"Error: {e.error_code} - {e.error_description}")
18except NetworkError:
19 # Timeout or connection failure (after retries)
20 pass
21except RateLimitError as e:
22 # 429 from Adobe IMS; retry after e.retry_after seconds
23 pass
24except FrameioAuthError:
25 # Catch-all for any other auth error
26 pass

Справочник по ошибкам

ИсключениеКогда возникает
ConfigurationErrorОтсутствует или указана неверная конфигурация (например, пустой client_id, URI перенаправления без поддержки HTTPS).
AuthenticationErrorОбмен или обновление токена отклонены со стороны Adobe IMS (содержит .error_code и .error_description).
TokenExpiredErrorИстек срок действия самого токена обновления; пользователю необходимо пройти аутентификацию заново.
NetworkErrorИстекло время ожидания HTTP-запроса или произошел сбой подключения после исчерпания всех повторных попыток.
RateLimitErrorСервис Adobe IMS вернул ошибку 429; используйте .retry_after для определения времени задержки перед повторным запросом.
PKCEErrorСбой проверки PKCE (процесс SPA).

Обработка истекших токенов обновления в производстве

В процессах веб-приложения и SPA срок действия токена обновления со временем истекает. Когда это происходит, метод get_token генерирует исключение TokenExpiredError. Вам следует перехватить эту ошибку и перенаправить пользователя на повторное прохождение процедуры авторизации.

1from frameio.auth import TokenExpiredError
2
3try:
4 client = Frameio(token=auth.get_token)
5 assets = client.files.list(project_id="...")
6except TokenExpiredError:
7 # Clear persisted tokens and redirect user to login
8 auth.revoke()
9 return redirect("/login")

Справочник по конфигурации

Все классы аутентификации принимают следующие дополнительные параметры.

ПараметрПо умолчаниюОписание
scopesЗависит от выбранного процессаОбласти доступа OAuth, разделенные пробелами. Для сценария S2S по умолчанию используются значения openid AdobeID frame.s2s.all; для пользовательских процессов — openid email profile offline_access additional_info.roles.
ims_base_urlhttps://ims-na1.adobelogin.comБазовый URL-адрес Adobe IMS. Переопределите его для работы в тестовых или непроизводственных средах.
http_clientНетПользовательский клиент httpx.Client (или httpx.AsyncClient) для прокси, mTLS или пула подключений.
timeout30Время ожидания запроса HTTP в секундах при вызове конечных точек токенов.
max_retries2Максимальное количество повторных попыток при временных сбоях (ошибки 5xx, таймауты). Повторные попытки при превышении лимита запросов (ошибки 429) отслеживаются отдельно.
refresh_buffer60Количество секунд до истечения срока действия токена, при котором запускается упреждающее обновление.
on_token_refreshedНетФункция обратного вызова, которая срабатывает после каждого успешного обновления токена. Принимает словарь, содержащий access_token, refresh_token и expires_at.

Тестовые среды

Чтобы перенаправить запросы на тестовый экземпляр Adobe IMS, переопределите параметр ims_base_url. SDK также экспортирует константу DEFAULT_IMS_BASE_URL (https://ims-na1.adobelogin.com) если вам необходимо программно ссылаться на значение, используемое в производственной среде.

1auth = ServerToServerAuth(
2 client_id="...",
3 client_secret="...",
4 ims_base_url="https://ims-na1-stg1.adobelogin.com",
5)

Пользовательский HTTP-клиент

Для поддержки прокси или пользовательской конфигурации TLS используйте следующий метод.

1import httpx
2
3http_client = httpx.Client(
4 proxy="http://corporate-proxy:8080",
5 verify="/path/to/custom-ca-bundle.pem",
6)
7
8auth = ServerToServerAuth(
9 client_id="...",
10 client_secret="...",
11 http_client=http_client,
12)

Безопасность потоков

Синхронные классы аутентификации полностью потокобезопасны. Если несколько потоков одновременно вызывают метод get_token в момент, когда требуется обновление, только один поток выполняет это обновление. Остальные потоки ожидают и получают тот же результат. Никаких внешних механизмов блокировки не требуется. Асинхронные классы обеспечивают такую же гарантию безопасности с помощью механизма asyncio.Lock, что делает их безопасными для одновременного использования несколькими сопрограммами в рамках одного цикла событий.