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

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


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

SDK для TypeScript поддерживает четыре класса аутентификации OAuth, а также прямое использование токенов.

МетодПример использованияТребуется взаимодействие с пользователем?Требуется секретный ключ клиента?
Статический токенБыстрые сценарии, тестирование или если у вас уже есть токенНетНет
Межсерверная аутентификацияСерверные службы, задачи планировщика, автоматизацияНетДа
Веб-приложениеСерверные приложения (Express, Fastify, Next.js)ДаДа
Одностраничное приложение (PKCE)Браузерные приложения, которые не могут хранить секретный ключДаНет
Встроенное приложение (PKCE)Приложения для ПК/мобильных устройств с перенаправлением через пользовательские схемы URIДаНет
Межсерверная аутентификация позволяет приложению действовать как сервисная учетная запись без участия пользователя. Доступна только для учетных записей Frame.io V4, управляемых через Adobe Admin Console. Процессы веб-приложения и одностраничного приложения позволяют приложению действовать от имени конкретного пользователя. Оба процесса используют архитектуру Adobe IMS: пользователь авторизует приложение, после чего SDK обменивает полученный код на токены. SDK для TypeScript полностью берет на себя выполнение процессов IMS /authorize/v2 и /token/v3. Для веб-приложения требуется секретный ключ клиента, а для одностраничного приложения используется PKCE. Встроенное приложение использует тот же процесс с PKCE, что и одностраничное приложение, но применяет URI перенаправления adobe+<hash>://callback</hash>, который Adobe автоматически закрепляет за вашими учетными данными встроенного приложения. Это позволяет вашему приложению перехватывать перенаправление на уровне ОС после авторизации.

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

При использовании межсерверной аутентификации ваше приложение выступает в роли пользователя сервисной учетной записи — отдельного типа учетной записи, которая может выполнять действия от имени сервиса. Эти действия видны другим пользователям в 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
$npm install frameio

Выбор метода

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

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

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

1import { FrameioClient } from "frameio";
2
3const client = new FrameioClient({ token: "YOUR_ACCESS_TOKEN" });

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

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

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

