Guide d’authentification du SDK TypeScript de Frame.io

Ce guide explique comment s’authentifier auprès de l’API Frame.io à l’aide du SDK TypeScript Frame.io (frameio). L’API Frame.io V4 utilise le service Adobe Identity Management (IMS), la plateforme d’authentification OAuth 2.0 d’Adobe. Il s’agit d’un guide de référence autonome destiné aux développeurs TypeScript/JavaScript. Tous les exemples de code et les flux ci-dessous concernent exclusivement le package frameio.


Types d’authentification dans le SDK TypeScript

Le SDK TypeScript prend en charge quatre classes d’authentification OAuth, ainsi que l’utilisation directe de jeton :

MéthodeCas d’usageInteraction utilisateur ?Nécessite un secret client ?
Jeton statiqueScripts rapides, test ou vous avez déjà un jetonNonNon
De serveur à serveurServices backend, tâches cron, automatisationNonOui
Application webApplications côté serveur (Express, Fastify, Next.js)OuiOui
SPA (PKCE)Applications web qui ne peuvent pas stocker un secretOuiNon
Application native (PKCE)Applications de bureau ou mobiles avec redirections de schéma URI personnaliséOuiNon
Serveur à serveur permet à votre application d’agir comme un compte de service sans interaction utilisateur. Disponible uniquement pour les comptes Frame.io V4 gérés via l’Adobe Admin Console. Appli web et SPA permettent à votre application d’agir comme un utilisateur spécifique. Les deux utilisent Adobe IMS en arrière-plan : l’utilisateur autorise votre application et le SDK échange le code résultant contre des jetons. Le SDK TypeScript gère le flux IMS /authorize/v2 et /token/v3 pour vous. Pour une application web, vous avez besoin d’un secret client ; pour une SPA, utilisez PKCE à la place. L’Application native suit le même flux PKCE que SPA, mais utilise l’URI de redirection adobe+<hash>://callback</hash> qu’Adobe attribue à vos informations d’identification d’application native. Cela permet à votre application d’intercepter la redirection au niveau du système d’exploitation après autorisation.

Utilisateurs de comptes de service

Lorsque vous utilisez l’authentification de serveur à serveur, votre application agit en tant qu’utilisateur de compte de service, un type de compte distinct qui peut effectuer des actions au nom du service. Ces informations sont visibles par les autres utilisateurs de Frame.io : lorsqu’un compte de service effectue une action, son nom s’affiche dans l’interface utilisateur. Vous pouvez accorder ou révoquer l’accès à un compte de service via l’Adobe Admin Console et la Developer Console. Les noms des comptes de service sont gérés depuis l’interface utilisateur de Frame.io. Par défaut, votre première connexion S2S est nommée Service Account User, la deuxième ** Service Account User 2**, et ainsi de suite.


Démarrage rapide

Conditions préalables

  1. Informations d’identification de l’Adobe Developer Console :
  • ID client (obligatoire pour tous les flux OAuth), Secret client (obligatoire pour les flux serveur à serveur et les flux d’application web), URI de redirection (obligatoire pour les flux d’application web, d’applications natives et SPA). Ces informations doivent être enregistrées dans votre projet Adobe.
  1. Installer le SDK :
npm install frameio

Choisir une méthode

  • Aucun utilisateur n’est concerné ? Utilisez l’authentification serveur à serveur (ServerToServerAuth).
  • L’utilisateur est concerné et vous pouvez enregistrer un secret ? Utilisez l’authentification par application web (WebAppAuth).
  • L’utilisateur est concerné et vous ne pouvez pas enregistrer un secret ? Utilisez SPA (SPAAuth) pour les applications web, ou l’Application native (NativeAppAuth) pour les applications de bureau et mobiles.

Jeton d’accès

Si vous disposez déjà d’un jeton d’accès (provenant d’un autre système OAuth ou d’un échange précédent, par exemple via notre Explorateur des API), vous pouvez le transmettre directement :

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

C’est la méthode la plus simple, mais le jeton finira par expirer et le SDK ne le renouvellera pas pour vous.

Jetons de développeur hérités

Pour les comptes ayant migré vers la version 4 et qui ne sont pas encore gérés via l’Adobe Admin Console, vous pouvez continuer à utiliser les jetons de développeur hérités disponibles sur le site des développeurs Frame.io. Vous devez inclure l’en-tête x-frameio-legacy-token-auth et le configurer sur true :

