Frame.io TypeScript SDK — Authentication Guide
Frame.io TypeScript SDK — Authentication Guide
This guide explains how to authenticate with the Frame.io API using the Frame.io TypeScript SDK (frameio). The Frame.io V4 API uses Adobe Identity Management Service (IMS), Adobe’s OAuth 2.0 identity platform.
This is a standalone reference for TypeScript/JavaScript developers. All code examples and flows below are for the frameio package only.
Authentication Types in the TypeScript SDK
The TypeScript SDK supports four OAuth authentication classes, plus direct token usage:
Server-to-Server lets your app act as a service account with no user interaction. It’s only available to Frame.io V4 accounts administered via the Adobe Admin Console.
Web App and SPA let your app act as a specific user. Both use Adobe IMS under the hood: the user authorizes your app, and the SDK exchanges the resulting code for tokens. The TypeScript SDK handles the IMS /authorize/v2 and /token/v3 flow for you. For Web App you need a client secret; for SPA you use PKCE instead.
Native App follows the same PKCE flow as SPA but uses the adobe+<hash>://callback redirect URI that Adobe assigns to your Native App credential. This lets your application intercept the redirect at the OS level after authorization.
Service Account Users
When you use Server-to-Server authentication, your application acts as a service account user, a distinct account type that can perform actions on behalf of the service. These are visible to other users in Frame.io: when a service account takes an action, its name is displayed in the UI.
You can grant and revoke service account access through the Adobe Admin Console and Developer Console. Service account names are managed from the Frame.io UI. By default, your first S2S connection is named Service Account User, the second Service Account User 2, and so on.
See Automate your setup using Frame.io server to server support for more information.
Quick Start
Prerequisites
-
Credentials from the Adobe Developer Console:
- Client ID — required for all OAuth flows
- Client Secret — required for Server-to-Server and Web App flows
- Redirect URI — required for Web App, SPA, and Native App flows; must be registered in your Adobe project
-
Install the SDK:
Choosing a method
- No user involved? Use Server-to-Server (
ServerToServerAuth). - User involved and you can store a secret? Use Web App (
WebAppAuth). - User involved but you can’t store a secret? Use SPA (
SPAAuth) for browser apps, or Native App (NativeAppAuth) for desktop/mobile apps.
Access Token
If you already have an access token (from another OAuth system or a prior exchange, e.g. via our API Explorer) you can pass it directly:
This is the simplest approach, but the token will eventually expire and the SDK won’t refresh it for you.
Legacy Developer Tokens
For V4-migrated accounts not yet administered via the Adobe Admin Console, you can continue to use Legacy Developer Tokens from the Frame.io developer site. You must include the x-frameio-legacy-token-auth header and set it to true:
Legacy developer tokens do not expire, but they are a transitional mechanism. For new integrations and production workloads, we recommend using one of the OAuth 2.0 flows below. See the Migration Guide for details.
Server-to-Server (Client Credentials)
Use this for backend services and scripts that need Frame.io access without user interaction. This flow is only available to Frame.io V4 accounts administered via the Adobe Admin Console. Your application authenticates as a service account user with no human in the loop.
That’s it. auth.getToken() is an async function that the SDK invokes on every request. If the current token is still valid, it returns immediately. If it’s about to expire, it fetches a new one first, completely transparently.
How it works
Your client credentials (client ID + secret) never expire. You only rotate them manually for security hygiene. S2S gives you effectively permanent, uninterrupted API access with zero manual intervention.
Under the hood:
- On the first API call,
getToken()requests a new access token from Adobe IMS using theclient_credentialsgrant. - The token is cached in memory. Individual access tokens expire (typically 24 hours), but this is handled for you.
- When a cached token is within the refresh buffer (default: 60 seconds before expiry), the SDK fetches a fresh one automatically using the same client credentials.
- No refresh tokens are involved. The client credentials themselves are the long-lived secret, and they can always be used to mint a new access token.
Explicit authentication
If you want to fetch the token eagerly (for example, to fail fast on bad credentials at startup):
Web App (Authorization Code)
Use this for server-side applications where users sign in with their Adobe ID. This flow requires a client secret, which must be stored securely on your server.
Full Express example
Single Page App / PKCE (Authorization Code + PKCE)
Use this for browser-based applications, desktop apps, or CLI tools that cannot securely store a client secret. This flow uses PKCE (RFC 7636) to protect the authorization code exchange.
The codeVerifier must be stored securely on the client side between the authorization request and the code
exchange. Use sessionStorage or equivalent in browser apps.
Native App (Authorization Code + PKCE)
Use this for desktop and mobile applications. When you create a Native App credential in the Adobe Developer Console, Adobe assigns you a redirect URI of the form adobe+<hash>://callback — you register your application to handle that custom URI scheme at the OS level. Loopback redirects (http://127.0.0.1:<port>/callback) are also supported for local development. The flow is identical to SPA — it uses PKCE with no client secret.
Redirect URI rules
Adobe enforces redirect URI rules at two points: when you register the credential in the Adobe Developer Console, and when the redirect_uri parameter hits the /authorize/v2 endpoint. The value you pass to redirectUri in this SDK must match one of the “Redirect URI patterns” you registered on the credential — otherwise Adobe redirects to the Default Redirect URI on the credential instead.
- Web App and SPA credentials require HTTPS.
- Native App credentials use a non-HTTPS redirect — typically the
adobe+<hash>://callbackURI shown in the Developer Console for the credential.
See the Adobe Developer Console for the exact patterns accepted for your credential.
The Python SDK does not include a Native App credential class, since Python has no standard way to register custom URI scheme handlers. The TypeScript SDK supports all four credential types including Native App.
Manual Token Refresh
For Web App, SPA, and Native App flows, the SDK refreshes tokens automatically via getToken(). If you need explicit control, you can call refresh() directly:
This is useful when you want to force a refresh ahead of a critical operation rather than relying on the automatic refresh buffer.
refresh() is available on WebAppAuth, SPAAuth, and NativeAppAuth. It throws ConfigurationError if no refresh token is available (i.e. you must call exchangeCode() first). ServerToServerAuth does not have a refresh() method — it uses authenticate() to fetch a new token via client credentials instead.
Token Persistence
All auth classes support exportTokens() and importTokens() for persisting token state across restarts. For Web App, SPA, and Native App flows this is especially important, since the access and refresh tokens live in memory by default — if your application restarts, users would need to re-authenticate unless you persist them. For Server-to-Server, persistence is optional (the client credentials can always mint a new token), but importing a cached token avoids an extra round-trip on startup.
Export and import
Store exported tokens securely. They contain access and refresh tokens that grant API access. Avoid writing tokens to plaintext files in production.
Automatic persistence with onTokenRefreshed
To persist tokens automatically every time they’re refreshed, use the onTokenRefreshed callback:
The callback receives the same shape as exportTokens() and fires after every successful token refresh.
Revoking Tokens
To sign out a user and invalidate their tokens with Adobe IMS:
This makes two best-effort revocation requests to Adobe IMS — one for the access token and one for the refresh token, in parallel — and clears all local token state. For confidential clients (WebAppAuth), revocation requests use HTTP Basic Auth; for public clients (SPAAuth, NativeAppAuth), the client_id is sent as a query parameter. Revocation errors are logged but not thrown. After revoking, the user will need to re-authenticate.
Error Handling
All auth errors inherit from FrameioAuthError, so you can catch them broadly or handle specific cases:
Error reference
Handling expired refresh tokens in production
For Web App, SPA, and Native App flows, the refresh token will eventually expire. When that happens, getToken()
raises TokenExpiredError. You should catch this and redirect the user through the authorization flow again.
Configuration Reference
These parameters have sensible defaults and rarely need to be set. If you do need to customize behavior — pointing at a staging IMS, injecting a custom fetch, tuning timeouts, or wiring up a logger — pass any of them as optional parameters when constructing the auth class:
Staging environments
Point at a staging Adobe IMS instance by overriding imsBaseUrl. The SDK also exports DEFAULT_IMS_BASE_URL (https://ims-na1.adobelogin.com) if you need to reference the production value programmatically.
Custom fetch
For proxy support or custom TLS configuration:
Concurrency Safety
The TypeScript SDK is safe for concurrent use. When multiple getToken() calls happen simultaneously and a refresh is needed, only one refresh request fires. The others await the same promise and receive the same result. No external locking is required.
This deduplication uses JavaScript’s single-threaded event loop and a shared Promise — if a refresh is already in flight, concurrent callers join it instead of starting a second request.
If revoke() is called while a refresh is in flight, the refresh is rejected with an AuthenticationError and tokens remain cleared — the revocation always wins.