1import { FrameioClient } from "frameio";
2
3const client = new FrameioClient({
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. Ваше приложение проходит аутентификацию как пользователь сервисной учетной записи без участия человека.

1import { FrameioClient, ServerToServerAuth } from "frameio";
2
3const auth = new ServerToServerAuth({
4 clientId: "YOUR_CLIENT_ID",
5 clientSecret: "YOUR_CLIENT_SECRET",
6});
7
8const client = new FrameioClient({ token: () => auth.getToken() });

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

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

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

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

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

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

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

1const auth = new ServerToServerAuth({ clientId: "...", clientSecret: "..." });
2await auth.authenticate(); // throws AuthenticationError if credentials are invalid
3const client = new FrameioClient({ token: () => auth.getToken() });

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

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

1

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

1 import { WebAppAuth } from "frameio";
2 import crypto from "crypto";
3
4 const auth = new WebAppAuth({
5 clientId: "YOUR_CLIENT_ID",
6 clientSecret: "YOUR_CLIENT_SECRET",
7 redirectUri: "https://yourapp.com/callback",
8 });
9
10 // Generate a cryptographically random state value to prevent CSRF attacks
11 const state = crypto.randomBytes(32).toString("hex");
12
13 const authorizationUrl = auth.getAuthorizationUrl({ state });
14 // Store `state` in the user's session, then redirect them to `authorizationUrl`
2

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

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

1 // In your callback handler (e.g. an Express route):
2 await auth.exchangeCode(req.query.code as string);

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

3

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

1 import { FrameioClient } from "frameio";
2
3 const client = new FrameioClient({ token: () => auth.getToken() });

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

Полный пример для Express

1import crypto from "crypto";
2import express from "express";
3import session from "express-session";
4import { FrameioClient, WebAppAuth } from "frameio";
5
6const auth = new WebAppAuth({
7 clientId: "YOUR_CLIENT_ID",
8 clientSecret: "YOUR_CLIENT_SECRET",
9 redirectUri: "http://localhost:3000/callback",
10});
11
12const app = express();
13app.use(session({ secret: crypto.randomBytes(32).toString("hex"), resave: false, saveUninitialized: false }));
14
15app.get("/login", (req, res) => {
16 const state = crypto.randomBytes(32).toString("hex");
17 (req.session as any).oauthState = state;
18 res.redirect(auth.getAuthorizationUrl({ state }));
19});
20
21app.get("/callback", async (req, res) => {
22 if (req.query.state !== (req.session as any).oauthState) {
23 return res.status(403).send("Invalid state parameter");
24 }
25
26 await auth.exchangeCode(req.query.code as string);
27
28 const client = new FrameioClient({ token: () => auth.getToken() });
29 const accounts = await client.accounts.index();
30 res.json(accounts);
31});
32
33app.listen(3000);

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

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

1

Создание URL-адреса авторизации

1 import { SPAAuth } from "frameio";
2
3 const auth = new SPAAuth({
4 clientId: "YOUR_CLIENT_ID",
5 redirectUri: "https://yourapp.com/callback",
6 });
7
8 const state = crypto.randomUUID();
9 const result = await auth.getAuthorizationUrl({ state });
10 // result.url -> redirect the user here
11 // result.codeVerifier -> store this securely until the callback

Метод getAuthorizationUrl возвращает объект AuthorizationUrlResult, содержащий полный URL-адрес (с встроенной строкой PKCE code_challenge) и строку codeVerifier, которая понадобится вам на следующем шаге.

2

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

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

1 await auth.exchangeCode({
2 code: "CODE_FROM_CALLBACK",
3 codeVerifier: result.codeVerifier,
4 });
3

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

1 import { FrameioClient } from "frameio";
2
3 const client = new FrameioClient({ token: () => auth.getToken() });

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

Ключ codeVerifier должен надежно храниться на стороне клиента в промежутке между запросом авторизации и обменом кода. Используйте хранилище sessionStorage или аналогичный механизм в браузерных приложениях.


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

Используйте этот метод при работе с приложениями для ПК и мобильных устройств. При создании учетных данных встроенного приложения в Adobe Developer Console Adobe назначает вам URI перенаправления вида adobe+<hash>://callback</hash>. Вам необходимо зарегистрировать свое приложение для обработки этой пользовательской схемы URI на уровне операционной системы. Перенаправление на локальный адрес (http://127.0.0.1:<port>/callback</port>) также поддерживается при локальной разработке. Процесс идентичен одностраничному приложению: в нем используется PKCE без секретного ключа клиента.

1import { NativeAppAuth } from "frameio";
2
3const auth = new NativeAppAuth({
4 clientId: "YOUR_CLIENT_ID",
5 redirectUri: "adobe+abc123def456://callback", // from your Adobe Developer Console Native App credential
6 // Also supports loopback: "http://127.0.0.1:8080/callback"
7});
8
9const { url, codeVerifier } = await auth.getAuthorizationUrl({
10 state: crypto.randomUUID(),
11});
12
13// Open system browser to `url`
14// Listen for redirect on your custom URI scheme or loopback server
15
16await auth.exchangeCode({ code: "CODE_FROM_REDIRECT", codeVerifier });
17const client = new FrameioClient({ token: () => auth.getToken() });

Правила URI перенаправления

Adobe применяет правила проверки URI перенаправления в двух точках: когда вы регистрируете учетные данные в Adobe Developer Console и когда параметр redirect_uri достигает конечной точки /authorize/v2. Значение, которое вы передаете в redirectUri внутри SDK, должно соответствовать одному из шаблонов URI перенаправления, заданных в ваших учетных данных. В противном случае Adobe перенаправит пользователя на адрес по умолчанию.

  • Учетные данные в процессах веб-приложения и одностраничного приложения требуют использования протокола HTTPS.
  • Учетные данные в процессах встроенного приложения используют перенаправление без HTTPS — обычно это URI вида adobe+<hash>://callback</hash>, указанный для этих данных в Developer Console.

Точные шаблоны, поддерживаемые вашими учетными данными, можно посмотреть в Adobe Developer Console.

В состав SDK для Python не входит класс учетных данных для встроенных приложений, поскольку в Python нет стандартного способа регистрации обработчиков

пользовательских схем URI. SDK для TypeScript поддерживает все четыре типа учетных данных, включая данные для встроенного приложения.


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

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

1await auth.refresh(); // fetches a new access token using the refresh token

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

Метод refresh() доступен в классах WebAppAuth, SPAAuth и NativeAppAuth. Он выдает ошибку ConfigurationError, если токен обновления отсутствует (то есть сначала нужно вызвать exchangeCode()). В процессе ServerToServerAuth метод refresh() отсутствует — вместо этого для получения нового токена через учетные данные клиента используется метод authenticate().


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

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

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

1// After exchangeCode(), save the token state
2const tokenData = auth.exportTokens();
3// tokenData is: { 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.importTokens(tokenData);
8const client = new FrameioClient({ token: () => auth.getToken() });
9// The SDK will automatically refresh if the token is near expiry

Экспортированные токены должны храниться в безопасности. Они содержат токены доступа и обновления, которые предоставляют доступ к API-интерфейсу. Избегайте записи токенов

в текстовые файлы в производственной среде.

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

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

1import fs from "fs/promises";
2
3const TOKEN_FILE = "tokens.json";
4
5const auth = new WebAppAuth({
6 clientId: "...",
7 clientSecret: "...",
8 redirectUri: "...",
9 onTokenRefreshed: (tokens) => {
10 fs.writeFile(TOKEN_FILE, JSON.stringify(tokens));
11 },
12});
13
14// On startup, restore if available
15try {
16 const saved = JSON.parse(await fs.readFile(TOKEN_FILE, "utf-8"));
17 auth.importTokens(saved);
18} catch {
19 // No saved tokens — user will need to authenticate
20}

Функция обратного вызова принимает словарь того же формата, что и exportTokens(), и срабатывает после каждого успешного обновления токена.


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

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

1await auth.revoke();

Этот метод отправляет в Adobe IMS два параллельных запроса на аннулирование токенов по принципу наилучших усилий (один — для токена доступа, второй — для токена обновления), а затем очищает все локальные данные о состоянии токенов. Для конфиденциальных клиентов (WebAppAuth) запросы на аннулирование токенов используют базовую HTTP-аутентификацию, а для публичных клиентов (SPAAuth, NativeAppAuth) в строке запроса передается параметр client_id. Ошибки отзыва регистрируются в журнале, но не генерируют исключение. После отзыва токенов пользователю потребуется пройти аутентификацию заново.


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

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

1import {
2 FrameioAuthError,
3 AuthenticationError,
4 TokenExpiredError,
5 ConfigurationError,
6 NetworkError,
7 RateLimitError,
8} from "frameio";
9
10try {
11 await auth.exchangeCode("...");
12} catch (error) {
13 if (error instanceof TokenExpiredError) {
14 // The refresh token has expired; redirect the user to sign in again
15 } else if (error instanceof AuthenticationError) {
16 // Token exchange failed
17 console.error(`Error: ${error.errorCode} - ${error.errorDescription}`);
18 } else if (error instanceof NetworkError) {
19 // Timeout or connection failure (after retries)
20 } else if (error instanceof RateLimitError) {
21 // 429 from Adobe IMS; retry after error.retryAfter seconds
22 } else if (error instanceof FrameioAuthError) {
23 // Catch-all for any other auth error
24 }
25}

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

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

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

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

1import { TokenExpiredError } from "frameio";
2
3try {
4 const client = new FrameioClient({ token: () => auth.getToken() });
5 const assets = await client.files.list({ projectId: "..." });
6} catch (error) {
7 if (error instanceof TokenExpiredError) {
8 // Clear persisted tokens and redirect user to login
9 await auth.revoke();
10 return res.redirect("/login");
11 }
12}

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

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

ПараметрПо умолчаниюОписание
scopesЗависит от выбранного процессаОбласти доступа OAuth, разделенные пробелами. Для сценария S2S по умолчанию используются значения openid AdobeID frame.s2s.all; для пользовательских процессов — openid email profile offline_access additional_info.roles.
imsBaseUrlhttps://ims-na1.adobelogin.comБазовый URL-адрес Adobe IMS. Переопределите его для работы в тестовых или непроизводственных средах. Обязательно использование HTTPS.
fetchglobalThis.fetchПользовательская реализация функции fetch для прокси, mTLS или пользовательской обработки HTTP.
timeout30000Время ожидания запроса HTTP в миллисекундах при вызове конечных точек токенов.
maxRetries2Максимальное количество повторных попыток при временных сбоях (ошибки 5xx, таймауты). Повторные попытки при превышении лимита запросов (ошибки 429) отслеживаются отдельно.
refreshBuffer60Количество секунд до истечения срока действия токена, при котором запускается упреждающее обновление.
onTokenRefreshedundefinedФункция обратного вызова, которая срабатывает после каждого успешного обновления токена. Принимает объект со свойствами access_token, refresh_token и expires_at.
loggerЗаглушка (без вывода)Экземпляр логгера со стандартными методами debug, info, warn, error (например, console, pino, winston).

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

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

1const auth = new ServerToServerAuth({
2 clientId: "...",
3 clientSecret: "...",
4 imsBaseUrl: "https://ims-na1-stg1.adobelogin.com",
5});

Пользовательская функция fetch

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

1import { ProxyAgent } from "undici";
2
3const proxyAgent = new ProxyAgent("http://corporate-proxy:8080");
4
5const auth = new ServerToServerAuth({
6 clientId: "...",
7 clientSecret: "...",
8 fetch: (url, init) => fetch(url, { ...init, dispatcher: proxyAgent }),
9});

Безопасность при параллельном использовании

SDK для TypeScript безопасен при параллельном использовании. Если одновременно происходит несколько вызовов метода getToken() в момент, когда требуется обновление токена, выполняется только один запрос на обновление. Остальные вызовы ожидают выполнения этого же промиса и получают идентичный результат. Никаких внешних механизмов блокировки не требуется. Такое устранение дубликатов реализуется за счет однопоточного цикла событий JavaScript и общего промиса Promise. Если запрос на обновление уже выполняется, параллельные вызовы просто подключаются к нему вместо выполнения повторного запроса. Если метод revoke() вызывается в момент, когда выполняется обновление токена, процесс обновления отклоняется с ошибкой AuthenticationError, а токены удаляются — операция отзыва всегда имеет наивысший приоритет.