import { FrameioClient } from "frameio";
const client = new FrameioClient({
token: "YOUR_LEGACY_DEVELOPER_TOKEN",
headers: { "x-frameio-legacy-token-auth": "true" },
});

Les jetons de développeur hérités n’expirent pas, mais ils constituent un mécanisme transitoire. Pour les nouvelles intégrations et les charges de travail en production, nous vous recommandons d’utiliser l’un des flux OAuth 2.0 ci-dessous. Pour plus de détails, consultez le guide de migration.


Authentification de serveur à serveur (Informations d’identification)

Utilisez cette option pour les services et scripts backend qui nécessitent un accès à Frame.io sans intervention de l’utilisateur. Ce flux n’est disponible que pour les comptes Frame.io V4 gérés via l’Adobe Admin Console. Votre application s’authentifie en tant qu’utilisateur de compte de service sans intervention humaine.

import { FrameioClient, ServerToServerAuth } from "frameio";
const auth = new ServerToServerAuth({
clientId: "YOUR_CLIENT_ID",
clientSecret: "YOUR_CLIENT_SECRET",
});
const client = new FrameioClient({ token: () => auth.getToken() });

Et voilà. auth.getToken() est une fonction asynchrone que le SDK appelle à chaque requête. Si le jeton actuel est toujours valide, il est renvoyé immédiatement. S’il est sur le point d’expirer, le système en récupère d’abord un nouveau, de manière totalement transparente.

Fonctionnement

Vos informations d’identification client (ID client + secret) n’expirent jamais. Vous ne les changez manuellement que pour des raisons de sécurité. L’authentification S2S vous offre un accès à l’API pratiquement permanent et ininterrompu, sans aucune intervention manuelle.

En coulisses :

  1. Lors du premier appel d’API, getToken() présente une requête pour obtenir un nouveau jeton d’accès à Adobe IMS en utilisant le mode d’octroi client_credentials.
  2. Le jeton est mis en cache en mémoire. Les jetons d’accès individuels expirent (généralement au bout de 24 heures), mais cette gestion est prise en charge pour vous.
  3. Lorsqu’un jeton mis en cache se trouve dans la mémoire tampon d’actualisation (par défaut : 60 secondes avant son expiration), le SDK en récupère automatiquement un nouveau en utilisant les mêmes informations d’identification.
  4. Aucun jeton d’actualisation n’est utilisé. Les informations d’identification du client constituent en elles-mêmes un secret à long terme et peuvent toujours être utilisées pour générer un nouveau jeton d’accès.

Authentification explicite

Si vous souhaitez récupérer le jeton dès le début (par exemple, pour détecter rapidement les informations d’identification incorrectes au démarrage) :

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

Application web (code d’autorisation)

Utilisez cette option pour les applications côté serveur dans lesquelles les utilisateurs se connectent à l’aide de leur Adobe ID. Ce flux nécessite un secret client, qui doit être stocké en toute sécurité sur votre serveur.

1

Rediriger l’utilisateur vers Adobe IMS

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

Gérer le rappel

Lorsqu’Adobe IMS redirige l’utilisateur vers votre redirectUri, extrayez les paramètres code et state. Vérifiez que l’état correspond bien à ce que vous avez enregistré, puis échangez le code contre des jetons :

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

Cette opération permet d’échanger le code d’autorisation contre un jeton d’accès et un jeton d’actualisation, qui sont tous deux enregistrés en interne.

3

Utiliser le client

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

Et voilà. À partir de ce point, getToken() gère automatiquement le cycle de vie du jeton. Lorsque le jeton d’accès arrive à expiration, le SDK utilise le jeton d’actualisation pour en obtenir un nouveau. Aucune intervention de l’utilisateur n’est nécessaire.

Exemple Express complet

import crypto from "crypto";
import express from "express";
import session from "express-session";
import { FrameioClient, WebAppAuth } from "frameio";
const auth = new WebAppAuth({
clientId: "YOUR_CLIENT_ID",
clientSecret: "YOUR_CLIENT_SECRET",
redirectUri: "http://localhost:3000/callback",
});
const app = express();
app.use(session({ secret: crypto.randomBytes(32).toString("hex"), resave: false, saveUninitialized: false }));
app.get("/login", (req, res) => {
const state = crypto.randomBytes(32).toString("hex");
(req.session as any).oauthState = state;
res.redirect(auth.getAuthorizationUrl({ state }));
});
app.get("/callback", async (req, res) => {
if (req.query.state !== (req.session as any).oauthState) {
return res.status(403).send("Invalid state parameter");
}
await auth.exchangeCode(req.query.code as string);
const client = new FrameioClient({ token: () => auth.getToken() });
const accounts = await client.accounts.index();
res.json(accounts);
});
app.listen(3000);

