diff --git a/EXAMPLES.md b/EXAMPLES.md index 23ab3357..02c1c763 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -820,6 +820,117 @@ bootstrapApplication(AppComponent, { }); ``` +## Online Access (Online Refresh Tokens) + +> [!NOTE] +> Online Access (Online Refresh Tokens) support via SDKs is currently in Early Access. To request access to this feature, contact your Auth0 representative. + +**Online Refresh Tokens (ORTs)** are a refresh token type bound to the lifetime of the user's Auth0 session, unlike rotating offline refresh tokens. An ORT is: + +- **Session-bound** — valid only while the underlying Auth0 session is active. When the session ends (logout, idle/absolute session expiry, or an admin revoking the session), the ORT stops working. +- **Non-rotating** — refreshing an access token with an ORT does **not** issue a new refresh token; the same ORT is reused for the life of the session. + +Read more about [Online Refresh Tokens](https://auth0.com/docs/secure/tokens/refresh-tokens/online-refresh-tokens/online-refresh-tokens) to decide whether this fits your application. + +> [!IMPORTANT] +> Online access requires DPoP. Sender-constraining the token via [DPoP](#device-bound-tokens-with-dpop) is mandatory because the ORT is non-rotating — binding it to the browser's key pair is what mitigates token replay if it is exfiltrated. You must set `useDpop: true` explicitly; the SDK does not enable it for you. +> +> This also requires the `online_refresh_tokens` flag to be enabled for your Auth0 tenant, and `allow_online_access` to be enabled on the resource server you log in with (on by default). + +### Enabling Online Access + +Set `refreshTokenMode` to `RefreshTokenMode.Online` together with `useRefreshTokens: true` and `useDpop: true`: + +```ts +import { NgModule } from '@angular/core'; +import { AuthModule, RefreshTokenMode } from '@auth0/auth0-angular'; + +@NgModule({ + imports: [ + AuthModule.forRoot({ + domain: 'YOUR_AUTH0_DOMAIN', + clientId: 'YOUR_AUTH0_CLIENT_ID', + useRefreshTokens: true, // required — online access is a refresh-token grant + refreshTokenMode: RefreshTokenMode.Online, // 👈 + useDpop: true, // required — DPoP is mandatory for online access + authorizationParams: { + redirect_uri: window.location.origin, + }, + }), + ], +}) +export class AppModule {} +``` + +Or with standalone components via `provideAuth0`: + +```ts +import { bootstrapApplication } from '@angular/platform-browser'; +import { provideAuth0, RefreshTokenMode } from '@auth0/auth0-angular'; +import { AppComponent } from './app/app.component'; + +bootstrapApplication(AppComponent, { + providers: [ + provideAuth0({ + domain: 'YOUR_AUTH0_DOMAIN', + clientId: 'YOUR_AUTH0_CLIENT_ID', + useRefreshTokens: true, + refreshTokenMode: RefreshTokenMode.Online, + useDpop: true, + authorizationParams: { + redirect_uri: window.location.origin, + }, + }), + ], +}); +``` + +`refreshTokenMode` defaults to `RefreshTokenMode.Offline` (rotating refresh tokens). Enabling online mode causes the underlying SDK to: + +- Send the `online_access` scope to the authorization server (instead of `offline_access`) — you do **not** need to add it to `authorizationParams.scope` yourself. +- Route token renewal through the `refresh_token` grant against `/oauth/token` rather than a hidden iframe. +- Store the non-rotating ORT in the existing cache and reuse it on every refresh, never replacing it. + +### Configuration validation + +If `refreshTokenMode: RefreshTokenMode.Online` is set without `useRefreshTokens: true` and `useDpop: true`, the underlying `Auth0Client` constructor throws an `InvalidConfigurationError`: + +```ts +import { InvalidConfigurationError } from '@auth0/auth0-angular'; + +try { + // AuthModule.forRoot / provideAuth0 constructs the client during app bootstrap. + // Wrap it, or validate your configuration up front, to catch misconfiguration. +} catch (e) { + if (e instanceof InvalidConfigurationError) { + console.error(e.error_description); // includes the suggested fix + } +} +``` + +### Using Online Access with MRRT + +Online access is compatible with Multi-Resource Refresh Tokens (MRRT): a single ORT can be exchanged for access tokens across the audiences allowed by your refresh-token policies. The ORT remains non-rotating throughout. + +```ts +AuthModule.forRoot({ + domain: 'YOUR_AUTH0_DOMAIN', + clientId: 'YOUR_AUTH0_CLIENT_ID', + useRefreshTokens: true, + refreshTokenMode: RefreshTokenMode.Online, + useDpop: true, + useMrrt: true, // 👈 + authorizationParams: { + redirect_uri: window.location.origin, + audience: 'https://api.example.com', + }, +}); +``` + +> [!IMPORTANT] +> In order for MRRT to work, it needs a previous configuration setting the refresh token policies. +> Visit [configure and implement MRRT](https://auth0.com/docs/secure/tokens/refresh-tokens/multi-resource-refresh-token/configure-and-implement-multi-resource-refresh-token). + ## Standalone components and a more functional approach As of Angular 15, the Angular team is putting standalone components, as well as a more functional approach, in favor of the traditional use of NgModules and class-based approach. diff --git a/package.json b/package.json index b7271eda..357a6d2d 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@angular/platform-browser": "^19.2.21", "@angular/platform-browser-dynamic": "^19.2.21", "@angular/router": "^19.2.21", - "@auth0/auth0-spa-js": "^2.21.0", + "@auth0/auth0-spa-js": "^2.23.0", "rxjs": "^6.6.7", "tslib": "^2.8.1", "zone.js": "~0.15.1" diff --git a/projects/auth0-angular/src/public-api.ts b/projects/auth0-angular/src/public-api.ts index c90fec6c..051954f8 100644 --- a/projects/auth0-angular/src/public-api.ts +++ b/projects/auth0-angular/src/public-api.ts @@ -36,6 +36,8 @@ export { AuthenticationError, PopupCancelledError, MissingRefreshTokenError, + MissingScopesError, + InvalidConfigurationError, ConnectError, Fetcher, FetcherConfig, @@ -44,6 +46,7 @@ export { CustomTokenExchangeOptions, TokenEndpointResponse, ResponseType, + RefreshTokenMode, MfaError, MfaListAuthenticatorsError, MfaEnrollmentError,