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 | Backend | Interactive user login (confidential clients) |
| PKCE | Frontend & Backend | Interactive user login (public clients) |
| ROPC | Backend only | Username/password for trusted or internal apps |
| Bearer Token | Frontend & Backend | You already have a token from another source |
| Custom Refresh | Frontend & Backend | You manage token refresh yourself |
For complete examples of each flow, see 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:
C# .NET
CustomAuthClient:
C# .NET
Authorization Code Flow
The standard OAuth 2.0 authorization code flow for interactive user authentication. Use this when your application has a server component that can keep theclientSecret confidential.
Redirect to login
Create a
CustomAuthClient instance and send the user to Corti’s authorization page:C# .NET
Receive authorization code
The user is redirected back to your
redirectUri with a code query parameter.Exchange code for tokens
Pass Or exchange manually using the
code to CortiClient — it handles the exchange and refresh automatically:C# .NET
auth instance from step 1:C# .NET
Use tokens
The
client from the CortiClient path is ready to use. For the CustomAuthClient path, create a CortiClient with the returned accessToken using the Bearer Token method.PKCE Flow
The Authorization Code flow with Proof Key for Code Exchange — recommended for public clients where a client secret cannot be stored securely (native apps, SPAs).Exchange code with verifier
After the user is redirected back with a Or exchange using the
code parameter, pass it with the verifier to CortiClient:C# .NET
auth instance from step 1:C# .NET
Use tokens
The
client from the CortiClient path is ready to use. For the CustomAuthClient 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
C# .NET
tenantName and environment automatically. You can override them if needed by using the (tenantName, environment, auth) constructor overload.
With automatic refresh
If you passclientId and refreshToken, the SDK will call refreshToken automatically when the access token expires — no custom callback needed:
C# .NET
Custom Refresh
Provide your own refresh logic so the SDK can transparently refresh expired tokens:C# .NET
C# .NET
CustomRefreshResult supports additional fields:
| Property | Type | Description |
|---|---|---|
AccessToken | string | Required. The new access token |
ExpiresIn | int? | Token lifetime in seconds |
RefreshToken | string? | Updated refresh token (if rotated) |
RefreshExpiresIn | int? | Refresh token lifetime in seconds |
TokenType | string? | Token type (typically "Bearer") |
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 usingCustomAuthClient:
C# .NET
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, and a static token is used as-is until it expires. With Custom Refresh, your delegate controls the refresh behaviour entirely.
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.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.Custom Refresh (BearerCustomRefresh)
Custom Refresh (BearerCustomRefresh)
When you provide a
refreshAccessToken delegate via CortiClientAuth.BearerCustomRefresh, the SDK calls it automatically when the access token is expired or missing. Your delegate receives the current access token (if any) and must return a CustomRefreshResult.If the initial accessToken is omitted, the SDK calls your delegate 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.
Proxy / passthrough mode
When your server acts as a proxy and handles authentication externally, create a client with only an environment:C# .NET
Resources
- Authentication overview — OAuth 2.0 concepts and Corti-specific details
- Security best practices — credential management guidance
- Examples repository — working code for authentication, streaming, text generation, and more
For support or questions, reach out through help.corti.app