Application monopage / PKCE (code d’autorisation + PKCE)

Utilisez cette option pour les applications web, les applications de bureau ou les outils en ligne de commande qui ne peuvent pas stocker un secret client en toute sécurité. Ce flux utilise le protocole PKCE (RFC 7636) pour sécuriser l’échange de codes d’autorisation.

1

Générer l’URL d’autorisation

import { SPAAuth } from "frameio";
const auth = new SPAAuth({
clientId: "YOUR_CLIENT_ID",
redirectUri: "https://yourapp.com/callback",
});
const state = crypto.randomUUID();
const result = await auth.getAuthorizationUrl({ state });
// result.url -> redirect the user here
// result.codeVerifier -> store this securely until the callback

getAuthorizationUrl renvoie un AuthorizationUrlResult contenant l’URL complète (avec le PKCE code_challenge intégré) et le codeVerifier dont vous aurez besoin à l’étape suivante.

2

Échanger le code avec le vérificateur

Lorsque l’utilisateur est redirigé de retour :

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

Utiliser le client

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

Et voilà. La mise à jour fonctionne de la même manière que pour l’application web : le SDK utilise automatiquement le jeton de mise à jour. La différence réside dans le fait qu’aucun secret client n’est transmis lors de l’actualisation, car le flux SPA est conçu pour les clients publics.

Le codeVerifier doit être stocké en toute sécurité côté client entre la requête d’autorisation et l’échange de code. Utilisez sessionStorage ou un équivalent dans les applications de navigateur.


Application native (code d’autorisation + PKCE)

Utilisez cette option pour les applications de bureau et mobiles. Lorsque vous créez des informations d’identification pour une application native dans l’Adobe Developer Console, Adobe vous affecte un URI de redirection sous la forme adobe+<hash>://callback</hash> – vous enregistrez votre application pour gérer ce schéma d’URI personnalisé au niveau du système d’exploitation. Les redirections en boucle (http://127.0.0.1:<port>/callback</port>) sont également prises en charge pour le développement local. Le flux est identique à celui de SPA : il utilise PKCE sans secret client.

import { NativeAppAuth } from "frameio";
const auth = new NativeAppAuth({
clientId: "YOUR_CLIENT_ID",
redirectUri: "adobe+abc123def456://callback", // from your Adobe Developer Console Native App credential
// Also supports loopback: "http://127.0.0.1:8080/callback"
});
const { url, codeVerifier } = await auth.getAuthorizationUrl({
state: crypto.randomUUID(),
});
// Open system browser to `url`
// Listen for redirect on your custom URI scheme or loopback server
await auth.exchangeCode({ code: "CODE_FROM_REDIRECT", codeVerifier });
const client = new FrameioClient({ token: () => auth.getToken() });

Règles relatives aux URI de redirection

Adobe applique les règles relatives aux URI de redirection à deux moments : lorsque vous enregistrez vos informations d’identification dans l’Adobe Developer Console, et lorsque le paramètre redirect_uri est envoyé au point d’entrée /authorize/v2. La valeur que vous transmettez à redirectUri dans ce SDK doit correspondre à l’un des « schémas d’URI de redirection » que vous avez enregistrés dans les informations d’identification ; dans le cas contraire, Adobe effectuera la redirection vers l’URI de redirection par défaut associé à ces informations d’identification.

  • Les informations d’identification pour les applications web et les SPA nécessitent le protocole HTTPS.
  • Les informations d’identification des applications natives utilisent une redirection non HTTPS, généralement adobe+<hash>://callback</hash> URI affichée dans la Developer Console pour les informations d’identification.

Consultez l’Adobe Developer Console pour connaître les formats exacts acceptés pour vos informations d’identification.

Le SDK Python ne comprend pas de classe d’informations d’identification pour les applications natives, car Python ne dispose pas de méthode standard pour enregistrer des informations d’identification personnalisées.

Gestionnaires de schémas d’URI. Le SDK TypeScript prend en charge les quatre types d’informations d’identification, y compris les applications natives.


Actualisation manuelle des jetons

Pour les flux d’applications web, de SPA et d’applications natives, le SDK actualise automatiquement les jetons via getToken(). Si vous avez besoin d’un contrôle explicite, vous pouvez appeler refresh() directement :

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

Cela s’avère utile lorsque vous souhaitez forcer une actualisation avant une opération critique, plutôt que de compter sur la mémoire tampon d’actualisation automatique.

