From e032e321d6e65f987374e6ea7248507bec0d218c Mon Sep 17 00:00:00 2001 From: AJ Ancheta <7781450+ancheetah@users.noreply.github.com> Date: Thu, 5 Nov 2026 14:18:43 -0500 Subject: [PATCH] feat(oidc-client): add RAR support [SDKS-5435] --- .changeset/big-kids-smash.md | 7 ++ e2e/oidc-app/src/index.html | 2 + e2e/oidc-app/src/par/main.ts | 46 +-------- e2e/oidc-app/src/rar-par/index.html | 61 ++++++++++++ e2e/oidc-app/src/rar-par/main.ts | 52 ++++++++++ e2e/oidc-app/src/rar/index.html | 28 ++++++ e2e/oidc-app/src/rar/main.ts | 31 ++++++ e2e/oidc-app/src/utils/journey-login.ts | 53 ++++++++++ e2e/oidc-suites/src/par.spec.ts | 4 +- packages/oidc-client/README.md | 99 ++++++++++++++++++- .../src/lib/authorize.request.micros.ts | 3 + packages/oidc-client/src/lib/client.store.ts | 19 +++- .../oidc/src/lib/authorize.utils.ts | 20 +++- packages/sdk-types/src/lib/authorize.types.ts | 31 +++++- packages/sdk-types/src/lib/config.types.ts | 9 +- 15 files changed, 413 insertions(+), 52 deletions(-) create mode 100644 .changeset/big-kids-smash.md create mode 100644 e2e/oidc-app/src/rar-par/index.html create mode 100644 e2e/oidc-app/src/rar-par/main.ts create mode 100644 e2e/oidc-app/src/rar/index.html create mode 100644 e2e/oidc-app/src/rar/main.ts create mode 100644 e2e/oidc-app/src/utils/journey-login.ts diff --git a/.changeset/big-kids-smash.md b/.changeset/big-kids-smash.md new file mode 100644 index 00000000000..7e11344480c --- /dev/null +++ b/.changeset/big-kids-smash.md @@ -0,0 +1,7 @@ +--- +'@forgerock/oidc-client': minor +'@forgerock/sdk-oidc': minor +'@forgerock/sdk-types': minor +--- + +Added RAR support through `authorizationDetails` parameter in OIDC config. Works with or without PAR. diff --git a/e2e/oidc-app/src/index.html b/e2e/oidc-app/src/index.html index dcc720ee3b0..c0fd57ee6a7 100644 --- a/e2e/oidc-app/src/index.html +++ b/e2e/oidc-app/src/index.html @@ -13,6 +13,8 @@

OIDC Client E2E Test Index | Ping Identity JavaScript SDK

