New to Corti authentication? Read the general Authentication Overview first to understand environments, tenants, and how to create API clients.
| Method | Environment | When to use |
|---|---|---|
| Client Credentials | Backend only | Recommended. Server-to-server integrations |
| Authorization Code | Frontend & Backend | Interactive user login (confidential clients) |
| PKCE | Frontend & Backend | Interactive user login (public clients, SPAs) |
| ROPC | Backend only | Username/password for trusted or internal apps |
| Bearer Token | Frontend & Backend | You already have a token from another source |
For complete examples of each flow, see the authentication examples in the examples repository.
Client Credentials
This is the recommended method for server-to-server applications. The SDK handles the full OAuth 2.0 token exchange and automatic refresh. Create aCortiClient with your credentials — token acquisition and refresh are automatic:
JavaScript
CortiAuth:
JavaScript
Authorization Code Flow
The standard OAuth2 authorization code flow for interactive user authentication. Use this when your application has a server component that can keep theclientSecret confidential.
Receive authorization code
The user is redirected back to your
redirectUri with a code query parameter:JavaScript
Exchange code for tokens
Pass Or exchange manually using the
code to CortiClient — it handles the exchange and refresh automatically:JavaScript
auth instance from step 1:JavaScript
Use tokens
The
client from the CortiClient path is ready to use. For the CortiAuth path, create a CortiClient with the returned accessToken using the Bearer Token method.Authorization Code Flow with PKCE
Proof Key for Code Exchange (PKCE) is the recommended flow for public clients — single-page apps, native apps, and any environment where a client secret cannot be safely stored.Generate the authorization URL
The SDK handles code verifier generation and If you need manual control over the verifier:
localStorage storage automatically:JavaScript
Exchange code with verifier
After the user is redirected back, retrieve the code and verifier:Pass them to Or exchange using the
JavaScript
CortiClient:JavaScript
auth instance from step 1:JavaScript
Use tokens
The
client from the CortiClient path is ready to use. For the CortiAuth path, create a CortiClient with the returned accessToken using the Bearer Token method.Resource Owner Password Credentials
The ROPC flow lets users authenticate with a username and password using the SDK.Bearer Token
If you already have an access token — for example, from another OAuth flow, a token endpoint on your backend, or a third-party identity provider — you can pass it directly toCortiClient without using any of the built-in authentication flows.
Using a token
JavaScript
With automatic refresh
If you passclientId and refreshToken, the SDK will call refreshToken automatically when the access token expires — no custom callback needed:
JavaScript
refreshAccessToken callback instead:
JavaScript
Scoped tokens
In some cases it’s acceptable to open a WebSocket connection directly from the frontend — for example, when streaming audio for real-time transcription. To do this securely, your backend should issue a scoped token instead of a full service-account token. A scoped token restricts access to a single endpoint. Even if the token is intercepted, it can only be used to send audio to the scoped WebSocket — it cannot read, modify, or delete any other data.Available scopes
| Scope | Grants access to |
|---|---|
"streams" | Stream WebSocket endpoint (/streams) only |
"transcribe" | Transcribe WebSocket endpoint (/transcribe) only |
Requesting scoped tokens
Issue scoped tokens from your backend usingCortiAuth or client.auth:
Using scoped tokens in the frontend
Pass the scoped token to the frontend and use it as a bearer token:JavaScript
How token refresh works
When using Client Credentials, Authorization Code, PKCE, or ROPC, the SDK manages the full token lifecycle automatically — you don’t need to handle expiry or renewal. With Bearer Token, refresh depends on what you provide: aclientId + refreshToken pair enables automatic refresh, a refreshAccessToken callback gives you full control, and a static token is used as-is until it expires.
Proactive refresh
Tokens are refreshed before each API call, not in response to a 401 error. Every time you call an SDK method, the client checks whether the current access token is still valid. If it has expired (or is about to), the SDK refreshes it transparently before sending the request. The SDK subtracts a 2-minute buffer from the token’sexpiresIn value to ensure refresh happens before the token actually expires on the server.
Refresh behaviour per flow
Client Credentials
Client Credentials
The SDK acquires a token on the first API call using your
clientId and clientSecret. When the token approaches expiry:- If the server returned a refresh token and it hasn’t expired, the SDK uses it to get a new access token.
- Otherwise, the SDK performs a fresh client credentials exchange.
clientId and clientSecret.Bearer Token (static)
Bearer Token (static)
A static
accessToken without refreshToken or refreshAccessToken is used as-is. The SDK does not attempt to refresh it. When the token expires, API calls will fail with an authentication error.If you provide expiresIn, the SDK tracks the expiry locally. Without it, the SDK attempts to extract expiry from the JWT.Bearer Token with clientId + refreshToken
Bearer Token with clientId + refreshToken
When you provide
clientId and refreshToken alongside the accessToken, the SDK calls refreshToken automatically when the access token approaches expiry. No custom callback is needed.Bearer Token with refreshAccessToken
Bearer Token with refreshAccessToken
When you provide a If you omit the initial
refreshAccessToken callback, the SDK calls it automatically when the access token is expired or missing. Your callback receives the current refreshToken (if any) and must return a new token response:JavaScript
accessToken entirely, the SDK calls refreshAccessToken immediately on the first API request to obtain one.Authorization Code / PKCE / ROPC
Authorization Code / PKCE / ROPC
What the SDK does NOT do
- No 401-based retry. If a token is rejected by the server while the SDK considers it valid (e.g. clock skew or server-side revocation), the request fails immediately. HTTP retries only apply to 408, 429, and 5xx status codes.
- No persistent storage. Tokens live only in memory for the lifetime of the client instance.
- No configurable buffer. The 2-minute refresh buffer is fixed and cannot be overridden.
Resources
- Authentication overview — OAuth2 concepts and Corti-specific details
- Security best practices — guidance on credential management
- Auth examples — interactive Next.js demo of all four OAuth flows
- Proxy Guide — secure frontend patterns when using client credentials
For support or questions, reach out through help.corti.app