refresh() est disponible sur WebAppAuth, SPAAuth et NativeAppAuth. Il renvoie ConfigurationError si aucun jeton d’actualisation n’est disponible (c’est-à-dire que vous devez appeler exchangeCode() en premier). ServerToServerAuth n’a pas de méthode refresh() : il utilise authenticate() pour récupérer un nouveau jeton à l’aide des informations d’identification du client à la place.


Persistance des jetons

Toutes les classes d’authentification prennent en charge les méthodes exportTokens() et importTokens() pour conserver l’état des jetons entre les redémarrages. Cela revêt une importance particulière pour les flux des applications web, des SPA et des applications natives, car les jetons d’accès et d’actualisation sont conservés en mémoire par défaut : si votre application redémarre, les utilisateurs devront se réauthentifier, à moins que vous ne les conserviez en mémoire. Pour les communications de serveur à serveur, la persistance est facultative (les informations d’identification du client permettent toujours de générer un nouveau jeton), mais l’importation d’un jeton mis en cache évite un aller-retour supplémentaire au démarrage.

Exporter et importer

// After exchangeCode(), save the token state
const tokenData = auth.exportTokens();
// tokenData is: { access_token: "...", refresh_token: "...", expires_at: 1234567890.0 }
// Save it to your database, file, or secret store
// On next startup, restore it
auth.importTokens(tokenData);
const client = new FrameioClient({ token: () => auth.getToken() });
// The SDK will automatically refresh if the token is near expiry

Conservez les jetons exportés en toute sécurité. Ils contiennent des jetons d’accès et d’actualisation qui permettent d’accéder à l’API. Évitez d’enregistrer des jetons

sous forme de fichiers de texte brut en environnement de production.

Persistance automatique avec onTokenRefreshed

Pour conserver automatiquement les jetons à chaque fois qu’ils sont actualisés, utilisez le rappel onTokenRefreshed :

import fs from "fs/promises";
const TOKEN_FILE = "tokens.json";
const auth = new WebAppAuth({
clientId: "...",
clientSecret: "...",
redirectUri: "...",
onTokenRefreshed: (tokens) => {
fs.writeFile(TOKEN_FILE, JSON.stringify(tokens));
},
});
// On startup, restore if available
try {
const saved = JSON.parse(await fs.readFile(TOKEN_FILE, "utf-8"));
auth.importTokens(saved);
} catch {
// No saved tokens — user will need to authenticate
}

Le rappel reçoit la même structure que exportTokens() et se déclenche après chaque actualisation réussie des jetons.


Révocation des jetons

Pour déconnecter un utilisateur et invalider ses jetons avec Adobe IMS :

await auth.revoke();

Cette opération envoie deux requêtes de révocation (au mieux) à Adobe IMS (l’une pour le jeton d’accès et l’autre pour le jeton d’actualisation, en parallèle) et efface l’état de tous les jetons locaux. Pour les clients confidentiels (WebAppAuth), les requêtes de révocation utilisent l’authentification HTTP de base ; pour les clients publics (SPAAuth, NativeAppAuth), le client_id est envoyé en tant que paramètre de requête. Les erreurs de révocation sont consignées dans le journal, mais ne sont pas levées. Une fois l’accès révoqué, l’utilisateur devra s’authentifier à nouveau.


Gestion des erreurs

Toutes les erreurs d’authentification sont dérivées de FrameioAuthError. Vous pouvez donc les traiter de manière globale ou gérer des cas particuliers :

import {
FrameioAuthError,
AuthenticationError,
TokenExpiredError,
ConfigurationError,
NetworkError,
RateLimitError,
} from "frameio";
try {
await auth.exchangeCode("...");
} catch (error) {
if (error instanceof TokenExpiredError) {
// The refresh token has expired; redirect the user to sign in again
} else if (error instanceof AuthenticationError) {
// Token exchange failed
console.error(`Error: ${error.errorCode} - ${error.errorDescription}`);
} else if (error instanceof NetworkError) {
// Timeout or connection failure (after retries)
} else if (error instanceof RateLimitError) {
// 429 from Adobe IMS; retry after error.retryAfter seconds
} else if (error instanceof FrameioAuthError) {
// Catch-all for any other auth error
}
}

Références des erreurs