Ping AM Ping One PAR (Pushed Authorization Request) + RAR (Rich Authorization Request) + RAR with PAR diff --git a/e2e/oidc-app/src/par/main.ts b/e2e/oidc-app/src/par/main.ts index 46ec6b3e367..ce5664181a8 100644 --- a/e2e/oidc-app/src/par/main.ts +++ b/e2e/oidc-app/src/par/main.ts @@ -6,13 +6,11 @@ * of the MIT license. See the LICENSE file for details. * */ +import { runLoginJourney } from '../utils/journey-login.js'; import { oidcApp } from '../utils/oidc-app.js'; -const AM_BASE = 'https://openam-sdks.forgeblocks.com/am'; -const REALM = 'alpha'; - const urlParams = new URLSearchParams(window.location.search); -const wellknown = urlParams.get('wellknown'); +const AM_BASE = 'https://openam-sdks.forgeblocks.com/am'; const config = { clientId: 'ParClient', @@ -20,51 +18,15 @@ const config = { scope: 'openid profile email', par: true, serverConfig: { - wellknown: - wellknown || - 'https://openam-sdks.forgeblocks.com/am/oauth2/alpha/.well-known/openid-configuration', + wellknown: `${AM_BASE}/oauth2/alpha/.well-known/openid-configuration`, }, }; -// Run journey Login to establish an AM session before background PAR auth -async function runLoginJourney(username: string, password: string): Promise { - const authenticateUrl = `${AM_BASE}/json/realms/root/realms/${REALM}/authenticate?authIndexType=service&authIndexValue=Login`; - - // Step 1: start the journey - const initRes = await fetch(authenticateUrl, { - method: 'POST', - credentials: 'include', - headers: { 'Content-Type': 'application/json', 'Accept-API-Version': 'resource=2.1' }, - body: '{}', - }); - const initJson = await initRes.json(); - - if (initJson.successUrl) return; // already authenticated - - // Fill NameCallback + PasswordCallback - for (const cb of initJson.callbacks ?? []) { - if (cb.type === 'NameCallback') cb.input[0].value = username; - if (cb.type === 'PasswordCallback') cb.input[0].value = password; - } - - // Step 2: submit credentials - const submitRes = await fetch(authenticateUrl, { - method: 'POST', - credentials: 'include', - headers: { 'Content-Type': 'application/json', 'Accept-API-Version': 'resource=2.1' }, - body: JSON.stringify(initJson), - }); - const submitJson = await submitRes.json(); - - if (!submitJson.tokenId && !submitJson.successUrl) { - throw new Error(submitJson.message || 'Login failed'); - } -} - const journeyForm = document.getElementById('journey-form') as HTMLFormElement; const journeyStatus = document.getElementById('journey-status') as HTMLParagraphElement; const backgroundBtn = document.getElementById('login-background') as HTMLButtonElement; +// Run journey Login to establish an AM session before background PAR auth journeyForm.addEventListener('submit', async (e) => { e.preventDefault(); const username = (document.getElementById('username') as HTMLInputElement).value; diff --git a/e2e/oidc-app/src/rar-par/index.html b/e2e/oidc-app/src/rar-par/index.html new file mode 100644 index 00000000000..58a2fc055d7 --- /dev/null +++ b/e2e/oidc-app/src/rar-par/index.html @@ -0,0 +1,61 @@ + + + + + + E2E Test | Ping Identity JavaScript SDK + + + + +
+ Home +

OIDC App | RAR (Rich Authorization Request) + PAR Login

+

+ Client: rar — RAR enabled. authorization_details are + serialized and sent in the authorize url or PAR POST body. +

+ +

Step 1: Establish AM Session (Journey: Login)

+

+ Background PAR + RAR auth requires an existing AM session. Log in via the Login journey + first. +

+
+
+ + + + + +
+
+

+ +

Step 2: RAR OAuth

+ + + + + + + + + Start Over +
+ + + diff --git a/e2e/oidc-app/src/rar-par/main.ts b/e2e/oidc-app/src/rar-par/main.ts new file mode 100644 index 00000000000..6898093d846 --- /dev/null +++ b/e2e/oidc-app/src/rar-par/main.ts @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2026 Ping Identity Corporation. All right reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + */ +import { runLoginJourney } from '../utils/journey-login.js'; +import { oidcApp } from '../utils/oidc-app.js'; + +const urlParams = new URLSearchParams(window.location.search); +const AM_BASE = 'https://openam-stoyan.forgeblocks.com/am'; + +const config = { + clientId: 'rar', + redirectUri: 'http://localhost:8443/rar-par/', + scope: 'openid profile email', + serverConfig: { + wellknown: `${AM_BASE}/oauth2/alpha/.well-known/openid-configuration`, + }, + par: true, + authorizationDetails: [ + { + type: 'account_information', + actions: ['list_accounts', 'read_balances'], + locations: ['https://example.com/accounts'], + datatypes: ['balances'], + }, + ], +}; + +const journeyForm = document.getElementById('journey-form') as HTMLFormElement; +const journeyStatus = document.getElementById('journey-status') as HTMLParagraphElement; +const backgroundBtn = document.getElementById('login-background') as HTMLButtonElement; + +// Run journey Login to establish an AM session before background auth +journeyForm.addEventListener('submit', async (e) => { + e.preventDefault(); + const username = (document.getElementById('username') as HTMLInputElement).value; + const password = (document.getElementById('password') as HTMLInputElement).value; + journeyStatus.textContent = 'Logging in…'; + try { + await runLoginJourney(username, password, AM_BASE); + journeyStatus.textContent = '✓ Session established — background login now available.'; + backgroundBtn.disabled = false; + } catch (err) { + journeyStatus.textContent = `✗ ${err instanceof Error ? err.message : 'Login failed'}`; + } +}); + +oidcApp({ config, urlParams }); diff --git a/e2e/oidc-app/src/rar/index.html b/e2e/oidc-app/src/rar/index.html new file mode 100644 index 00000000000..2f344b1eeff --- /dev/null +++ b/e2e/oidc-app/src/rar/index.html @@ -0,0 +1,28 @@ + + + + E2E Test | Ping Identity JavaScript SDK + + + + +
+ Home +

OIDC App | RAR Login

+ + + + + + + + + Start Over +
+ + + diff --git a/e2e/oidc-app/src/rar/main.ts b/e2e/oidc-app/src/rar/main.ts new file mode 100644 index 00000000000..59fc4de962a --- /dev/null +++ b/e2e/oidc-app/src/rar/main.ts @@ -0,0 +1,31 @@ +/* + * + * Copyright (c) 2026 Ping Identity Corporation. All right reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + */ +import { oidcApp } from '../utils/oidc-app.js'; + +const urlParams = new URLSearchParams(window.location.search); + +const config = { + clientId: 'rar', + redirectUri: 'http://localhost:8443/rar/', + scope: 'openid profile email', + serverConfig: { + wellknown: + 'https://openam-stoyan.forgeblocks.com/am/oauth2/alpha/.well-known/openid-configuration', + }, + authorizationDetails: [ + { + type: 'account_information', + actions: ['list_accounts', 'read_balances'], + locations: ['https://example.com/accounts'], + datatypes: ['balances'], + }, + ], +}; + +oidcApp({ config, urlParams }); diff --git a/e2e/oidc-app/src/utils/journey-login.ts b/e2e/oidc-app/src/utils/journey-login.ts new file mode 100644 index 00000000000..6dc6059e006 --- /dev/null +++ b/e2e/oidc-app/src/utils/journey-login.ts @@ -0,0 +1,53 @@ +/* + * + * Copyright (c) 2026 Ping Identity Corporation. All right reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + */ +const urlParams = new URLSearchParams(window.location.search); +const journeyParam = urlParams.get('journey'); + +const AM_BASE = 'https://openam-sdks.forgeblocks.com/am'; +const REALM = 'alpha'; +const JOURNEY = journeyParam || 'Login'; + +// Run journey Login to establish an AM session before background auth +export async function runLoginJourney( + username: string, + password: string, + amBase?: string, +): Promise { + const authenticateUrl = `${amBase || AM_BASE}/json/realms/root/realms/${REALM}/authenticate?authIndexType=service&authIndexValue=${JOURNEY}`; + + // Step 1: start the journey + const initRes = await fetch(authenticateUrl, { + method: 'POST', + credentials: 'include', + headers: { 'Content-Type': 'application/json', 'Accept-API-Version': 'resource=2.1' }, + body: '{}', + }); + const initJson = await initRes.json(); + + if (initJson.successUrl) return; // already authenticated + + // Fill NameCallback + PasswordCallback + for (const cb of initJson.callbacks ?? []) { + if (cb.type === 'NameCallback') cb.input[0].value = username; + if (cb.type === 'PasswordCallback') cb.input[0].value = password; + } + + // Step 2: submit credentials + const submitRes = await fetch(authenticateUrl, { + method: 'POST', + credentials: 'include', + headers: { 'Content-Type': 'application/json', 'Accept-API-Version': 'resource=2.1' }, + body: JSON.stringify(initJson), + }); + const submitJson = await submitRes.json(); + + if (!submitJson.tokenId && !submitJson.successUrl) { + throw new Error(submitJson.message || 'Login failed'); + } +} diff --git a/e2e/oidc-suites/src/par.spec.ts b/e2e/oidc-suites/src/par.spec.ts index 8d618d449da..a73a6896dee 100644 --- a/e2e/oidc-suites/src/par.spec.ts +++ b/e2e/oidc-suites/src/par.spec.ts @@ -11,7 +11,9 @@ import { expect, test } from '@playwright/test'; import { asyncEvents } from './utils/async-events.js'; import { pingAmPassword, pingAmUsername } from './utils/demo-users.js'; -async function loginJourney(page, username: string, password: string) { +import type { Page } from '@playwright/test'; + +async function loginJourney(page: Page, username: string, password: string) { await page.getByLabel('User Name').fill(username); await page.getByLabel('Password').fill(password); await page.getByRole('button', { name: 'Login (Journey)' }).click(); diff --git a/packages/oidc-client/README.md b/packages/oidc-client/README.md index 4119d84729e..cc276ef20f8 100644 --- a/packages/oidc-client/README.md +++ b/packages/oidc-client/README.md @@ -18,6 +18,8 @@ The oidc module follows the [OIDC](https://openid.net/specs/openid-connect-core- - [Redirect-Based Login](#redirect-based-login-authorizeurl) - [Background Authorization](#background-authorization-authorizebackground) - [Automatic Token Renewal](#automatic-token-renewal) + - [Pushed Authorization Requests (PAR)](#pushed-authorization-requests-par) + - [Rich Authorization Requests (RAR)](#rich-authorization-requests-rar) - [Error Handling](#error-handling) ## Installation @@ -57,7 +59,10 @@ The `oidc()` initialization function accepts the following configuration: - **scope** (required) - Space-separated list of requested scopes (e.g., `'openid profile email'`) - **storage** (optional) - Storage configuration for tokens (defaults to localStorage) - **timeout** (optional) - Request timeout in milliseconds -- **additionalParameters** (optional) - Additional parameters to include in authorization requests +- **par** (optional) - Use Pushed Authorization Requests (PAR) for the authorization flow; omitted auto-detects from the server's well-known configuration (see [Pushed Authorization Requests (PAR)](#pushed-authorization-requests-par)) +- **authorizationDetails** (optional) - Use Rich Authorization Requests (RAR) for the authorization flow. See [Rich Authorization Requests (RAR)](#rich-authorization-requests-rar). + +See `OidcConfig` interface for the full list of options. ## Quick Start @@ -330,6 +335,98 @@ if ('error' in tokens) { } ``` +### Pushed Authorization Requests (PAR) + +The client supports [Pushed Authorization Requests](https://datatracker.ietf.org/doc/html/rfc9126) (PAR, RFC 9126), an OAuth 2.0 extension that hardens the authorization flow. + +In a standard flow, all authorization parameters (`redirect_uri`, `scope`, PKCE `code_challenge`, `state`, and so on) are packed into the authorize URL and pass through the browser. With PAR, the client first POSTs those parameters directly to the server's PAR endpoint, receives a short-lived `request_uri`, and then sends the browser to the authorization endpoint with only `client_id` and `request_uri` in the URL: + +**Enabling PAR** + +PAR is enabled with the `par` configuration option: + +```js +const config = { + serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' }, + clientId: 'example-client-id', + redirectUri: 'https://example-app/redirect-uri', + scope: 'openid profile email', + par: true, +}; +``` + +How it resolves: + +- `par: true` — always use PAR +- `par: false` — never use PAR; OIDC Client initialization fails if the server's well-known configuration advertises `require_pushed_authorization_requests: true` +- `par` omitted — PAR is used automatically when the server requires it, otherwise the standard flow is used + +Both `authorize.url()` and `authorize.background()` respect this setting. The `request_uri` is single-use and short-lived (typically 30–90 seconds), so the authorize navigation must complete before it expires. + +### Rich Authorization Requests (RAR) + +The client supports [Rich Authorization Requests](https://datatracker.ietf.org/doc/html/rfc9396) (RAR, RFC 9396), an OAuth 2.0 extension that lets the client request fine-grained, transaction-specific authorization instead of just scopes. Details are sent as the `authorization_details` request parameter — a JSON array describing _what_ the client wants to do rather than a coarse scope string. + +Each detail object has a `type` string defined by the authorization server, plus the standard fields `locations`, `actions`, `datatypes`, and `privileges`. Type-specific fields the SDK doesn't model go in `additionalFields`, whose entries are flattened onto the object before the request is sent. + +**Declaring authorization details** + +Details can be set at initialization, so they apply to every authorization request the client makes: + +```js +const config = { + serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' }, + clientId: 'example-client-id', + redirectUri: 'https://example-app/redirect-uri', + scope: 'openid profile email', + authorizationDetails: [ + { + type: 'payment_initiation', + actions: ['initiate', 'status'], + locations: ['https://example.com/payments'], + instructedAmount: { currency: 'EUR', amount: '123.50' }, + creditorName: 'Merchant A', + }, + ], +}; +``` + +Type-specific fields like `instructedAmount` and `creditorName` can be passed through `additionalFields`: + +```js +const config = { + // ...other options + authorizationDetails: [ + { + type: 'payment_initiation', + actions: ['initiate', 'status'], + locations: ['https://example.com/payments'], + additionalFields: { + instructedAmount: { currency: 'EUR', amount: '123.50' }, + creditorName: 'Merchant A', + }, + }, + ], +}; +``` + +Authorization details can alternatively be supplied per call, which overrides the OIDC Client configuration for that request: + +```js +const authResponse = await oidcClient.authorize.background({ + authorizationDetails: [ + { + type: 'account_information', + actions: ['list', 'read'], + locations: ['https://example.com/accounts'], + datatypes: ['balances', 'transactions'], + }, + ], +}); +``` + +Details are serialized to JSON for the `authorization_details` parameter and are included in both the standard flow and the pushed (PAR) request body. Server support for RAR is required; consult your authorization server's documentation for the detail `type` values and fields it accepts. + ### Error Handling The library uses a consistent error handling pattern. All methods return either a success response or an error object. Check if the response contains an `error` property: diff --git a/packages/oidc-client/src/lib/authorize.request.micros.ts b/packages/oidc-client/src/lib/authorize.request.micros.ts index 53098144839..0bdc6caa26a 100644 --- a/packages/oidc-client/src/lib/authorize.request.micros.ts +++ b/packages/oidc-client/src/lib/authorize.request.micros.ts @@ -100,6 +100,9 @@ export const buildParBodyµ = ( redirectUri: config.redirectUri, scope: config.scope || 'openid', responseType: config.responseType || 'code', + ...(config.authorizationDetails !== undefined && { + authorizationDetails: config.authorizationDetails, + }), ...parBodyOptions, challenge, state, diff --git a/packages/oidc-client/src/lib/client.store.ts b/packages/oidc-client/src/lib/client.store.ts index e971a35ea7d..af9fb9d84ca 100644 --- a/packages/oidc-client/src/lib/client.store.ts +++ b/packages/oidc-client/src/lib/client.store.ts @@ -175,6 +175,9 @@ export async function oidc({ redirectUri: config.redirectUri, scope: config.scope || 'openid', responseType: config.responseType || 'code', + ...(config.authorizationDetails !== undefined && { + authorizationDetails: config.authorizationDetails, + }), ...(config.loginHint !== undefined && { loginHint: config.loginHint }), ...(config.nonce !== undefined && { nonce: config.nonce }), ...(config.display !== undefined && { display: config.display }), @@ -213,7 +216,13 @@ export async function oidc({ config, log, store, - { ...(options ?? ({} as GetAuthorizationUrlOptions)), prompt: 'none' as const }, + { + ...(config.authorizationDetails !== undefined && { + authorizationDetails: config.authorizationDetails, + }), + ...(options ?? ({} as GetAuthorizationUrlOptions)), + prompt: 'none' as const, + }, useParFlow, ), ); @@ -335,7 +344,13 @@ export async function oidc({ config, log, store, - { ...(authorizeOptions ?? ({} as GetAuthorizationUrlOptions)), prompt: 'none' as const }, + { + ...(config.authorizationDetails !== undefined && { + authorizationDetails: config.authorizationDetails, + }), + ...(authorizeOptions ?? ({} as GetAuthorizationUrlOptions)), + prompt: 'none' as const, + }, useParFlow, ).pipe( Micro.flatMap((response): Micro.Micro => { diff --git a/packages/sdk-effects/oidc/src/lib/authorize.utils.ts b/packages/sdk-effects/oidc/src/lib/authorize.utils.ts index 204749334d0..604644eb152 100644 --- a/packages/sdk-effects/oidc/src/lib/authorize.utils.ts +++ b/packages/sdk-effects/oidc/src/lib/authorize.utils.ts @@ -4,8 +4,21 @@ * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ +import type { AuthorizationDetail, GetAuthorizationUrlOptions } from '@forgerock/sdk-types'; -import type { GetAuthorizationUrlOptions } from '@forgerock/sdk-types'; +/** + * Serializes RAR {@link AuthorizationDetail} objects to a JSON string for the + * `authorization_details` request parameter. Each detail's `additionalFields` + * is flattened onto the detail; entries in `additionalFields` that shadow a + * modeled property are overridden by the modeled entry. + */ +export function serializeRarAuthDetails(authDetails: AuthorizationDetail[]): string { + const flattenedDetails = authDetails.map((detail) => { + const { additionalFields, ...knownAuthDetails } = detail; + return { ...additionalFields, ...knownAuthDetails }; + }); + return JSON.stringify(flattenedDetails); +} /** * Builds URLSearchParams for an OAuth2/OIDC authorization request. @@ -35,5 +48,10 @@ export function buildAuthorizeParams( if (options.uiLocales) params.set('ui_locales', options.uiLocales); if (options.acrValues) params.set('acr_values', options.acrValues); + if (options.authorizationDetails?.length) { + const serializedAuthDetails = serializeRarAuthDetails(options.authorizationDetails); + params.set('authorization_details', serializedAuthDetails); + } + return params; } diff --git a/packages/sdk-types/src/lib/authorize.types.ts b/packages/sdk-types/src/lib/authorize.types.ts index 014273d67f5..0a183459314 100644 --- a/packages/sdk-types/src/lib/authorize.types.ts +++ b/packages/sdk-types/src/lib/authorize.types.ts @@ -19,21 +19,23 @@ export type AuthPromptValue = (typeof AUTH_PROMPT_VALUES)[number]; /** * Options for the authorization URL + * + * These four properties clientid, scope, responseType and redirectUri are required + * when using this type, which are not required when defining Config. + * * @param clientId The client ID of the application * @param redirectUri The redirect URI of the application * @param responseType The response type of the authorization request * @param scope The scope of the authorization request */ export interface GetAuthorizationUrlOptions extends LegacyConfigOptions { - /** - * These four properties clientid, scope, responseType and redirectUri are required - * when using this type, which are not required when defining Config. - */ clientId: string; scope: string; redirectUri: string; responseType: ResponseType; responseMode?: 'fragment' | 'form_post' | 'pi.flow' | 'query'; + /** Authorization details for Rich Authorization Requests (RAR) */ + authorizationDetails?: AuthorizationDetail[]; login?: 'redirect' | 'embedded'; state?: string; verifier?: string; @@ -56,3 +58,24 @@ export interface GenerateAndStoreAuthUrlValues extends GetAuthorizationUrlOption clientId: string; prefix?: string; } + +/** + * A single object for the `authorization_details` request parameter as + * defined by RFC 9396 (Rich Authorization Requests). Type-specific fields + * not modeled below can be added to the catch-all `additionalFields` parameter, + * whose entries are flattened onto the object before sending the request. + */ +export interface AuthorizationDetail { + /** The type of authorization details as defined by the authorization server */ + type: string; + /** Locations this authorization applies to */ + locations?: string[]; + /** Actions this authorization applies to */ + actions?: string[]; + /** Data types this authorization applies to */ + datatypes?: string[]; + /** Privileges this authorization applies to */ + privileges?: string[]; + /** Catch-all for type-specific fields not modeled above (e.g. `instructedAmount` for `payment_initiation`) */ + additionalFields?: Record; +} diff --git a/packages/sdk-types/src/lib/config.types.ts b/packages/sdk-types/src/lib/config.types.ts index ce2d9e84695..eb63a888bf2 100644 --- a/packages/sdk-types/src/lib/config.types.ts +++ b/packages/sdk-types/src/lib/config.types.ts @@ -4,7 +4,12 @@ * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ -import type { AuthDisplayValue, AuthPromptValue, ResponseType } from './authorize.types.js'; +import type { + AuthDisplayValue, + AuthorizationDetail, + AuthPromptValue, + ResponseType, +} from './authorize.types.js'; import type { AsyncLegacyConfigOptions } from './legacy-config.types.js'; import type { CustomStorageObject } from './tokens.types.js'; @@ -27,6 +32,8 @@ export interface OidcConfig extends AsyncLegacyConfigOptions { responseType?: ResponseType; /** Use Pushed Authorization Requests (PAR) for the authorization flow. */ par?: boolean; + /** Authorization details for Rich Authorization Requests (RAR) */ + authorizationDetails?: AuthorizationDetail[]; /** URI to redirect to after logout; maps to `post_logout_redirect_uri` in the end-session request. */ signOutRedirectUri?: string; loginHint?: string;