ExceptionDéclenchée dans les cas suivants
ConfigurationErrorConfiguration manquante ou non valide (p. ex. client_id vide, URI de redirection non HTTPS, imsBaseUrl non HTTPS)
AuthenticationErrorRefus de l’échange ou de l’actualisation du jeton par Adobe IMS (avec .errorCode et .errorDescription)
TokenExpiredErrorLe jeton d’actualisation a expiré ; l’utilisateur doit se réauthentifier
NetworkErrorDélai d’attente HTTP ou échec de la connexion après toutes les tentatives
RateLimitErrorAdobe IMS a renvoyé 429 ; vérifier .retryAfter pour des recommandations sur le délai d’attente
PKCEErrorMise à disposition des utilisateurs dans les flux PKCE ; n’est pas générée en interne par le SDK.

Gestion des jetons d’actualisation expirés en production

Pour les flux des applications web, des SPA et des applications natives, le jeton d’actualisation finira par expirer. Quand cela arrive, getToken() déclenche TokenExpiredError. Vous devriez détecter cette situation et rediriger l’utilisateur vers le flux d’autorisation.

import { TokenExpiredError } from "frameio";
try {
const client = new FrameioClient({ token: () => auth.getToken() });
const assets = await client.files.list({ projectId: "..." });
} catch (error) {
if (error instanceof TokenExpiredError) {
// Clear persisted tokens and redirect user to login
await auth.revoke();
return res.redirect("/login");
}
}

Référence de configuration

Ces paramètres ont des valeurs par défaut raisonnables et il est rarement nécessaire de les modifier. Si vous devez personnaliser le comportement (p. ex., en indiquant un IMS d’évaluation, en injectant une requête fetch personnalisée, en ajustant les délais d’expiration ou en configurant un enregistreur de journaux), transmettez ces paramètres en tant que paramètres facultatifs lors de la création de la classe d’authentification :

ParamètrePar défautDescription
portéesValeurs par défaut spécifiques au fluxPortées OAuth séparées par des espaces. Par défaut, l’authentification S2S est configurée sur openid AdobeID frame.s2s.all ; les flux destinés aux utilisateurs sont configurés par défaut sur openid email profile offline_access additional_info.roles.
imsBaseUrlhttps://ims-na1.adobelogin.comURL de base pour Adobe IMS. Remplacement pour les environnements de test ou hors production. Doit utiliser HTTPS.
fetchglobalThis.fetchRequête fetch personnalisée mise en œuvre pour les proxys, le protocole mTLS ou la gestion HTTP personnalisée.
délai d’expiration30000Délai d’expiration en millisecondes des requêtes HTTP pour les appels vers le point d’entrée des jetons.
maxRetries2Nombre maximal de tentatives en cas d’erreurs temporaires (codes 5xx, délais d’attente). Les tentatives de reconnexion en cas de dépassement de la limite de requêtes (429) sont comptabilisées séparément.
refreshBuffer60Secondes avant l’expiration du jeton pour déclencher une actualisation proactive.
onTokenRefreshedundefinedRappel déclenché après chaque actualisation réussie du jeton. Reçoit un objet avec access_token, refresh_token et expires_at.
loggerNo-op (silent)Instance d’enregistreur de journaux avec les méthodes debug, info, warn, error (soit console, pino, winston).

Environnements d’évaluation

Pointe vers une instance Adobe IMS d’évaluation en ignorant imsBaseUrl. Le SDK exporte également DEFAULT_IMS_BASE_URL (https://ims-na1.adobelogin.com) si vous devez accéder à la valeur de production par programmation.

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

Récupération personnalisée

Pour l’assistance relative aux serveurs proxy ou la configuration TLS personnalisée :

import { ProxyAgent } from "undici";
const proxyAgent = new ProxyAgent("http://corporate-proxy:8080");
const auth = new ServerToServerAuth({
clientId: "...",
clientSecret: "...",
fetch: (url, init) => fetch(url, { ...init, dispatcher: proxyAgent }),
});

Usage simultané sécurisé

Le SDK TypeScript est tout à fait compatible avec une utilisation en parallèle. Lorsque plusieurs appels getToken() ont lieu simultanément et qu’une actualisation est nécessaire, une seule requête d’actualisation est déclenchée. Les autres attendent la même promesse et obtiennent le même résultat. Aucun verrouillage externe n’est nécessaire. Cette déduplication utilise la boucle d’événements monothread de JavaScript et une promesse partagée : si une actualisation est déjà en cours, les requêtes simultanées s’y joignent au lieu de lancer une deuxième requête. Si revoke() est appelée alors qu’une actualisation est en cours, celle-ci est rejetée avec une AuthenticationError et les jetons restent invalides : la révocation prévaut toujours.