@strivacity/sdk-core 4.0.0-beta.0 → 4.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/assets/oidc.cjs +1 -1
- package/dist/assets/oidc.cjs.map +1 -1
- package/dist/assets/oidc.mjs +1 -1
- package/dist/assets/oidc.mjs.map +1 -1
- package/dist/flows/base.cjs +1 -1
- package/dist/flows/base.cjs.map +1 -1
- package/dist/flows/base.mjs +1 -1
- package/dist/flows/base.mjs.map +1 -1
- package/dist/server/base.cjs +1 -1
- package/dist/server/base.cjs.map +1 -1
- package/dist/server/base.mjs +1 -1
- package/dist/server/base.mjs.map +1 -1
- package/dist/types/oidc.cjs.map +1 -1
- package/dist/types/oidc.d.ts +6 -0
- package/dist/types/oidc.mjs.map +1 -1
- package/dist/utils/session.cjs +1 -1
- package/dist/utils/session.cjs.map +1 -1
- package/dist/utils/session.d.ts +2 -1
- package/dist/utils/session.mjs +1 -1
- package/dist/utils/session.mjs.map +1 -1
- package/package.json +1 -1
- package/testing/tests/utils/oidc.spec.ts +1 -0
- package/testing/tests/utils/session.spec.ts +87 -0
package/dist/assets/oidc.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oidc.mjs","names":[],"sources":["../../src/utils/state.ts","../../src/utils/oidc.ts"],"sourcesContent":["import type { StateData } from '../types/oidc';\nimport { timestamp } from './common';\nimport { generateCodeVerifier, generateCodeChallenge, generateRandomHex } from './oidc';\n\n/**\n * Creates a new state object for OAuth 2.0 authorization requests, including a code verifier and challenge for PKCE.\n *\n * @param {Record<string, unknown>} [metadata={}] Optional metadata to associate with the state.\n * @returns {Promise<StateData>} A promise that resolves to the newly created state object.\n */\nexport async function createState(metadata: Record<string, unknown> = {}): Promise<StateData> {\n\tconst codeVerifier = generateCodeVerifier();\n\n\treturn {\n\t\tid: generateRandomHex(16),\n\t\tcreatedAt: timestamp(),\n\t\tcodeVerifier,\n\t\tmetadata,\n\t\tcodeChallenge: await generateCodeChallenge(codeVerifier),\n\t\tnonce: generateRandomHex(16),\n\t};\n}\n\n/**\n * Parses a serialized state string into a StateData object.\n *\n * @param {string} serialized - The serialized state string to parse.\n * @returns {StateData} The parsed StateData object.\n * @throws {Error} If the serialized string is invalid or cannot be parsed.\n */\nexport function parseState(serialized: string): StateData {\n\treturn JSON.parse(serialized) as StateData;\n}\n\n/**\n * Serializes a StateData object into a string for storage or transmission.\n *\n * @param {StateData} state - The StateData object to serialize.\n * @returns {string} The serialized state string.\n */\nexport function serializeState(state: StateData): string {\n\treturn JSON.stringify(state);\n}\n","import type { ExtraRequestArgs, IdTokenClaims, DiscoveryDocument, SDKOptions, SessionData, EntryResponse, FlowState, SigningKey } from '../types/oidc';\nimport type { NativeFlowState } from '../types/native';\nimport { decodeBase64URL, encodeBase64URL } from './base64url';\nimport { FallbackError, SessionExpiredError, OidcError, ProtocolError, ServerError, NetworkError, throwHttpError, throwTokenEndpointError } from './errors';\nimport { createHttpClient } from './httpClient';\nimport { createSession } from './session';\nimport { createState, parseState, serializeState } from './state';\nimport { redirectUrlHandler, redirectCallbackHandler } from '../handlers/redirect';\nimport { createLocalStorage } from '../storages/local';\nimport { createSessionStorage } from '../storages/session';\nimport { timestamp } from './common';\n\n/**\n * Stores the expiration timestamp of the cached OpenID configuration discovery document.\n */\nlet discoveryDocumentCacheExpiresAt = 0;\n\n/**\n * A promise that represents the ongoing fetch of the OpenID configuration discovery document.\n */\nlet discoveryDocumentFetchPromise: Promise<DiscoveryDocument> | null = null;\n\n/**\n * OpenID configuration discovery document cache.\n */\nlet discoveryDocument: DiscoveryDocument | null = null;\n\n/**\n * JSON Web Key Set (JWKS) cache.\n */\nconst jwksCache = new Map<string, { keys: Array<SigningKey>; expiresAt: number }>();\n\n/**\n * Returns the default flow state for the SDK.\n *\n * @returns {FlowState} The default flow state object.\n */\nexport function getDefaultFlowState(): FlowState {\n\treturn {\n\t\tinitialized: false,\n\t\tsession: null,\n\t\tsessionId: null,\n\t\tshortAppId: null,\n\t\tlanguage: globalThis.navigator?.language ?? 'en-US',\n\t};\n}\n\n/**\n * Returns the default SDK options for the SDK.\n */\nexport const defaultOptions: Partial<SDKOptions> = {\n\tlazyLoad: false,\n\tautoRefresh: true,\n\tserverSessionUri: null,\n\tscopes: ['openid'],\n\tresponseType: 'code',\n\tresponseMode: 'query',\n\tstorageTokenName: 'sty.session',\n\tdiscoveryDocumentCacheTTL: 3600,\n\tjwksCacheTTL: 600,\n} as const;\n\n/**\n * Fetches the OpenID configuration discovery document from the authorization server.\n * Caches the document for a specified duration to avoid unnecessary network requests.\n *\n * @param {SDKOptions} options - The SDK options containing the issuer URL and other configurations.\n * @returns {Promise<DiscoveryDocument>} A promise that resolves to the fetched discovery document.\n * @throws {ServerError} If the discovery document fetch fails with a server error (HTTP 429 or 5xx).\n * @throws {ProtocolError} If the discovery document is missing required fields or has an issuer mismatch.\n */\nexport async function getDiscoveryDocument(options: SDKOptions): Promise<DiscoveryDocument> {\n\tif (discoveryDocument && discoveryDocumentCacheExpiresAt > timestamp()) {\n\t\treturn discoveryDocument;\n\t}\n\n\tif (discoveryDocumentFetchPromise) {\n\t\treturn discoveryDocumentFetchPromise;\n\t}\n\n\tdiscoveryDocumentFetchPromise = (async () => {\n\t\ttry {\n\t\t\tconst response = await options.httpClient.request<DiscoveryDocument>(new URL('/.well-known/openid-configuration', options.issuer));\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new ServerError(`Failed to fetch OIDC metadata`, response.status);\n\t\t\t}\n\n\t\t\tlet metadata: DiscoveryDocument;\n\n\t\t\ttry {\n\t\t\t\tmetadata = await response.json();\n\t\t\t} catch {\n\t\t\t\tthrow new ProtocolError('Non-JSON response from discovery document endpoint');\n\t\t\t}\n\n\t\t\tif (metadata.issuer?.replace(/\\/$/, '') !== options.issuer.replace(/\\/$/, '')) {\n\t\t\t\tthrow new ProtocolError(`Discovery document issuer mismatch: expected ${options.issuer}, got ${metadata.issuer}`);\n\t\t\t}\n\n\t\t\tconst issuerHost = new URL(options.issuer).host;\n\n\t\t\tfor (const field of ['authorization_endpoint', 'token_endpoint', 'jwks_uri'] as const) {\n\t\t\t\tconst endpoint = metadata[field];\n\n\t\t\t\tif (!endpoint) {\n\t\t\t\t\tthrow new ProtocolError(`Discovery document is missing required field: ${field}`);\n\t\t\t\t}\n\n\t\t\t\tconst endpointUrl = new URL(endpoint);\n\n\t\t\t\tif (endpointUrl.protocol !== 'https:' || endpointUrl.host !== issuerHost) {\n\t\t\t\t\tthrow new ProtocolError(`Discovery document field \"${field}\" must be an https:// URL on ${issuerHost}, got ${endpoint}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const field of ['end_session_endpoint', 'revocation_endpoint'] as const) {\n\t\t\t\tconst endpoint = metadata[field];\n\n\t\t\t\tif (!endpoint) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst endpointUrl = new URL(endpoint);\n\n\t\t\t\tif (endpointUrl.protocol !== 'https:' || endpointUrl.host !== issuerHost) {\n\t\t\t\t\tthrow new ProtocolError(`Discovery document field \"${field}\" must be an https:// URL on ${issuerHost}, got ${endpoint}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!metadata.code_challenge_methods_supported?.includes('S256')) {\n\t\t\t\tthrow new ProtocolError('Discovery document does not advertise S256 PKCE support');\n\t\t\t}\n\n\t\t\tdiscoveryDocument = metadata;\n\t\t\tdiscoveryDocumentCacheExpiresAt = timestamp() + options.discoveryDocumentCacheTTL;\n\n\t\t\treturn metadata;\n\t\t} finally {\n\t\t\tdiscoveryDocumentFetchPromise = null;\n\t\t}\n\t})();\n\n\treturn discoveryDocumentFetchPromise;\n}\n\n/**\n * Returns the JWKS for the given URI, from cache unless it's stale or `forceRefresh` is set.\n *\n * @param {Object} options - The options for fetching the JWKS.\n * @param {string} options.jwksUri - The URL of the JWKS endpoint.\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options.\n * @param {boolean} [options.forceRefresh=false] - Bypasses the cache and fetches a fresh key set.\n * @returns {Promise<{ keys: Array<SigningKey> }>} The (possibly cached) key set.\n * @throws {NetworkError} If the JWKS fetch fails due to network issues.\n * @throws {ServerError} If the JWKS fetch fails with a server error (HTTP 429 or 5xx).\n */\nasync function getJwks({\n\tjwksUri,\n\toptions,\n\tforceRefresh = false,\n}: {\n\tjwksUri: string;\n\toptions: SDKOptions;\n\tforceRefresh?: boolean;\n}): Promise<{ keys: Array<SigningKey> }> {\n\tconst cached = jwksCache.get(jwksUri);\n\n\tif (!forceRefresh && cached && cached.expiresAt > timestamp()) {\n\t\treturn { keys: cached.keys };\n\t}\n\n\tlet jwksResponse: Response;\n\n\ttry {\n\t\tjwksResponse = await fetch(jwksUri);\n\t} catch {\n\t\tthrow new NetworkError(`Failed to fetch JWKS: ${jwksUri}`);\n\t}\n\n\tif (!jwksResponse.ok) {\n\t\tthrow new ServerError(`Failed to fetch JWKS: HTTP ${jwksResponse.status}`, jwksResponse.status);\n\t}\n\n\tconst jwks = (await jwksResponse.json()) as { keys: Array<SigningKey> };\n\n\tjwksCache.set(jwksUri, { keys: jwks.keys, expiresAt: timestamp() + options.jwksCacheTTL });\n\n\treturn jwks;\n}\n\n/**\n * Returns with the SDK options merged with the provided options.\n *\n * @param {SDKInitConfig} options - The SDK initialization configuration.\n * @template InitOptions - The type of the SDK initialization configuration.\n * @template Options - The type of the SDK options.\n * @returns {Options} The merged SDK options.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function getSDKOptions<Options extends SDKOptions = SDKOptions>(options: any): Options {\n\toptions.issuer = options.issuer.endsWith('/') ? options.issuer.slice(0, -1) : options.issuer;\n\toptions.storage ??= createLocalStorage();\n\toptions.stateStorage ??= createSessionStorage();\n\toptions.httpClient ??= createHttpClient(options.logging);\n\toptions.urlHandler ??= redirectUrlHandler;\n\toptions.callbackHandler ??= redirectCallbackHandler;\n\toptions.lazyLoad ??= defaultOptions.lazyLoad;\n\toptions.autoRefresh ??= defaultOptions.autoRefresh;\n\toptions.serverSessionUri ??= defaultOptions.serverSessionUri;\n\n\toptions.scopes ??= defaultOptions.scopes;\n\toptions.responseType ??= defaultOptions.responseType;\n\toptions.responseMode ??= defaultOptions.responseMode;\n\toptions.storageTokenName ??= defaultOptions.storageTokenName;\n\toptions.discoveryDocumentCacheTTL ??= defaultOptions.discoveryDocumentCacheTTL;\n\toptions.jwksCacheTTL ??= defaultOptions.jwksCacheTTL;\n\n\treturn options;\n}\n\n/**\n * Generates a code verifier for PKCE (Proof Key for Code Exchange).\n *\n * @returns {string} A randomly generated code verifier string.\n */\nexport function generateCodeVerifier(): string {\n\tconst bytes = new Uint8Array(32);\n\n\tglobalThis.crypto.getRandomValues(bytes);\n\n\treturn encodeBase64URL(bytes.buffer);\n}\n\n/**\n * Generates a code challenge from a code verifier using SHA-256 hashing.\n *\n * @param {string} codeVerifier The code verifier string.\n * @returns {Promise<string>} A promise that resolves to the generated code challenge.\n */\nexport async function generateCodeChallenge(codeVerifier: string): Promise<string> {\n\tconst encoded = new TextEncoder().encode(codeVerifier);\n\tconst hash = await globalThis.crypto.subtle.digest('SHA-256', encoded);\n\n\treturn encodeBase64URL(hash);\n}\n\n/**\n * Generates a random hexadecimal string of the specified byte length.\n *\n * @param {number} [byteLength=16] - The number of random bytes to generate (default is 16).\n * @returns {string} A randomly generated hexadecimal string.\n */\nexport function generateRandomHex(byteLength = 16): string {\n\tconst bytes = new Uint8Array(byteLength);\n\n\tglobalThis.crypto.getRandomValues(bytes);\n\n\treturn Array.from(bytes)\n\t\t.map((b) => b.toString(16).padStart(2, '0'))\n\t\t.join('');\n}\n\n/**\n * Decodes a JWT token and returns the payload as an object.\n *\n * @template T The expected structure of the JWT payload.\n * @param {string} token - The JWT token to decode.\n * @returns {T} The decoded payload of the JWT token.\n * @throws {ProtocolError} If the token is invalid or has the wrong format.\n */\nexport function decodeJwt<T = Record<string, unknown>>(token: string): T {\n\tconst [, payload] = token.split('.');\n\n\tif (!payload) {\n\t\tthrow new ProtocolError('Invalid JWT: missing payload segment');\n\t}\n\n\ttry {\n\t\treturn JSON.parse(new TextDecoder().decode(decodeBase64URL(payload))) as T;\n\t} catch {\n\t\tthrow new ProtocolError('Invalid JWT: payload is not valid base64url-encoded JSON');\n\t}\n}\n\n/**\n * Verifies a JWT token's signature against a JWKS endpoint.\n * Only RS256 is supported.\n *\n * @param {Object} options - The options for verifying the JWT.\n * @param {string} options.token - The JWT token to verify.\n * @param {string} options.jwksUri - The URL of the JWKS endpoint.\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options.\n * @template T - The expected structure of the JWT payload.\n * @returns {Promise<T>} The verified payload.\n * @throws {ProtocolError} If the token is invalid, the key is not found, or verification fails.\n */\nexport async function verifyJwt<T = Record<string, unknown>>({ token, jwksUri, options }: { token: string; jwksUri: string; options: SDKOptions }): Promise<T> {\n\tconst parts = token.split('.');\n\n\tif (parts.length !== 3) {\n\t\tthrow new ProtocolError('Invalid JWT: must have 3 parts');\n\t}\n\n\tconst [encodedHeader, encodedPayload, encodedSignature] = parts;\n\tconst header = JSON.parse(new TextDecoder().decode(decodeBase64URL(encodedHeader))) as { kid?: string; alg?: string };\n\n\tif (header.alg !== 'RS256') {\n\t\tthrow new ProtocolError(`Unsupported JWT algorithm: ${header.alg}`);\n\t}\n\n\tlet jwks = await getJwks({ jwksUri, options });\n\tlet signingKey = header.kid ? jwks.keys.find((k) => k.kid === header.kid) : jwks.keys.find((k) => k.alg === 'RS256');\n\n\tif (!signingKey && header.kid) {\n\t\tjwks = await getJwks({ jwksUri, options, forceRefresh: true });\n\t\tsigningKey = jwks.keys.find((k) => k.kid === header.kid);\n\t}\n\n\tif (!signingKey) {\n\t\tthrow new ProtocolError(`No matching key found in JWKS${header.kid ? ` for kid: ${header.kid}` : ''}`);\n\t}\n\n\tconst cryptoKey = await globalThis.crypto.subtle.importKey(\n\t\t'jwk',\n\t\t{ kty: signingKey.kty, n: signingKey.n, e: signingKey.e, alg: signingKey.alg, use: signingKey.use },\n\t\t{ name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-256' } },\n\t\tfalse,\n\t\t['verify'],\n\t);\n\tconst signature = decodeBase64URL(encodedSignature);\n\tconst data = new TextEncoder().encode(`${encodedHeader}.${encodedPayload}`);\n\tconst valid = await globalThis.crypto.subtle.verify({ name: 'RSASSA-PKCS1-v1_5' }, cryptoKey, signature, data);\n\n\tif (!valid) {\n\t\tthrow new ProtocolError('JWT signature verification failed');\n\t}\n\n\treturn JSON.parse(new TextDecoder().decode(decodeBase64URL(encodedPayload))) as T;\n}\n\n/**\n * Generates a signed JWT token using the provided header, payload, and private key.\n *\n * @param {object} header - The JWT header.\n * @param {object} payload - The JWT payload.\n * @param {CryptoKey} [privateKey] - The private key to sign the JWT. If not provided, an unsigned token will be generated.\n * @returns {Promise<string>} A promise that resolves to the signed JWT token.\n */\nexport async function generateJwt(header: object, payload: object, privateKey?: CryptoKey): Promise<string> {\n\tconst encodedHeader = encodeBase64URL(new TextEncoder().encode(JSON.stringify(header)).buffer);\n\tconst encodedPayload = encodeBase64URL(new TextEncoder().encode(JSON.stringify(payload)).buffer);\n\tconst encodedToken = `${encodedHeader}.${encodedPayload}`;\n\n\tif (privateKey) {\n\t\tconst signature = await globalThis.crypto.subtle.sign(\n\t\t\t{\n\t\t\t\tname: 'ECDSA',\n\t\t\t\thash: { name: 'SHA-256' },\n\t\t\t},\n\t\t\tprivateKey,\n\t\t\tnew TextEncoder().encode(encodedToken),\n\t\t);\n\n\t\treturn `${encodedToken}.${encodeBase64URL(signature)}`;\n\t}\n\n\treturn `${encodedToken}.signature`;\n}\n\n/**\n * Verifies and validates an ID token's claims.\n *\n * @param {Object} options - The options for verifying the ID token\n * @param {string} options.idToken - The ID token to verify\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options\n * @param {string} [options.expectedSub] - Optional expected subject (`sub`) claim to validate against the ID token\n * @param {string} [options.expectedNonce] - Optional expected nonce claim to validate against the ID token\n * @returns {Promise<IdTokenClaims>} The verified, validated claims.\n * @throws {ProtocolError} If the signature, `iss`, `aud`, `exp`, or `sub` fail validation.\n */\nexport async function verifyIdToken({\n\tidToken,\n\toptions,\n\tverifySignature = false,\n\texpectedSub,\n\texpectedNonce,\n}: {\n\tidToken: string;\n\toptions: SDKOptions;\n\tverifySignature?: boolean;\n\texpectedSub?: string;\n\texpectedNonce?: string;\n}): Promise<IdTokenClaims> {\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst claims = verifySignature ? await verifyJwt<IdTokenClaims>({ token: idToken, options, jwksUri: metadata.jwks_uri }) : decodeJwt<IdTokenClaims>(idToken);\n\tconst now = timestamp();\n\n\tif (claims?.iss !== metadata.issuer) {\n\t\tthrow new ProtocolError('Invalid iss');\n\t}\n\tif (Array.isArray(claims?.aud) ? !claims.aud.includes(options.clientId) : claims?.aud !== options.clientId) {\n\t\tthrow new ProtocolError('Invalid aud');\n\t}\n\tif (!claims?.exp || claims.exp <= now) {\n\t\tthrow new ProtocolError('Token has expired');\n\t}\n\tif (!claims?.sub || (expectedSub && claims.sub !== expectedSub)) {\n\t\tthrow new ProtocolError('Invalid sub');\n\t}\n\tif (expectedNonce && claims?.nonce !== expectedNonce) {\n\t\tthrow new ProtocolError('Invalid nonce');\n\t}\n\n\treturn claims;\n}\n\n/**\n * Builds the authorization URL with the provided parameters and configuration.\n *\n * @param {Object} options - The options for building the login URL and starting the session\n * @param {ExtraRequestArgs} options.params - The parameters for the authorization request, including optional prompts and hints\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options\n * @returns {Promise<URL>} A promise that resolves to the constructed authorization URL\n * @throws {Error} If fetching OIDC metadata fails or writing the PKCE state to storage fails.\n */\nexport async function buildAuthorizationUrl<URLHandlerParams extends ExtraRequestArgs = ExtraRequestArgs>({\n\turl,\n\tincludeOAuthParams = true,\n\tpersistState = true,\n\tparams,\n\toptions,\n}: {\n\turl?: string | null | URL;\n\tincludeOAuthParams?: boolean;\n\tpersistState?: boolean;\n\tparams: URLHandlerParams;\n\toptions: SDKOptions;\n}): Promise<URL> {\n\tconst stateData = await createState();\n\tstateData.metadata = {};\n\n\tif (!url) {\n\t\tconst metadata = await getDiscoveryDocument(options);\n\t\turl = new URL(metadata.authorization_endpoint);\n\t}\n\tif (typeof url === 'string') {\n\t\turl = new URL(url, globalThis.location.origin);\n\t}\n\n\tif (includeOAuthParams) {\n\t\tconst scopes = new Set(options.scopes ?? ['openid']);\n\n\t\turl.searchParams.set('client_id', options.clientId);\n\t\turl.searchParams.set('redirect_uri', options.redirectUri);\n\t\turl.searchParams.set('response_type', options.responseType ?? 'code');\n\t\turl.searchParams.set('response_mode', options.responseMode ?? 'query');\n\t\turl.searchParams.set('scope', Array.from(scopes).join(' '));\n\t\turl.searchParams.set('code_challenge_method', 'S256');\n\t\turl.searchParams.set('state', stateData.id);\n\t\turl.searchParams.set('code_challenge', stateData.codeChallenge);\n\n\t\tif (scopes.has('openid')) {\n\t\t\turl.searchParams.set('nonce', stateData.nonce);\n\t\t}\n\t}\n\n\tif (params.prompt) {\n\t\turl.searchParams.set('prompt', params.prompt);\n\t\tstateData.metadata.prompt = params.prompt;\n\t}\n\tif (params.display) {\n\t\turl.searchParams.set('display', params.display);\n\t\tstateData.metadata.display = params.display;\n\t}\n\tif (params.loginHint) {\n\t\turl.searchParams.set('login_hint', params.loginHint);\n\t\tstateData.metadata.loginHint = params.loginHint;\n\t}\n\tif (params.acrValues?.length) {\n\t\tconst acrValues = params.acrValues.filter(Boolean);\n\n\t\tif (acrValues.length) {\n\t\t\turl.searchParams.set('acr_values', acrValues.join(' '));\n\t\t\tstateData.metadata.acrValues = acrValues;\n\t\t}\n\t}\n\tif (params.uiLocales?.length) {\n\t\tconst uiLocales = params.uiLocales.filter(Boolean);\n\n\t\tif (uiLocales.length) {\n\t\t\turl.searchParams.set('ui_locales', uiLocales.join(' '));\n\t\t\tstateData.metadata.uiLocales = uiLocales;\n\t\t}\n\t}\n\tif (params.audiences?.length) {\n\t\tconst audiences = params.audiences.filter(Boolean);\n\n\t\tif (audiences.length) {\n\t\t\turl.searchParams.set('audience', audiences.join(' '));\n\t\t\tstateData.metadata.audiences = audiences;\n\t\t}\n\t}\n\n\tif (persistState) {\n\t\tawait options.stateStorage.set(`sty.${stateData.id}`, serializeState(stateData));\n\t}\n\n\treturn url;\n}\n\n/**\n * Builds the end session (logout) URL with optional parameters for ID token hint and post-logout redirect URI.\n *\n * @param {Object} options - The options for building the end session URL\n * @param {string | URL} options.url - The base URL for the end session endpoint\n * @param {string} options.idToken - The ID token to include as a hint for the end session request\n * @param {string} [options.postLogoutRedirectUri] - Optional URI to redirect to after logout\n * @returns {URL} A promise that resolves to the constructed end session URL\n * @throws {Error} If fetching metadata fails or the end session endpoint is not available\n */\nexport function buildEndSessionUrl({ url, idToken, postLogoutRedirectUri }: { url: string | URL; idToken: string; postLogoutRedirectUri?: string }): URL {\n\tconst endSessionUrl = new URL(url);\n\n\tendSessionUrl.searchParams.set('id_token_hint', idToken);\n\n\tif (postLogoutRedirectUri) {\n\t\tendSessionUrl.searchParams.set('post_logout_redirect_uri', postLogoutRedirectUri);\n\t}\n\n\treturn endSessionUrl;\n}\n\n/**\n * Exchanges an authorization code for tokens by sending a request to the token endpoint.\n * Validates the PKCE state and ID token claims, and returns the session data.\n *\n * @param {Object} options - The options for exchanging the authorization code\n * @param {string | URL} [options.url] - The token endpoint URL (optional, will be fetched from metadata if not provided)\n * @param {Record<string, string>} options.params - The parameters received from the authorization server, including the authorization code and state\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options\n * @returns {Promise<SessionData>} A promise that resolves to the session data containing tokens and claims\n * @throws {OidcError} If the token endpoint returns an OIDC error response\n * @throws {ServerError} If the token endpoint request fails with a server error (HTTP 429 or 5xx)\n * @throws {NetworkError} If the token endpoint request fails due to network issues\n * @throws {ProtocolError} If the authorization code or state is invalid, or if the token endpoint returns an error\n * @throws {ProtocolError} If the authorization code or state is invalid, or if the token endpoint returns an error\n */\nexport async function exchangeCode({\n\turl,\n\tparams,\n\toptions,\n}: {\n\turl?: string | URL;\n\tparams: Record<string, string>;\n\toptions: SDKOptions;\n}): Promise<SessionData> {\n\tconst session = createSession(params);\n\n\tif (session.error) {\n\t\tthrow new OidcError(session.error, session.error_description, session.error_uri);\n\t}\n\tif (!session.code) {\n\t\tthrow new ProtocolError('Invalid or missing authorization code');\n\t}\n\n\tconst stateKey = `sty.${session.state}`;\n\tconst serializedState = await options.stateStorage.get(stateKey);\n\n\tif (!serializedState) {\n\t\tthrow new ProtocolError('Invalid or missing state');\n\t}\n\n\tlet state;\n\n\ttry {\n\t\tstate = parseState(serializedState);\n\t} catch {\n\t\tthrow new ProtocolError('Invalid or missing state');\n\t}\n\n\tawait options.stateStorage.delete(stateKey);\n\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst tokenUrl = url ?? metadata.token_endpoint;\n\tconst response = await options.httpClient.sendTokenRequest<Record<string, string>>(tokenUrl, {\n\t\tgrant_type: 'authorization_code',\n\t\tclient_id: options.clientId,\n\t\tredirect_uri: options.redirectUri,\n\t\tcode_verifier: state.codeVerifier,\n\t\tcode: session.code,\n\t});\n\n\tif (!response.ok) {\n\t\tawait throwTokenEndpointError(response);\n\t}\n\n\tlet data: Record<string, string>;\n\n\ttry {\n\t\tdata = await response.json();\n\t} catch {\n\t\tthrow new ProtocolError('Non-JSON response from token endpoint');\n\t}\n\n\tconst updatedSession: SessionData = { ...params, ...createSession(data) };\n\n\tif (updatedSession.error) {\n\t\tthrow new OidcError(updatedSession.error, updatedSession.error_description, updatedSession.error_uri);\n\t}\n\n\tif (updatedSession.id_token) {\n\t\tupdatedSession.claims = await verifyIdToken({ idToken: updatedSession.id_token, expectedNonce: state.nonce, options });\n\t}\n\n\treturn updatedSession;\n}\n\n/**\n * Refreshes the access token using the stored refresh token and persists the updated session.\n *\n * @param {Object} options - The options for refreshing the access token\n * @param {string} options.url - The token endpoint URL\n * @param {string} options.refreshToken - The refresh token to use for refreshing the access token\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options\n * @param {string} [options.grantType='refresh_token'] - The grant type to use for the token refresh request (default is 'refresh_token')\n * @param {string} [options.clientId] - Optional client ID to override the default client ID in the SDK options\n * @param {string} [options.audience] - Optional audience to include in the token refresh request\n * @param {string} [options.scope] - Optional scope to include in the token refresh request\n * @returns {Promise<SessionData>} A promise that resolves to the updated session data with refreshed tokens\n * @throws {ServerError} If the token refresh request fails with a server error (HTTP 429 or 5xx)\n * @throws {NetworkError} If the token refresh request fails due to network issues\n * @throws {OidcError} If the token refresh request returns an OIDC error response\n * @throws {ProtocolError} If the token refresh request returns an error or the ID token claims are invalid\n */\nexport async function refreshToken({\n\turl,\n\trefreshToken,\n\toptions,\n\tgrantType = 'refresh_token',\n\tclientId,\n\taudience,\n\tscope,\n\texpectedSub,\n}: {\n\turl?: string | URL;\n\trefreshToken: string;\n\toptions: SDKOptions;\n\tgrantType?: string;\n\tclientId?: string;\n\taudience?: string;\n\tscope?: string;\n\texpectedSub?: string;\n}): Promise<SessionData> {\n\tconst params: Record<string, string> = {\n\t\tgrant_type: grantType,\n\t\tclient_id: clientId ?? options.clientId,\n\t\trefresh_token: refreshToken,\n\t};\n\n\tif (audience) {\n\t\tparams.audience = audience;\n\t}\n\n\tif (scope) {\n\t\tparams.scope = scope;\n\t}\n\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst refreshUrl = url ?? metadata.token_endpoint;\n\tconst response = await options.httpClient.sendTokenRequest<Record<string, string>>(refreshUrl, params);\n\n\tif (!response.ok) {\n\t\tawait throwTokenEndpointError(response);\n\t}\n\n\tlet data: Record<string, string>;\n\n\ttry {\n\t\tdata = await response.json();\n\t} catch {\n\t\tthrow new ProtocolError('Non-JSON response from token endpoint');\n\t}\n\n\tconst updatedSession: SessionData = createSession(data);\n\n\tif (updatedSession.error) {\n\t\tthrow new OidcError(updatedSession.error, updatedSession.error_description, updatedSession.error_uri);\n\t}\n\n\tif (updatedSession.id_token) {\n\t\tupdatedSession.claims = await verifyIdToken({ idToken: updatedSession.id_token, expectedSub, options });\n\t}\n\n\treturn updatedSession;\n}\n\n/**\n * Revokes the best available token (refresh token preferred, then access token) and removes the session from storage.\n *\n * @param {Object} options - The options for revoking the token\n * @param {string | URL} options.url - The revocation endpoint URL\n * @param {string} options.tokenTypeHint - The type of token to revoke ('refresh_token' or 'access_token')\n * @param {string} options.token - The token to revoke\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options\n * @param {string} [options.clientId] - Optional client ID to override the default client ID in the SDK options\n * @returns {Promise<void>} A promise that resolves when the token is revoked and the session is cleared from storage\n * @throws {ServerError} If the token revocation request fails with a server error (HTTP 429 or 5xx)\n * @throws {ProtocolError} If the token revocation request returns an error or the ID token claims are invalid\n */\nexport async function revokeToken({\n\turl,\n\ttokenTypeHint,\n\ttoken,\n\toptions,\n\tclientId,\n}: {\n\turl?: string | URL;\n\ttokenTypeHint: string;\n\ttoken: string;\n\toptions: SDKOptions;\n\tclientId?: string;\n}): Promise<void> {\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst revokeUrl = url ?? metadata.revocation_endpoint;\n\n\tif (!revokeUrl) {\n\t\toptions.logging?.debug('Revocation skipped: no revocation_endpoint available');\n\t\treturn;\n\t}\n\n\tconst response = await options.httpClient.sendTokenRequest<Record<string, string>>(revokeUrl, {\n\t\tclient_id: clientId ?? options.clientId,\n\t\ttoken_type_hint: tokenTypeHint,\n\t\ttoken,\n\t});\n\n\tif (response && !response.ok) {\n\t\tawait throwTokenEndpointError(response);\n\t}\n}\n\n/**\n * Fetches the entry flow from the specified URL with the provided parameters and SDK options.\n *\n * @param {Object} options\n * @param {string | URL} options.url - The URL to request the entry flow from\n * @param {URLSearchParams} options.params - The parameters to include in the entry request\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options\n * @param {string} [options.clientId] - Optional client ID to override the default client ID in the SDK options\n * @param {string} [options.redirectUri] - Optional redirect URI to override the default redirect URI in the SDK options\n * @param {string} [options.sdkMode='web'] - Optional SDK mode to include in the entry request (default is 'web')\n * @returns {Promise<EntryResponse>} A promise resolving to the entry result.\n * @throws {OidcError} If the entry request returns an OIDC error response.\n * @throws {ServerError} If the entry request fails with a server error (HTTP 429 or 5xx).\n * @throws {ProtocolError} If the entry request fails with a protocol error or missing required fields.\n */\nexport async function fetchFlowEntry({\n\turl,\n\tparams,\n\toptions,\n\tclientId,\n\tredirectUri,\n\tsdkMode = 'web',\n}: {\n\turl: string | URL;\n\tparams: URLSearchParams;\n\toptions: SDKOptions;\n\tclientId?: string;\n\tredirectUri?: string;\n\tsdkMode?: string;\n}): Promise<EntryResponse> {\n\tparams.set('sdk', sdkMode);\n\tparams.set('client_id', clientId ?? options.clientId);\n\tparams.set('redirect_uri', redirectUri ?? options.redirectUri);\n\n\tconst requestUrl = new URL(url);\n\trequestUrl.search = params.toString();\n\n\tconst response = await options.httpClient.request<string | Record<string, string>>(requestUrl);\n\n\tif (!response.ok) {\n\t\tif (response.status === 400) {\n\t\t\tconst data = await response.json();\n\n\t\t\tif (data && typeof data === 'object') {\n\t\t\t\tif (data.error) {\n\t\t\t\t\tthrow new OidcError(data.error, data.error_description, data.error_uri);\n\t\t\t\t} else if (data.errorKey) {\n\t\t\t\t\tthrow new ProtocolError(data.errorKey);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow new ProtocolError('Entry request failed');\n\t\t}\n\n\t\tthrowHttpError(response.status, 'Entry request failed');\n\t}\n\n\tlet uri: URL;\n\tlet searchParams: Record<string, string>;\n\n\ttry {\n\t\turi = new URL(await response.text());\n\t\tsearchParams = Object.fromEntries(uri.searchParams.entries());\n\t} catch {\n\t\turi = new URL(response.url);\n\t\tsearchParams = Object.fromEntries(uri.searchParams.entries());\n\t}\n\n\tconst shortAppId = searchParams.short_app_id;\n\tconst sessionId = searchParams.session_id;\n\tconst language = searchParams.language || globalThis.navigator?.language || 'en-US';\n\n\tif (!sessionId) {\n\t\tthrow new ProtocolError('\"session_id\" is missing from the response');\n\t}\n\n\treturn { session_id: sessionId, short_app_id: shortAppId, language };\n}\n\n/**\n * Finalizes the login session using the provided url.\n *\n * @param {Object} options - The options for finalizing the session\n * @param {string | URL} options.url - The URL to finalize the session.\n * @param {string} options.sessionId - The session ID to finalize the session with.\n * @param {string} options.language - The language to use for the session.\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options.\n * @returns {Promise<URL>} A promise that resolves to the redirect URL after finalizing the session.\n * @throws {ServerError} If the request to finalize the session fails with a server error (HTTP 429 or 5xx).\n * @throws {ProtocolError} If the response from the server is invalid or does not contain a valid redirect URI.\n */\nexport async function finalizeLoginSession({\n\turl,\n\tsessionId,\n\tlanguage,\n\toptions,\n}: {\n\turl: string | URL;\n\tsessionId: string;\n\tlanguage: string;\n\toptions: SDKOptions;\n}): Promise<URL> {\n\tconst response = await options.httpClient.request(url, {\n\t\tmethod: 'GET',\n\t\tcredentials: 'include',\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${sessionId}`,\n\t\t\t'Accept-language': language,\n\t\t},\n\t});\n\n\tif (!response.ok) {\n\t\tthrowHttpError(response.status, 'Failed to finalize login session');\n\t}\n\n\tlet redirectUri: URL;\n\n\ttry {\n\t\tredirectUri = new URL(await response.text());\n\t} catch {\n\t\tthrow new ProtocolError('Invalid redirect URI');\n\t}\n\n\tif (!redirectUri.toString().startsWith(options.redirectUri)) {\n\t\tthrow new ProtocolError('Invalid redirect URI');\n\t}\n\n\treturn redirectUri;\n}\n\n/**\n * Submits a login form to the authentication server.\n *\n * @param {Object} options - The options for submitting the form.\n * @param {string} [options.formId] - The ID of the form to submit. If not provided, the init endpoint is used.\n * @param {Record<string, unknown>} [options.body] - The form data to include in the request body.\n * @param {string} options.sessionId - The session ID for the current authentication session.\n * @param {string} options.language - The language preference sent in the `Accept-language` header.\n * @param {SDKOptions} options.options - The SDK options.\n * @returns {Promise<NativeFlowState>} A promise that resolves to the current login flow state.\n * @throws {ServerError} If the server returns a non-recoverable HTTP error.\n * @throws {FallbackError} If the server indicates the flow should fall back to the hosted UI.\n * @throws {SessionExpiredError} If the session has expired (HTTP 403).\n */\nexport async function submitLoginForm({\n\tformId,\n\tbody,\n\tsessionId,\n\tlanguage,\n\toptions,\n}: {\n\tformId?: string;\n\tbody?: Record<string, unknown>;\n\tsessionId: string;\n\tlanguage: string;\n\toptions: SDKOptions;\n}): Promise<NativeFlowState> {\n\tconst response = await options.httpClient.request<NativeFlowState>(new URL(`/flow/api/v1/${formId ? `form/${formId}` : 'init'}`, options.issuer), {\n\t\tmethod: 'POST',\n\t\tcredentials: 'include',\n\t\tbody: JSON.stringify(body),\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${sessionId}`,\n\t\t\t'Content-Type': 'application/json',\n\t\t\t'Accept-language': language,\n\t\t},\n\t});\n\tlet data: NativeFlowState = {};\n\n\ttry {\n\t\tdata = await response.json();\n\t} catch {}\n\n\tif (!response.ok) {\n\t\tif (response.status === 403) {\n\t\t\tthrow new SessionExpiredError();\n\t\t}\n\n\t\tif (response.status >= 400 && response.status < 500 && data?.hostedUrl && !data.messages) {\n\t\t\tthrow new FallbackError(new URL(data.hostedUrl), `Received HTTP ${response.status} without messages`);\n\t\t}\n\n\t\tthrowHttpError(response.status, 'Failed to submit login form');\n\t}\n\n\tif (data.hostedUrl && !data.finalizeUrl && !data.forms && !data.messages) {\n\t\tthrow new FallbackError(new URL(data.hostedUrl), 'No forms or messages in response');\n\t}\n\n\treturn data;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"oidc.mjs","names":[],"sources":["../../src/utils/state.ts","../../src/utils/oidc.ts"],"sourcesContent":["import type { StateData } from '../types/oidc';\nimport { timestamp } from './common';\nimport { generateCodeVerifier, generateCodeChallenge, generateRandomHex } from './oidc';\n\n/**\n * Creates a new state object for OAuth 2.0 authorization requests, including a code verifier and challenge for PKCE.\n *\n * @param {Record<string, unknown>} [metadata={}] Optional metadata to associate with the state.\n * @returns {Promise<StateData>} A promise that resolves to the newly created state object.\n */\nexport async function createState(metadata: Record<string, unknown> = {}): Promise<StateData> {\n\tconst codeVerifier = generateCodeVerifier();\n\n\treturn {\n\t\tid: generateRandomHex(16),\n\t\tcreatedAt: timestamp(),\n\t\tcodeVerifier,\n\t\tmetadata,\n\t\tcodeChallenge: await generateCodeChallenge(codeVerifier),\n\t\tnonce: generateRandomHex(16),\n\t};\n}\n\n/**\n * Parses a serialized state string into a StateData object.\n *\n * @param {string} serialized - The serialized state string to parse.\n * @returns {StateData} The parsed StateData object.\n * @throws {Error} If the serialized string is invalid or cannot be parsed.\n */\nexport function parseState(serialized: string): StateData {\n\treturn JSON.parse(serialized) as StateData;\n}\n\n/**\n * Serializes a StateData object into a string for storage or transmission.\n *\n * @param {StateData} state - The StateData object to serialize.\n * @returns {string} The serialized state string.\n */\nexport function serializeState(state: StateData): string {\n\treturn JSON.stringify(state);\n}\n","import type { ExtraRequestArgs, IdTokenClaims, DiscoveryDocument, SDKOptions, SessionData, EntryResponse, FlowState, SigningKey } from '../types/oidc';\nimport type { NativeFlowState } from '../types/native';\nimport { decodeBase64URL, encodeBase64URL } from './base64url';\nimport { FallbackError, SessionExpiredError, OidcError, ProtocolError, ServerError, NetworkError, throwHttpError, throwTokenEndpointError } from './errors';\nimport { createHttpClient } from './httpClient';\nimport { createSession } from './session';\nimport { createState, parseState, serializeState } from './state';\nimport { redirectUrlHandler, redirectCallbackHandler } from '../handlers/redirect';\nimport { createLocalStorage } from '../storages/local';\nimport { createSessionStorage } from '../storages/session';\nimport { timestamp } from './common';\n\n/**\n * Stores the expiration timestamp of the cached OpenID configuration discovery document.\n */\nlet discoveryDocumentCacheExpiresAt = 0;\n\n/**\n * A promise that represents the ongoing fetch of the OpenID configuration discovery document.\n */\nlet discoveryDocumentFetchPromise: Promise<DiscoveryDocument> | null = null;\n\n/**\n * OpenID configuration discovery document cache.\n */\nlet discoveryDocument: DiscoveryDocument | null = null;\n\n/**\n * JSON Web Key Set (JWKS) cache.\n */\nconst jwksCache = new Map<string, { keys: Array<SigningKey>; expiresAt: number }>();\n\n/**\n * Returns the default flow state for the SDK.\n *\n * @returns {FlowState} The default flow state object.\n */\nexport function getDefaultFlowState(): FlowState {\n\treturn {\n\t\tinitialized: false,\n\t\tsession: null,\n\t\tsessionId: null,\n\t\tshortAppId: null,\n\t\tlanguage: globalThis.navigator?.language ?? 'en-US',\n\t};\n}\n\n/**\n * Returns the default SDK options for the SDK.\n */\nexport const defaultOptions: Partial<SDKOptions> = {\n\tlazyLoad: false,\n\tautoRefresh: true,\n\trefreshSkew: 60,\n\tserverSessionUri: null,\n\tscopes: ['openid'],\n\tresponseType: 'code',\n\tresponseMode: 'query',\n\tstorageTokenName: 'sty.session',\n\tdiscoveryDocumentCacheTTL: 3600,\n\tjwksCacheTTL: 600,\n} as const;\n\n/**\n * Fetches the OpenID configuration discovery document from the authorization server.\n * Caches the document for a specified duration to avoid unnecessary network requests.\n *\n * @param {SDKOptions} options - The SDK options containing the issuer URL and other configurations.\n * @returns {Promise<DiscoveryDocument>} A promise that resolves to the fetched discovery document.\n * @throws {ServerError} If the discovery document fetch fails with a server error (HTTP 429 or 5xx).\n * @throws {ProtocolError} If the discovery document is missing required fields or has an issuer mismatch.\n */\nexport async function getDiscoveryDocument(options: SDKOptions): Promise<DiscoveryDocument> {\n\tif (discoveryDocument && discoveryDocumentCacheExpiresAt > timestamp()) {\n\t\treturn discoveryDocument;\n\t}\n\n\tif (discoveryDocumentFetchPromise) {\n\t\treturn discoveryDocumentFetchPromise;\n\t}\n\n\tdiscoveryDocumentFetchPromise = (async () => {\n\t\ttry {\n\t\t\tconst response = await options.httpClient.request<DiscoveryDocument>(new URL('/.well-known/openid-configuration', options.issuer));\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new ServerError(`Failed to fetch OIDC metadata`, response.status);\n\t\t\t}\n\n\t\t\tlet metadata: DiscoveryDocument;\n\n\t\t\ttry {\n\t\t\t\tmetadata = await response.json();\n\t\t\t} catch {\n\t\t\t\tthrow new ProtocolError('Non-JSON response from discovery document endpoint');\n\t\t\t}\n\n\t\t\tif (metadata.issuer?.replace(/\\/$/, '') !== options.issuer.replace(/\\/$/, '')) {\n\t\t\t\tthrow new ProtocolError(`Discovery document issuer mismatch: expected ${options.issuer}, got ${metadata.issuer}`);\n\t\t\t}\n\n\t\t\tconst issuerHost = new URL(options.issuer).host;\n\n\t\t\tfor (const field of ['authorization_endpoint', 'token_endpoint', 'jwks_uri'] as const) {\n\t\t\t\tconst endpoint = metadata[field];\n\n\t\t\t\tif (!endpoint) {\n\t\t\t\t\tthrow new ProtocolError(`Discovery document is missing required field: ${field}`);\n\t\t\t\t}\n\n\t\t\t\tconst endpointUrl = new URL(endpoint);\n\n\t\t\t\tif (endpointUrl.protocol !== 'https:' || endpointUrl.host !== issuerHost) {\n\t\t\t\t\tthrow new ProtocolError(`Discovery document field \"${field}\" must be an https:// URL on ${issuerHost}, got ${endpoint}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const field of ['end_session_endpoint', 'revocation_endpoint'] as const) {\n\t\t\t\tconst endpoint = metadata[field];\n\n\t\t\t\tif (!endpoint) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst endpointUrl = new URL(endpoint);\n\n\t\t\t\tif (endpointUrl.protocol !== 'https:' || endpointUrl.host !== issuerHost) {\n\t\t\t\t\tthrow new ProtocolError(`Discovery document field \"${field}\" must be an https:// URL on ${issuerHost}, got ${endpoint}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!metadata.code_challenge_methods_supported?.includes('S256')) {\n\t\t\t\tthrow new ProtocolError('Discovery document does not advertise S256 PKCE support');\n\t\t\t}\n\n\t\t\tdiscoveryDocument = metadata;\n\t\t\tdiscoveryDocumentCacheExpiresAt = timestamp() + options.discoveryDocumentCacheTTL;\n\n\t\t\treturn metadata;\n\t\t} finally {\n\t\t\tdiscoveryDocumentFetchPromise = null;\n\t\t}\n\t})();\n\n\treturn discoveryDocumentFetchPromise;\n}\n\n/**\n * Returns the JWKS for the given URI, from cache unless it's stale or `forceRefresh` is set.\n *\n * @param {Object} options - The options for fetching the JWKS.\n * @param {string} options.jwksUri - The URL of the JWKS endpoint.\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options.\n * @param {boolean} [options.forceRefresh=false] - Bypasses the cache and fetches a fresh key set.\n * @returns {Promise<{ keys: Array<SigningKey> }>} The (possibly cached) key set.\n * @throws {NetworkError} If the JWKS fetch fails due to network issues.\n * @throws {ServerError} If the JWKS fetch fails with a server error (HTTP 429 or 5xx).\n */\nasync function getJwks({\n\tjwksUri,\n\toptions,\n\tforceRefresh = false,\n}: {\n\tjwksUri: string;\n\toptions: SDKOptions;\n\tforceRefresh?: boolean;\n}): Promise<{ keys: Array<SigningKey> }> {\n\tconst cached = jwksCache.get(jwksUri);\n\n\tif (!forceRefresh && cached && cached.expiresAt > timestamp()) {\n\t\treturn { keys: cached.keys };\n\t}\n\n\tlet jwksResponse: Response;\n\n\ttry {\n\t\tjwksResponse = await fetch(jwksUri);\n\t} catch {\n\t\tthrow new NetworkError(`Failed to fetch JWKS: ${jwksUri}`);\n\t}\n\n\tif (!jwksResponse.ok) {\n\t\tthrow new ServerError(`Failed to fetch JWKS: HTTP ${jwksResponse.status}`, jwksResponse.status);\n\t}\n\n\tconst jwks = (await jwksResponse.json()) as { keys: Array<SigningKey> };\n\n\tjwksCache.set(jwksUri, { keys: jwks.keys, expiresAt: timestamp() + options.jwksCacheTTL });\n\n\treturn jwks;\n}\n\n/**\n * Returns with the SDK options merged with the provided options.\n *\n * @param {SDKInitConfig} options - The SDK initialization configuration.\n * @template InitOptions - The type of the SDK initialization configuration.\n * @template Options - The type of the SDK options.\n * @returns {Options} The merged SDK options.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function getSDKOptions<Options extends SDKOptions = SDKOptions>(options: any): Options {\n\toptions.issuer = options.issuer.endsWith('/') ? options.issuer.slice(0, -1) : options.issuer;\n\toptions.storage ??= createLocalStorage();\n\toptions.stateStorage ??= createSessionStorage();\n\toptions.httpClient ??= createHttpClient(options.logging);\n\toptions.urlHandler ??= redirectUrlHandler;\n\toptions.callbackHandler ??= redirectCallbackHandler;\n\toptions.lazyLoad ??= defaultOptions.lazyLoad;\n\toptions.autoRefresh ??= defaultOptions.autoRefresh;\n\toptions.refreshSkew ??= defaultOptions.refreshSkew;\n\toptions.serverSessionUri ??= defaultOptions.serverSessionUri;\n\n\toptions.scopes ??= defaultOptions.scopes;\n\toptions.responseType ??= defaultOptions.responseType;\n\toptions.responseMode ??= defaultOptions.responseMode;\n\toptions.storageTokenName ??= defaultOptions.storageTokenName;\n\toptions.discoveryDocumentCacheTTL ??= defaultOptions.discoveryDocumentCacheTTL;\n\toptions.jwksCacheTTL ??= defaultOptions.jwksCacheTTL;\n\n\treturn options;\n}\n\n/**\n * Generates a code verifier for PKCE (Proof Key for Code Exchange).\n *\n * @returns {string} A randomly generated code verifier string.\n */\nexport function generateCodeVerifier(): string {\n\tconst bytes = new Uint8Array(32);\n\n\tglobalThis.crypto.getRandomValues(bytes);\n\n\treturn encodeBase64URL(bytes.buffer);\n}\n\n/**\n * Generates a code challenge from a code verifier using SHA-256 hashing.\n *\n * @param {string} codeVerifier The code verifier string.\n * @returns {Promise<string>} A promise that resolves to the generated code challenge.\n */\nexport async function generateCodeChallenge(codeVerifier: string): Promise<string> {\n\tconst encoded = new TextEncoder().encode(codeVerifier);\n\tconst hash = await globalThis.crypto.subtle.digest('SHA-256', encoded);\n\n\treturn encodeBase64URL(hash);\n}\n\n/**\n * Generates a random hexadecimal string of the specified byte length.\n *\n * @param {number} [byteLength=16] - The number of random bytes to generate (default is 16).\n * @returns {string} A randomly generated hexadecimal string.\n */\nexport function generateRandomHex(byteLength = 16): string {\n\tconst bytes = new Uint8Array(byteLength);\n\n\tglobalThis.crypto.getRandomValues(bytes);\n\n\treturn Array.from(bytes)\n\t\t.map((b) => b.toString(16).padStart(2, '0'))\n\t\t.join('');\n}\n\n/**\n * Decodes a JWT token and returns the payload as an object.\n *\n * @template T The expected structure of the JWT payload.\n * @param {string} token - The JWT token to decode.\n * @returns {T} The decoded payload of the JWT token.\n * @throws {ProtocolError} If the token is invalid or has the wrong format.\n */\nexport function decodeJwt<T = Record<string, unknown>>(token: string): T {\n\tconst [, payload] = token.split('.');\n\n\tif (!payload) {\n\t\tthrow new ProtocolError('Invalid JWT: missing payload segment');\n\t}\n\n\ttry {\n\t\treturn JSON.parse(new TextDecoder().decode(decodeBase64URL(payload))) as T;\n\t} catch {\n\t\tthrow new ProtocolError('Invalid JWT: payload is not valid base64url-encoded JSON');\n\t}\n}\n\n/**\n * Verifies a JWT token's signature against a JWKS endpoint.\n * Only RS256 is supported.\n *\n * @param {Object} options - The options for verifying the JWT.\n * @param {string} options.token - The JWT token to verify.\n * @param {string} options.jwksUri - The URL of the JWKS endpoint.\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options.\n * @template T - The expected structure of the JWT payload.\n * @returns {Promise<T>} The verified payload.\n * @throws {ProtocolError} If the token is invalid, the key is not found, or verification fails.\n */\nexport async function verifyJwt<T = Record<string, unknown>>({ token, jwksUri, options }: { token: string; jwksUri: string; options: SDKOptions }): Promise<T> {\n\tconst parts = token.split('.');\n\n\tif (parts.length !== 3) {\n\t\tthrow new ProtocolError('Invalid JWT: must have 3 parts');\n\t}\n\n\tconst [encodedHeader, encodedPayload, encodedSignature] = parts;\n\tconst header = JSON.parse(new TextDecoder().decode(decodeBase64URL(encodedHeader))) as { kid?: string; alg?: string };\n\n\tif (header.alg !== 'RS256') {\n\t\tthrow new ProtocolError(`Unsupported JWT algorithm: ${header.alg}`);\n\t}\n\n\tlet jwks = await getJwks({ jwksUri, options });\n\tlet signingKey = header.kid ? jwks.keys.find((k) => k.kid === header.kid) : jwks.keys.find((k) => k.alg === 'RS256');\n\n\tif (!signingKey && header.kid) {\n\t\tjwks = await getJwks({ jwksUri, options, forceRefresh: true });\n\t\tsigningKey = jwks.keys.find((k) => k.kid === header.kid);\n\t}\n\n\tif (!signingKey) {\n\t\tthrow new ProtocolError(`No matching key found in JWKS${header.kid ? ` for kid: ${header.kid}` : ''}`);\n\t}\n\n\tconst cryptoKey = await globalThis.crypto.subtle.importKey(\n\t\t'jwk',\n\t\t{ kty: signingKey.kty, n: signingKey.n, e: signingKey.e, alg: signingKey.alg, use: signingKey.use },\n\t\t{ name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-256' } },\n\t\tfalse,\n\t\t['verify'],\n\t);\n\tconst signature = decodeBase64URL(encodedSignature);\n\tconst data = new TextEncoder().encode(`${encodedHeader}.${encodedPayload}`);\n\tconst valid = await globalThis.crypto.subtle.verify({ name: 'RSASSA-PKCS1-v1_5' }, cryptoKey, signature, data);\n\n\tif (!valid) {\n\t\tthrow new ProtocolError('JWT signature verification failed');\n\t}\n\n\treturn JSON.parse(new TextDecoder().decode(decodeBase64URL(encodedPayload))) as T;\n}\n\n/**\n * Generates a signed JWT token using the provided header, payload, and private key.\n *\n * @param {object} header - The JWT header.\n * @param {object} payload - The JWT payload.\n * @param {CryptoKey} [privateKey] - The private key to sign the JWT. If not provided, an unsigned token will be generated.\n * @returns {Promise<string>} A promise that resolves to the signed JWT token.\n */\nexport async function generateJwt(header: object, payload: object, privateKey?: CryptoKey): Promise<string> {\n\tconst encodedHeader = encodeBase64URL(new TextEncoder().encode(JSON.stringify(header)).buffer);\n\tconst encodedPayload = encodeBase64URL(new TextEncoder().encode(JSON.stringify(payload)).buffer);\n\tconst encodedToken = `${encodedHeader}.${encodedPayload}`;\n\n\tif (privateKey) {\n\t\tconst signature = await globalThis.crypto.subtle.sign(\n\t\t\t{\n\t\t\t\tname: 'ECDSA',\n\t\t\t\thash: { name: 'SHA-256' },\n\t\t\t},\n\t\t\tprivateKey,\n\t\t\tnew TextEncoder().encode(encodedToken),\n\t\t);\n\n\t\treturn `${encodedToken}.${encodeBase64URL(signature)}`;\n\t}\n\n\treturn `${encodedToken}.signature`;\n}\n\n/**\n * Verifies and validates an ID token's claims.\n *\n * @param {Object} options - The options for verifying the ID token\n * @param {string} options.idToken - The ID token to verify\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options\n * @param {string} [options.expectedSub] - Optional expected subject (`sub`) claim to validate against the ID token\n * @param {string} [options.expectedNonce] - Optional expected nonce claim to validate against the ID token\n * @returns {Promise<IdTokenClaims>} The verified, validated claims.\n * @throws {ProtocolError} If the signature, `iss`, `aud`, `exp`, or `sub` fail validation.\n */\nexport async function verifyIdToken({\n\tidToken,\n\toptions,\n\tverifySignature = false,\n\texpectedSub,\n\texpectedNonce,\n}: {\n\tidToken: string;\n\toptions: SDKOptions;\n\tverifySignature?: boolean;\n\texpectedSub?: string;\n\texpectedNonce?: string;\n}): Promise<IdTokenClaims> {\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst claims = verifySignature ? await verifyJwt<IdTokenClaims>({ token: idToken, options, jwksUri: metadata.jwks_uri }) : decodeJwt<IdTokenClaims>(idToken);\n\tconst now = timestamp();\n\n\tif (claims?.iss !== metadata.issuer) {\n\t\tthrow new ProtocolError('Invalid iss');\n\t}\n\tif (Array.isArray(claims?.aud) ? !claims.aud.includes(options.clientId) : claims?.aud !== options.clientId) {\n\t\tthrow new ProtocolError('Invalid aud');\n\t}\n\tif (!claims?.exp || claims.exp <= now) {\n\t\tthrow new ProtocolError('Token has expired');\n\t}\n\tif (!claims?.sub || (expectedSub && claims.sub !== expectedSub)) {\n\t\tthrow new ProtocolError('Invalid sub');\n\t}\n\tif (expectedNonce && claims?.nonce !== expectedNonce) {\n\t\tthrow new ProtocolError('Invalid nonce');\n\t}\n\n\treturn claims;\n}\n\n/**\n * Builds the authorization URL with the provided parameters and configuration.\n *\n * @param {Object} options - The options for building the login URL and starting the session\n * @param {ExtraRequestArgs} options.params - The parameters for the authorization request, including optional prompts and hints\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options\n * @returns {Promise<URL>} A promise that resolves to the constructed authorization URL\n * @throws {Error} If fetching OIDC metadata fails or writing the PKCE state to storage fails.\n */\nexport async function buildAuthorizationUrl<URLHandlerParams extends ExtraRequestArgs = ExtraRequestArgs>({\n\turl,\n\tincludeOAuthParams = true,\n\tpersistState = true,\n\tparams,\n\toptions,\n}: {\n\turl?: string | null | URL;\n\tincludeOAuthParams?: boolean;\n\tpersistState?: boolean;\n\tparams: URLHandlerParams;\n\toptions: SDKOptions;\n}): Promise<URL> {\n\tconst stateData = await createState();\n\tstateData.metadata = {};\n\n\tif (!url) {\n\t\tconst metadata = await getDiscoveryDocument(options);\n\t\turl = new URL(metadata.authorization_endpoint);\n\t}\n\tif (typeof url === 'string') {\n\t\turl = new URL(url, globalThis.location.origin);\n\t}\n\n\tif (includeOAuthParams) {\n\t\tconst scopes = new Set(options.scopes ?? ['openid']);\n\n\t\turl.searchParams.set('client_id', options.clientId);\n\t\turl.searchParams.set('redirect_uri', options.redirectUri);\n\t\turl.searchParams.set('response_type', options.responseType ?? 'code');\n\t\turl.searchParams.set('response_mode', options.responseMode ?? 'query');\n\t\turl.searchParams.set('scope', Array.from(scopes).join(' '));\n\t\turl.searchParams.set('code_challenge_method', 'S256');\n\t\turl.searchParams.set('state', stateData.id);\n\t\turl.searchParams.set('code_challenge', stateData.codeChallenge);\n\n\t\tif (scopes.has('openid')) {\n\t\t\turl.searchParams.set('nonce', stateData.nonce);\n\t\t}\n\t}\n\n\tif (params.prompt) {\n\t\turl.searchParams.set('prompt', params.prompt);\n\t\tstateData.metadata.prompt = params.prompt;\n\t}\n\tif (params.display) {\n\t\turl.searchParams.set('display', params.display);\n\t\tstateData.metadata.display = params.display;\n\t}\n\tif (params.loginHint) {\n\t\turl.searchParams.set('login_hint', params.loginHint);\n\t\tstateData.metadata.loginHint = params.loginHint;\n\t}\n\tif (params.acrValues?.length) {\n\t\tconst acrValues = params.acrValues.filter(Boolean);\n\n\t\tif (acrValues.length) {\n\t\t\turl.searchParams.set('acr_values', acrValues.join(' '));\n\t\t\tstateData.metadata.acrValues = acrValues;\n\t\t}\n\t}\n\tif (params.uiLocales?.length) {\n\t\tconst uiLocales = params.uiLocales.filter(Boolean);\n\n\t\tif (uiLocales.length) {\n\t\t\turl.searchParams.set('ui_locales', uiLocales.join(' '));\n\t\t\tstateData.metadata.uiLocales = uiLocales;\n\t\t}\n\t}\n\tif (params.audiences?.length) {\n\t\tconst audiences = params.audiences.filter(Boolean);\n\n\t\tif (audiences.length) {\n\t\t\turl.searchParams.set('audience', audiences.join(' '));\n\t\t\tstateData.metadata.audiences = audiences;\n\t\t}\n\t}\n\n\tif (persistState) {\n\t\tawait options.stateStorage.set(`sty.${stateData.id}`, serializeState(stateData));\n\t}\n\n\treturn url;\n}\n\n/**\n * Builds the end session (logout) URL with optional parameters for ID token hint and post-logout redirect URI.\n *\n * @param {Object} options - The options for building the end session URL\n * @param {string | URL} options.url - The base URL for the end session endpoint\n * @param {string} options.idToken - The ID token to include as a hint for the end session request\n * @param {string} [options.postLogoutRedirectUri] - Optional URI to redirect to after logout\n * @returns {URL} A promise that resolves to the constructed end session URL\n * @throws {Error} If fetching metadata fails or the end session endpoint is not available\n */\nexport function buildEndSessionUrl({ url, idToken, postLogoutRedirectUri }: { url: string | URL; idToken: string; postLogoutRedirectUri?: string }): URL {\n\tconst endSessionUrl = new URL(url);\n\n\tendSessionUrl.searchParams.set('id_token_hint', idToken);\n\n\tif (postLogoutRedirectUri) {\n\t\tendSessionUrl.searchParams.set('post_logout_redirect_uri', postLogoutRedirectUri);\n\t}\n\n\treturn endSessionUrl;\n}\n\n/**\n * Exchanges an authorization code for tokens by sending a request to the token endpoint.\n * Validates the PKCE state and ID token claims, and returns the session data.\n *\n * @param {Object} options - The options for exchanging the authorization code\n * @param {string | URL} [options.url] - The token endpoint URL (optional, will be fetched from metadata if not provided)\n * @param {Record<string, string>} options.params - The parameters received from the authorization server, including the authorization code and state\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options\n * @returns {Promise<SessionData>} A promise that resolves to the session data containing tokens and claims\n * @throws {OidcError} If the token endpoint returns an OIDC error response\n * @throws {ServerError} If the token endpoint request fails with a server error (HTTP 429 or 5xx)\n * @throws {NetworkError} If the token endpoint request fails due to network issues\n * @throws {ProtocolError} If the authorization code or state is invalid, or if the token endpoint returns an error\n * @throws {ProtocolError} If the authorization code or state is invalid, or if the token endpoint returns an error\n */\nexport async function exchangeCode({\n\turl,\n\tparams,\n\toptions,\n}: {\n\turl?: string | URL;\n\tparams: Record<string, string>;\n\toptions: SDKOptions;\n}): Promise<SessionData> {\n\tconst session = createSession(params);\n\n\tif (session.error) {\n\t\tthrow new OidcError(session.error, session.error_description, session.error_uri);\n\t}\n\tif (!session.code) {\n\t\tthrow new ProtocolError('Invalid or missing authorization code');\n\t}\n\n\tconst stateKey = `sty.${session.state}`;\n\tconst serializedState = await options.stateStorage.get(stateKey);\n\n\tif (!serializedState) {\n\t\tthrow new ProtocolError('Invalid or missing state');\n\t}\n\n\tlet state;\n\n\ttry {\n\t\tstate = parseState(serializedState);\n\t} catch {\n\t\tthrow new ProtocolError('Invalid or missing state');\n\t}\n\n\tawait options.stateStorage.delete(stateKey);\n\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst tokenUrl = url ?? metadata.token_endpoint;\n\tconst response = await options.httpClient.sendTokenRequest<Record<string, string>>(tokenUrl, {\n\t\tgrant_type: 'authorization_code',\n\t\tclient_id: options.clientId,\n\t\tredirect_uri: options.redirectUri,\n\t\tcode_verifier: state.codeVerifier,\n\t\tcode: session.code,\n\t});\n\n\tif (!response.ok) {\n\t\tawait throwTokenEndpointError(response);\n\t}\n\n\tlet data: Record<string, string>;\n\n\ttry {\n\t\tdata = await response.json();\n\t} catch {\n\t\tthrow new ProtocolError('Non-JSON response from token endpoint');\n\t}\n\n\tconst updatedSession: SessionData = { ...params, ...createSession(data) };\n\n\tif (updatedSession.error) {\n\t\tthrow new OidcError(updatedSession.error, updatedSession.error_description, updatedSession.error_uri);\n\t}\n\n\tif (updatedSession.id_token) {\n\t\tupdatedSession.claims = await verifyIdToken({ idToken: updatedSession.id_token, expectedNonce: state.nonce, options });\n\t}\n\n\treturn updatedSession;\n}\n\n/**\n * Refreshes the access token using the stored refresh token and persists the updated session.\n *\n * @param {Object} options - The options for refreshing the access token\n * @param {string} options.url - The token endpoint URL\n * @param {string} options.refreshToken - The refresh token to use for refreshing the access token\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options\n * @param {string} [options.grantType='refresh_token'] - The grant type to use for the token refresh request (default is 'refresh_token')\n * @param {string} [options.clientId] - Optional client ID to override the default client ID in the SDK options\n * @param {string} [options.audience] - Optional audience to include in the token refresh request\n * @param {string} [options.scope] - Optional scope to include in the token refresh request\n * @returns {Promise<SessionData>} A promise that resolves to the updated session data with refreshed tokens\n * @throws {ServerError} If the token refresh request fails with a server error (HTTP 429 or 5xx)\n * @throws {NetworkError} If the token refresh request fails due to network issues\n * @throws {OidcError} If the token refresh request returns an OIDC error response\n * @throws {ProtocolError} If the token refresh request returns an error or the ID token claims are invalid\n */\nexport async function refreshToken({\n\turl,\n\trefreshToken,\n\toptions,\n\tgrantType = 'refresh_token',\n\tclientId,\n\taudience,\n\tscope,\n\texpectedSub,\n}: {\n\turl?: string | URL;\n\trefreshToken: string;\n\toptions: SDKOptions;\n\tgrantType?: string;\n\tclientId?: string;\n\taudience?: string;\n\tscope?: string;\n\texpectedSub?: string;\n}): Promise<SessionData> {\n\tconst params: Record<string, string> = {\n\t\tgrant_type: grantType,\n\t\tclient_id: clientId ?? options.clientId,\n\t\trefresh_token: refreshToken,\n\t};\n\n\tif (audience) {\n\t\tparams.audience = audience;\n\t}\n\n\tif (scope) {\n\t\tparams.scope = scope;\n\t}\n\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst refreshUrl = url ?? metadata.token_endpoint;\n\tconst response = await options.httpClient.sendTokenRequest<Record<string, string>>(refreshUrl, params);\n\n\tif (!response.ok) {\n\t\tawait throwTokenEndpointError(response);\n\t}\n\n\tlet data: Record<string, string>;\n\n\ttry {\n\t\tdata = await response.json();\n\t} catch {\n\t\tthrow new ProtocolError('Non-JSON response from token endpoint');\n\t}\n\n\tconst updatedSession: SessionData = createSession(data);\n\n\tif (updatedSession.error) {\n\t\tthrow new OidcError(updatedSession.error, updatedSession.error_description, updatedSession.error_uri);\n\t}\n\n\tif (updatedSession.id_token) {\n\t\tupdatedSession.claims = await verifyIdToken({ idToken: updatedSession.id_token, expectedSub, options });\n\t}\n\n\treturn updatedSession;\n}\n\n/**\n * Revokes the best available token (refresh token preferred, then access token) and removes the session from storage.\n *\n * @param {Object} options - The options for revoking the token\n * @param {string | URL} options.url - The revocation endpoint URL\n * @param {string} options.tokenTypeHint - The type of token to revoke ('refresh_token' or 'access_token')\n * @param {string} options.token - The token to revoke\n * @param {SDKOptions} options.options - The SDK options containing client ID, storage, and other options\n * @param {string} [options.clientId] - Optional client ID to override the default client ID in the SDK options\n * @returns {Promise<void>} A promise that resolves when the token is revoked and the session is cleared from storage\n * @throws {ServerError} If the token revocation request fails with a server error (HTTP 429 or 5xx)\n * @throws {ProtocolError} If the token revocation request returns an error or the ID token claims are invalid\n */\nexport async function revokeToken({\n\turl,\n\ttokenTypeHint,\n\ttoken,\n\toptions,\n\tclientId,\n}: {\n\turl?: string | URL;\n\ttokenTypeHint: string;\n\ttoken: string;\n\toptions: SDKOptions;\n\tclientId?: string;\n}): Promise<void> {\n\tconst metadata = await getDiscoveryDocument(options);\n\tconst revokeUrl = url ?? metadata.revocation_endpoint;\n\n\tif (!revokeUrl) {\n\t\toptions.logging?.debug('Revocation skipped: no revocation_endpoint available');\n\t\treturn;\n\t}\n\n\tconst response = await options.httpClient.sendTokenRequest<Record<string, string>>(revokeUrl, {\n\t\tclient_id: clientId ?? options.clientId,\n\t\ttoken_type_hint: tokenTypeHint,\n\t\ttoken,\n\t});\n\n\tif (response && !response.ok) {\n\t\tawait throwTokenEndpointError(response);\n\t}\n}\n\n/**\n * Fetches the entry flow from the specified URL with the provided parameters and SDK options.\n *\n * @param {Object} options\n * @param {string | URL} options.url - The URL to request the entry flow from\n * @param {URLSearchParams} options.params - The parameters to include in the entry request\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options\n * @param {string} [options.clientId] - Optional client ID to override the default client ID in the SDK options\n * @param {string} [options.redirectUri] - Optional redirect URI to override the default redirect URI in the SDK options\n * @param {string} [options.sdkMode='web'] - Optional SDK mode to include in the entry request (default is 'web')\n * @returns {Promise<EntryResponse>} A promise resolving to the entry result.\n * @throws {OidcError} If the entry request returns an OIDC error response.\n * @throws {ServerError} If the entry request fails with a server error (HTTP 429 or 5xx).\n * @throws {ProtocolError} If the entry request fails with a protocol error or missing required fields.\n */\nexport async function fetchFlowEntry({\n\turl,\n\tparams,\n\toptions,\n\tclientId,\n\tredirectUri,\n\tsdkMode = 'web',\n}: {\n\turl: string | URL;\n\tparams: URLSearchParams;\n\toptions: SDKOptions;\n\tclientId?: string;\n\tredirectUri?: string;\n\tsdkMode?: string;\n}): Promise<EntryResponse> {\n\tparams.set('sdk', sdkMode);\n\tparams.set('client_id', clientId ?? options.clientId);\n\tparams.set('redirect_uri', redirectUri ?? options.redirectUri);\n\n\tconst requestUrl = new URL(url);\n\trequestUrl.search = params.toString();\n\n\tconst response = await options.httpClient.request<string | Record<string, string>>(requestUrl);\n\n\tif (!response.ok) {\n\t\tif (response.status === 400) {\n\t\t\tconst data = await response.json();\n\n\t\t\tif (data && typeof data === 'object') {\n\t\t\t\tif (data.error) {\n\t\t\t\t\tthrow new OidcError(data.error, data.error_description, data.error_uri);\n\t\t\t\t} else if (data.errorKey) {\n\t\t\t\t\tthrow new ProtocolError(data.errorKey);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow new ProtocolError('Entry request failed');\n\t\t}\n\n\t\tthrowHttpError(response.status, 'Entry request failed');\n\t}\n\n\tlet uri: URL;\n\tlet searchParams: Record<string, string>;\n\n\ttry {\n\t\turi = new URL(await response.text());\n\t\tsearchParams = Object.fromEntries(uri.searchParams.entries());\n\t} catch {\n\t\turi = new URL(response.url);\n\t\tsearchParams = Object.fromEntries(uri.searchParams.entries());\n\t}\n\n\tconst shortAppId = searchParams.short_app_id;\n\tconst sessionId = searchParams.session_id;\n\tconst language = searchParams.language || globalThis.navigator?.language || 'en-US';\n\n\tif (!sessionId) {\n\t\tthrow new ProtocolError('\"session_id\" is missing from the response');\n\t}\n\n\treturn { session_id: sessionId, short_app_id: shortAppId, language };\n}\n\n/**\n * Finalizes the login session using the provided url.\n *\n * @param {Object} options - The options for finalizing the session\n * @param {string | URL} options.url - The URL to finalize the session.\n * @param {string} options.sessionId - The session ID to finalize the session with.\n * @param {string} options.language - The language to use for the session.\n * @param {SDKOptions} options.options - The SDK options containing client ID, redirect URI, storage, and other options.\n * @returns {Promise<URL>} A promise that resolves to the redirect URL after finalizing the session.\n * @throws {ServerError} If the request to finalize the session fails with a server error (HTTP 429 or 5xx).\n * @throws {ProtocolError} If the response from the server is invalid or does not contain a valid redirect URI.\n */\nexport async function finalizeLoginSession({\n\turl,\n\tsessionId,\n\tlanguage,\n\toptions,\n}: {\n\turl: string | URL;\n\tsessionId: string;\n\tlanguage: string;\n\toptions: SDKOptions;\n}): Promise<URL> {\n\tconst response = await options.httpClient.request(url, {\n\t\tmethod: 'GET',\n\t\tcredentials: 'include',\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${sessionId}`,\n\t\t\t'Accept-language': language,\n\t\t},\n\t});\n\n\tif (!response.ok) {\n\t\tthrowHttpError(response.status, 'Failed to finalize login session');\n\t}\n\n\tlet redirectUri: URL;\n\n\ttry {\n\t\tredirectUri = new URL(await response.text());\n\t} catch {\n\t\tthrow new ProtocolError('Invalid redirect URI');\n\t}\n\n\tif (!redirectUri.toString().startsWith(options.redirectUri)) {\n\t\tthrow new ProtocolError('Invalid redirect URI');\n\t}\n\n\treturn redirectUri;\n}\n\n/**\n * Submits a login form to the authentication server.\n *\n * @param {Object} options - The options for submitting the form.\n * @param {string} [options.formId] - The ID of the form to submit. If not provided, the init endpoint is used.\n * @param {Record<string, unknown>} [options.body] - The form data to include in the request body.\n * @param {string} options.sessionId - The session ID for the current authentication session.\n * @param {string} options.language - The language preference sent in the `Accept-language` header.\n * @param {SDKOptions} options.options - The SDK options.\n * @returns {Promise<NativeFlowState>} A promise that resolves to the current login flow state.\n * @throws {ServerError} If the server returns a non-recoverable HTTP error.\n * @throws {FallbackError} If the server indicates the flow should fall back to the hosted UI.\n * @throws {SessionExpiredError} If the session has expired (HTTP 403).\n */\nexport async function submitLoginForm({\n\tformId,\n\tbody,\n\tsessionId,\n\tlanguage,\n\toptions,\n}: {\n\tformId?: string;\n\tbody?: Record<string, unknown>;\n\tsessionId: string;\n\tlanguage: string;\n\toptions: SDKOptions;\n}): Promise<NativeFlowState> {\n\tconst response = await options.httpClient.request<NativeFlowState>(new URL(`/flow/api/v1/${formId ? `form/${formId}` : 'init'}`, options.issuer), {\n\t\tmethod: 'POST',\n\t\tcredentials: 'include',\n\t\tbody: JSON.stringify(body),\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${sessionId}`,\n\t\t\t'Content-Type': 'application/json',\n\t\t\t'Accept-language': language,\n\t\t},\n\t});\n\tlet data: NativeFlowState = {};\n\n\ttry {\n\t\tdata = await response.json();\n\t} catch {}\n\n\tif (!response.ok) {\n\t\tif (response.status === 403) {\n\t\t\tthrow new SessionExpiredError();\n\t\t}\n\n\t\tif (response.status >= 400 && response.status < 500 && data?.hostedUrl && !data.messages) {\n\t\t\tthrow new FallbackError(new URL(data.hostedUrl), `Received HTTP ${response.status} without messages`);\n\t\t}\n\n\t\tthrowHttpError(response.status, 'Failed to submit login form');\n\t}\n\n\tif (data.hostedUrl && !data.finalizeUrl && !data.forms && !data.messages) {\n\t\tthrow new FallbackError(new URL(data.hostedUrl), 'No forms or messages in response');\n\t}\n\n\treturn data;\n}\n"],"mappings":"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"}
|
package/dist/flows/base.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../utils/errors.cjs"),t=require("../utils/session.cjs"),n=require("../assets/oidc.cjs");function r(r,i){let a={init:null,refresh:null,revoke:null,logout:null,tokenExchange:new Map},o={accessTokenExpired:new Set,init:new Set,loggedIn:new Set,sessionUpdated:new Set,sessionCleared:new Set,loginInitiated:new Set,flowInitiated:new Set,logoutInitiated:new Set,sessionLoaded:new Set,tokenRefreshed:new Set,tokenRefreshFailed:new Set,tokenRevoked:new Set,tokenRevokeFailed:new Set};function s(e,t){for(let n of o[e])n(...t)}function c(e,t){return o[e].add(t),{dispose:()=>o[e].delete(t)}}function l(e){for(let t in o)o[t].add(e);return{dispose:()=>{for(let t in o)o[t].delete(e)}}}async function u(){return await m(),r.session}async function d(e){await m(),e.id_token&&!e.claims&&(e.claims=await n.v({idToken:e.id_token,options:i})),i.serverSessionUri||await i.storage.set(i.storageTokenName,t.serializeSession(e)),r.session=e,s(`sessionUpdated`,[{idToken:r.session.id_token,accessToken:r.session.access_token,refreshToken:r.session.refresh_token,claims:r.session.claims}])}async function f(){await m(),i.serverSessionUri||await i.storage.delete(i.storageTokenName),r.session=null,s(`sessionCleared`,[])}async function p(e={autoRefresh:i.autoRefresh}){if(r.session?.access_token&&!t.isSessionExpired(r.session))return!0;if(e?.autoRefresh&&r.session?.refresh_token)try{await _()}catch{return!1}return!t.isSessionExpired(r.session)}async function m(){if(!r.initialized)return a.init||=(async()=>{try{if(!i.issuer){let t=new e.ConfigurationError(`Missing option: issuer`);throw i.logging?.error(`Required option missing`,t),t}if(!i.clientId){let t=new e.ConfigurationError(`Missing option: clientId`);throw i.logging?.error(`Required option missing`,t),t}if(!i.redirectUri){let t=new e.ConfigurationError(`Missing option: redirectUri`);throw i.logging?.error(`Required option missing`,t),t}if(i.scopes&&!Array.isArray(i.scopes)){let t=new e.ConfigurationError(`Invalid option: scopes`);throw i.logging?.error(`Invalid option provided`,t),t}i.serverSessionUri||(r.session=t.loadSession(await i.storage.get(i.storageTokenName))),r.initialized=!0,s(`init`,[]),i.logging?.debug(`SDK initialized`),!r.session&&!i.serverSessionUri&&i.logging?.debug(`No session found in storage`),r.session?.access_token&&(s(`sessionLoaded`,[{idToken:r.session.id_token,accessToken:r.session.access_token,refreshToken:r.session.refresh_token,claims:r.session.claims}]),i.logging?.debug(`Session loaded from storage`)),r.session?.access_token&&t.isSessionExpired(r.session)&&(s(`accessTokenExpired`,[{accessToken:r.session.access_token,refreshToken:r.session.refresh_token}]),i.logging?.debug(`Access token has expired`))}finally{a.init=null}})(),a.init}async function h(t={}){await m();let r=t.state??``,o=a.tokenExchange.get(r);if(o)return o;let c=(async()=>{i.logging?.debug(`Exchanging authorization code for tokens`);try{let r=await n.a({params:t,options:i});if(!r.access_token)throw new e.ProtocolError(`Missing access_token`);await d(r),i.logging?.debug(`Token exchange successful`),s(`loggedIn`,[{idToken:r.id_token,accessToken:r.access_token,refreshToken:r.refresh_token,claims:r.claims}]),i.logging&&(i.logging.xEventId=void 0,i.logging.info(`Login successful`))}catch(e){throw i.logging?.error(`Token exchange failed`,e),e}finally{a.tokenExchange.delete(r)}})();return a.tokenExchange.set(r,c),c}async function g(e){await m();let t=e??globalThis.window?.location.href;await h(await i.callbackHandler(t,i.responseMode))}async function _(){if(await m(),a.refresh)return a.refresh;if(a.revoke)try{await a.revoke}catch{}if(a.logout)try{await a.logout}catch{}if(i.logging?.debug(`Attempting to refresh session`),typeof r.session?.refresh_token!=`string`){i.logging?.debug(`Refresh called without refresh token`);return}return a.refresh=(async()=>{try{await d(await n.h({refreshToken:r.session.refresh_token,options:i,expectedSub:r.session?.claims?.sub})),s(`tokenRefreshed`,[{idToken:r.session?.id_token,accessToken:r.session?.access_token,refreshToken:r.session?.refresh_token,claims:r.session?.claims}]),i.logging?.debug(`Session refresh successful`)}catch(t){let n=r.session?.refresh_token;throw!(t instanceof e.NetworkError)&&!(t instanceof e.ServerError)&&await f(),s(`tokenRefreshFailed`,[{refreshToken:n}]),i.logging?.error(`Session refresh failed`,t),t}finally{a.refresh=null}})(),a.refresh}async function v(){if(await m(),a.revoke)return a.revoke;if(a.refresh)try{await a.refresh}catch{}if(a.logout)try{await a.logout}catch{}return a.revoke=(async()=>{try{r.session?.refresh_token?i.logging?.debug(`Attempting to revoke refresh token`):r.session?.access_token&&i.logging?.debug(`Attempting to revoke access token`);let e=r.session;if(await f(),!e?.access_token&&!e?.refresh_token){i.logging?.debug(`Revoke called without session`);return}let t=e.refresh_token?`refresh_token`:`access_token`,a=t===`refresh_token`?e.refresh_token:e.access_token;try{await n.g({tokenTypeHint:t,token:a,options:i}),t===`refresh_token`?(s(`tokenRevoked`,[{token:e.refresh_token,tokenTypeHint:`refresh_token`}]),i.logging?.info(`Refresh token successfully revoked`)):(s(`tokenRevoked`,[{token:e.access_token,tokenTypeHint:`access_token`}]),i.logging?.info(`Access token successfully revoked`))}catch(n){throw t===`refresh_token`?s(`tokenRevokeFailed`,[{token:e.refresh_token,tokenTypeHint:`refresh_token`}]):s(`tokenRevokeFailed`,[{token:e.access_token,tokenTypeHint:`access_token`}]),i.logging?.error(`Token revocation failed`,n),n}}finally{a.revoke=null}})(),a.revoke}async function y(e){if(await m(),a.logout)return a.logout;if(a.revoke)try{await a.revoke}catch{}if(a.refresh)try{await a.refresh}catch{}return a.logout=(async()=>{try{i.logging?.debug(`Attempting to logout`);let t=r.session;if(await f(),s(`logoutInitiated`,[{idToken:t?.id_token,claims:t?.claims}]),i.logging?.debug(`Logout initiated`),!t?.id_token){i.logging?.debug(`Logout called without id token`);return}try{let r=await n.p(i),a=n.n({url:r.end_session_endpoint,idToken:t.id_token,postLogoutRedirectUri:e?.postLogoutRedirectUri});await i.urlHandler(a,e)}catch(e){i.logging?.error(`Unable to redirect to the end-session endpoint`,e)}}finally{a.logout=null}})(),a.logout}return{dispatchEvent:s,subscribeToEvent:c,subscribeToAllEvents:l,getSession:u,updateSession:d,cleanupSession:f,checkAuthentication:p,init:m,tokenExchange:h,handleCallback:g,refresh:_,revoke:v,logout:y}}exports.createBaseFlow=r;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../utils/errors.cjs"),t=require("../utils/session.cjs"),n=require("../assets/oidc.cjs");function r(r,i){let a={init:null,refresh:null,revoke:null,logout:null,tokenExchange:new Map},o={accessTokenExpired:new Set,init:new Set,loggedIn:new Set,sessionUpdated:new Set,sessionCleared:new Set,loginInitiated:new Set,flowInitiated:new Set,logoutInitiated:new Set,sessionLoaded:new Set,tokenRefreshed:new Set,tokenRefreshFailed:new Set,tokenRevoked:new Set,tokenRevokeFailed:new Set};function s(e,t){for(let n of o[e])n(...t)}function c(e,t){return o[e].add(t),{dispose:()=>o[e].delete(t)}}function l(e){for(let t in o)o[t].add(e);return{dispose:()=>{for(let t in o)o[t].delete(e)}}}async function u(){return await m(),r.session}async function d(e){await m(),e.id_token&&!e.claims&&(e.claims=await n.v({idToken:e.id_token,options:i})),i.serverSessionUri||await i.storage.set(i.storageTokenName,t.serializeSession(e)),r.session=e,s(`sessionUpdated`,[{idToken:r.session.id_token,accessToken:r.session.access_token,refreshToken:r.session.refresh_token,claims:r.session.claims}])}async function f(){await m(),i.serverSessionUri||await i.storage.delete(i.storageTokenName),r.session=null,s(`sessionCleared`,[])}async function p(e={autoRefresh:i.autoRefresh}){if(r.session?.access_token&&!t.isSessionExpired(r.session,i.refreshSkew))return!0;if(e?.autoRefresh&&r.session?.refresh_token)try{await _()}catch{return!1}return!t.isSessionExpired(r.session)}async function m(){if(!r.initialized)return a.init||=(async()=>{try{if(!i.issuer){let t=new e.ConfigurationError(`Missing option: issuer`);throw i.logging?.error(`Required option missing`,t),t}if(!i.clientId){let t=new e.ConfigurationError(`Missing option: clientId`);throw i.logging?.error(`Required option missing`,t),t}if(!i.redirectUri){let t=new e.ConfigurationError(`Missing option: redirectUri`);throw i.logging?.error(`Required option missing`,t),t}if(i.scopes&&!Array.isArray(i.scopes)){let t=new e.ConfigurationError(`Invalid option: scopes`);throw i.logging?.error(`Invalid option provided`,t),t}i.serverSessionUri||(r.session=t.loadSession(await i.storage.get(i.storageTokenName))),r.initialized=!0,s(`init`,[]),i.logging?.debug(`SDK initialized`),!r.session&&!i.serverSessionUri&&i.logging?.debug(`No session found in storage`),r.session?.access_token&&(s(`sessionLoaded`,[{idToken:r.session.id_token,accessToken:r.session.access_token,refreshToken:r.session.refresh_token,claims:r.session.claims}]),i.logging?.debug(`Session loaded from storage`)),r.session?.access_token&&t.isSessionExpired(r.session)&&(s(`accessTokenExpired`,[{accessToken:r.session.access_token,refreshToken:r.session.refresh_token}]),i.logging?.debug(`Access token has expired`))}finally{a.init=null}})(),a.init}async function h(t={}){await m();let r=t.state??``,o=a.tokenExchange.get(r);if(o)return o;let c=(async()=>{i.logging?.debug(`Exchanging authorization code for tokens`);try{let r=await n.a({params:t,options:i});if(!r.access_token)throw new e.ProtocolError(`Missing access_token`);await d(r),i.logging?.debug(`Token exchange successful`),s(`loggedIn`,[{idToken:r.id_token,accessToken:r.access_token,refreshToken:r.refresh_token,claims:r.claims}]),i.logging&&(i.logging.xEventId=void 0,i.logging.info(`Login successful`))}catch(e){throw i.logging?.error(`Token exchange failed`,e),e}finally{a.tokenExchange.delete(r)}})();return a.tokenExchange.set(r,c),c}async function g(e){await m();let t=e??globalThis.window?.location.href;await h(await i.callbackHandler(t,i.responseMode))}async function _(){if(await m(),a.refresh)return a.refresh;if(a.revoke)try{await a.revoke}catch{}if(a.logout)try{await a.logout}catch{}if(i.logging?.debug(`Attempting to refresh session`),typeof r.session?.refresh_token!=`string`){i.logging?.debug(`Refresh called without refresh token`);return}return a.refresh=(async()=>{try{await d(await n.h({refreshToken:r.session.refresh_token,options:i,expectedSub:r.session?.claims?.sub})),s(`tokenRefreshed`,[{idToken:r.session?.id_token,accessToken:r.session?.access_token,refreshToken:r.session?.refresh_token,claims:r.session?.claims}]),i.logging?.debug(`Session refresh successful`)}catch(t){let n=r.session?.refresh_token;throw!(t instanceof e.NetworkError)&&!(t instanceof e.ServerError)&&await f(),s(`tokenRefreshFailed`,[{refreshToken:n}]),i.logging?.error(`Session refresh failed`,t),t}finally{a.refresh=null}})(),a.refresh}async function v(){if(await m(),a.revoke)return a.revoke;if(a.refresh)try{await a.refresh}catch{}if(a.logout)try{await a.logout}catch{}return a.revoke=(async()=>{try{r.session?.refresh_token?i.logging?.debug(`Attempting to revoke refresh token`):r.session?.access_token&&i.logging?.debug(`Attempting to revoke access token`);let e=r.session;if(await f(),!e?.access_token&&!e?.refresh_token){i.logging?.debug(`Revoke called without session`);return}let t=e.refresh_token?`refresh_token`:`access_token`,a=t===`refresh_token`?e.refresh_token:e.access_token;try{await n.g({tokenTypeHint:t,token:a,options:i}),t===`refresh_token`?(s(`tokenRevoked`,[{token:e.refresh_token,tokenTypeHint:`refresh_token`}]),i.logging?.info(`Refresh token successfully revoked`)):(s(`tokenRevoked`,[{token:e.access_token,tokenTypeHint:`access_token`}]),i.logging?.info(`Access token successfully revoked`))}catch(n){throw t===`refresh_token`?s(`tokenRevokeFailed`,[{token:e.refresh_token,tokenTypeHint:`refresh_token`}]):s(`tokenRevokeFailed`,[{token:e.access_token,tokenTypeHint:`access_token`}]),i.logging?.error(`Token revocation failed`,n),n}}finally{a.revoke=null}})(),a.revoke}async function y(e){if(await m(),a.logout)return a.logout;if(a.revoke)try{await a.revoke}catch{}if(a.refresh)try{await a.refresh}catch{}return a.logout=(async()=>{try{i.logging?.debug(`Attempting to logout`);let t=r.session;if(await f(),s(`logoutInitiated`,[{idToken:t?.id_token,claims:t?.claims}]),i.logging?.debug(`Logout initiated`),!t?.id_token){i.logging?.debug(`Logout called without id token`);return}try{let r=await n.p(i),a=n.n({url:r.end_session_endpoint,idToken:t.id_token,postLogoutRedirectUri:e?.postLogoutRedirectUri});await i.urlHandler(a,e)}catch(e){i.logging?.error(`Unable to redirect to the end-session endpoint`,e)}}finally{a.logout=null}})(),a.logout}return{dispatchEvent:s,subscribeToEvent:c,subscribeToAllEvents:l,getSession:u,updateSession:d,cleanupSession:f,checkAuthentication:p,init:m,tokenExchange:h,handleCallback:g,refresh:_,revoke:v,logout:y}}exports.createBaseFlow=r;
|
|
2
2
|
//# sourceMappingURL=base.cjs.map
|
package/dist/flows/base.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.cjs","names":[],"sources":["../../src/flows/base.ts"],"sourcesContent":["import type { EventFunctions, ExtraRequestArgs, FlowState, SDK, SDKOptions, SessionData } from '../types/oidc';\nimport { buildEndSessionUrl, exchangeCode, getDiscoveryDocument, refreshToken, revokeToken, verifyIdToken } from '../utils/oidc';\nimport { loadSession, serializeSession, isSessionExpired } from '../utils/session';\nimport { ConfigurationError, NetworkError, ProtocolError, ServerError } from '../utils/errors';\n\n/**\n * Creates a base flow for the Strivacity SDK, providing common functionality for managing authentication sessions.\n *\n * @param flowState - The initial state of the flow, including session data and initialization status.\n * @param options - The SDK options, including issuer, clientId, redirectUri, scopes, and storage configuration.\n * @template URLHandlerParams - The type of additional request arguments for URL handling.\n * @returns An object implementing the SDK interface, with methods for initializing the flow, managing sessions, and handling authentication events.\n */\nexport function createBaseFlow<URLHandlerParams extends ExtraRequestArgs = ExtraRequestArgs>(flowState: FlowState, options: SDKOptions) {\n\tconst promises: Record<'init' | 'refresh' | 'revoke' | 'logout', Promise<void> | null> & { tokenExchange: Map<string, Promise<void>> } = {\n\t\tinit: null,\n\t\trefresh: null,\n\t\trevoke: null,\n\t\tlogout: null,\n\t\ttokenExchange: new Map(),\n\t};\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tconst eventCallbacks: Record<keyof EventFunctions, Set<(...args: Array<any>) => Promise<void> | void>> = {\n\t\taccessTokenExpired: new Set(),\n\t\tinit: new Set(),\n\t\tloggedIn: new Set(),\n\t\tsessionUpdated: new Set(),\n\t\tsessionCleared: new Set(),\n\t\tloginInitiated: new Set(),\n\t\tflowInitiated: new Set(),\n\t\tlogoutInitiated: new Set(),\n\t\tsessionLoaded: new Set(),\n\t\ttokenRefreshed: new Set(),\n\t\ttokenRefreshFailed: new Set(),\n\t\ttokenRevoked: new Set(),\n\t\ttokenRevokeFailed: new Set(),\n\t};\n\n\tfunction dispatchEvent<T extends keyof EventFunctions>(eventName: T, args: Parameters<EventFunctions[T]>): void {\n\t\tfor (const fn of eventCallbacks[eventName]) {\n\t\t\tvoid fn(...args);\n\t\t}\n\t}\n\n\tfunction subscribeToEvent<T extends keyof EventFunctions>(\n\t\teventName: T,\n\t\tcallbackFn: (...params: Parameters<EventFunctions[T]>) => Promise<void> | void,\n\t): ReturnType<SDK<URLHandlerParams>['subscribeToEvent']> {\n\t\teventCallbacks[eventName].add(callbackFn);\n\t\treturn { dispose: () => eventCallbacks[eventName].delete(callbackFn) };\n\t}\n\n\tfunction subscribeToAllEvents(callbackFn: (...params: Array<unknown>) => Promise<void> | void): ReturnType<SDK<URLHandlerParams>['subscribeToAllEvents']> {\n\t\tfor (const eventName in eventCallbacks) {\n\t\t\teventCallbacks[eventName as keyof EventFunctions].add(callbackFn);\n\t\t}\n\n\t\treturn {\n\t\t\tdispose: () => {\n\t\t\t\tfor (const eventName in eventCallbacks) {\n\t\t\t\t\teventCallbacks[eventName as keyof EventFunctions].delete(callbackFn);\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\tasync function getSession(): Promise<SessionData | null> {\n\t\tawait init();\n\n\t\treturn flowState.session;\n\t}\n\n\tasync function updateSession(newData: SessionData): ReturnType<SDK<URLHandlerParams>['updateSession']> {\n\t\tawait init();\n\n\t\t// NOTE: only unverified callers (e.g. direct API use) need validating here\n\t\tif (newData.id_token && !newData.claims) {\n\t\t\tnewData.claims = await verifyIdToken({ idToken: newData.id_token, options });\n\t\t}\n\n\t\tif (!options.serverSessionUri) {\n\t\t\tawait options.storage.set(options.storageTokenName, serializeSession(newData));\n\t\t}\n\n\t\tflowState.session = newData;\n\n\t\tdispatchEvent('sessionUpdated', [\n\t\t\t{\n\t\t\t\tidToken: flowState.session.id_token,\n\t\t\t\taccessToken: flowState.session.access_token,\n\t\t\t\trefreshToken: flowState.session.refresh_token,\n\t\t\t\tclaims: flowState.session.claims,\n\t\t\t},\n\t\t]);\n\t}\n\n\tasync function cleanupSession(): ReturnType<SDK<URLHandlerParams>['cleanupSession']> {\n\t\tawait init();\n\n\t\tif (!options.serverSessionUri) {\n\t\t\tawait options.storage.delete(options.storageTokenName);\n\t\t}\n\n\t\tflowState.session = null;\n\n\t\tdispatchEvent('sessionCleared', []);\n\t}\n\n\tasync function checkAuthentication(\n\t\tparams: { autoRefresh: boolean } = { autoRefresh: options.autoRefresh },\n\t): ReturnType<SDK<URLHandlerParams>['checkAuthentication']> {\n\t\tif (flowState.session?.access_token && !isSessionExpired(flowState.session)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (params?.autoRefresh && flowState.session?.refresh_token) {\n\t\t\ttry {\n\t\t\t\tawait refresh();\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn !isSessionExpired(flowState.session);\n\t}\n\n\tasync function init(): ReturnType<SDK<URLHandlerParams>['init']> {\n\t\tif (flowState.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (promises.init) {\n\t\t\treturn promises.init;\n\t\t}\n\n\t\tpromises.init = (async () => {\n\t\t\ttry {\n\t\t\t\tif (!options.issuer) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: issuer');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (!options.clientId) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: clientId');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (!options.redirectUri) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: redirectUri');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (options.scopes && !Array.isArray(options.scopes)) {\n\t\t\t\t\tconst error = new ConfigurationError('Invalid option: scopes');\n\t\t\t\t\toptions.logging?.error('Invalid option provided', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\tif (!options.serverSessionUri) {\n\t\t\t\t\tflowState.session = loadSession(await options.storage.get(options.storageTokenName));\n\t\t\t\t}\n\n\t\t\t\tflowState.initialized = true;\n\n\t\t\t\tdispatchEvent('init', []);\n\t\t\t\toptions.logging?.debug('SDK initialized');\n\n\t\t\t\tif (!flowState.session && !options.serverSessionUri) {\n\t\t\t\t\toptions.logging?.debug('No session found in storage');\n\t\t\t\t}\n\n\t\t\t\tif (flowState.session?.access_token) {\n\t\t\t\t\tdispatchEvent('sessionLoaded', [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tidToken: flowState.session.id_token,\n\t\t\t\t\t\t\taccessToken: flowState.session.access_token,\n\t\t\t\t\t\t\trefreshToken: flowState.session.refresh_token,\n\t\t\t\t\t\t\tclaims: flowState.session.claims,\n\t\t\t\t\t\t},\n\t\t\t\t\t]);\n\t\t\t\t\toptions.logging?.debug('Session loaded from storage');\n\t\t\t\t}\n\n\t\t\t\tif (flowState.session?.access_token && isSessionExpired(flowState.session)) {\n\t\t\t\t\tdispatchEvent('accessTokenExpired', [{ accessToken: flowState.session.access_token, refreshToken: flowState.session.refresh_token }]);\n\t\t\t\t\toptions.logging?.debug('Access token has expired');\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.init = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.init;\n\t}\n\n\tasync function tokenExchange(params: Parameters<SDK<URLHandlerParams>['tokenExchange']>[0] = {}): ReturnType<SDK<URLHandlerParams>['tokenExchange']> {\n\t\tawait init();\n\n\t\tconst exchangeKey = params.state ?? '';\n\t\tconst inFlight = promises.tokenExchange.get(exchangeKey);\n\n\t\tif (inFlight) {\n\t\t\treturn inFlight;\n\t\t}\n\n\t\tconst exchangePromise = (async () => {\n\t\t\toptions.logging?.debug('Exchanging authorization code for tokens');\n\n\t\t\ttry {\n\t\t\t\tconst session = await exchangeCode({ params, options });\n\n\t\t\t\tif (!session.access_token) {\n\t\t\t\t\tthrow new ProtocolError('Missing access_token');\n\t\t\t\t}\n\n\t\t\t\tawait updateSession(session);\n\n\t\t\t\toptions.logging?.debug('Token exchange successful');\n\n\t\t\t\tdispatchEvent('loggedIn', [\n\t\t\t\t\t{ idToken: session.id_token, accessToken: session.access_token, refreshToken: session.refresh_token, claims: session.claims },\n\t\t\t\t]);\n\n\t\t\t\tif (options.logging) {\n\t\t\t\t\toptions.logging.xEventId = undefined;\n\t\t\t\t\toptions.logging.info('Login successful');\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\toptions.logging?.error('Token exchange failed', error);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tpromises.tokenExchange.delete(exchangeKey);\n\t\t\t}\n\t\t})();\n\n\t\tpromises.tokenExchange.set(exchangeKey, exchangePromise);\n\n\t\treturn exchangePromise;\n\t}\n\n\tasync function handleCallback(url?: string | URL): ReturnType<SDK<URLHandlerParams>['handleCallback']> {\n\t\tawait init();\n\n\t\tconst callbackUrl = url ?? globalThis.window?.location.href;\n\t\tconst params = (await options.callbackHandler(callbackUrl, options.responseMode)) as Record<string, string>;\n\n\t\tawait tokenExchange(params);\n\t}\n\n\tasync function refresh(): ReturnType<SDK<URLHandlerParams>['refresh']> {\n\t\tawait init();\n\n\t\tif (promises.refresh) {\n\t\t\treturn promises.refresh;\n\t\t}\n\n\t\tif (promises.revoke) {\n\t\t\ttry {\n\t\t\t\tawait promises.revoke;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.logout) {\n\t\t\ttry {\n\t\t\t\tawait promises.logout;\n\t\t\t} catch {}\n\t\t}\n\n\t\toptions.logging?.debug('Attempting to refresh session');\n\n\t\tif (typeof flowState.session?.refresh_token !== 'string') {\n\t\t\toptions.logging?.debug('Refresh called without refresh token');\n\t\t\treturn;\n\t\t}\n\n\t\tpromises.refresh = (async () => {\n\t\t\ttry {\n\t\t\t\tconst session = await refreshToken({ refreshToken: flowState.session!.refresh_token!, options, expectedSub: flowState.session?.claims?.sub });\n\t\t\t\tawait updateSession(session);\n\n\t\t\t\tdispatchEvent('tokenRefreshed', [\n\t\t\t\t\t{\n\t\t\t\t\t\tidToken: flowState.session?.id_token,\n\t\t\t\t\t\taccessToken: flowState.session?.access_token,\n\t\t\t\t\t\trefreshToken: flowState.session?.refresh_token,\n\t\t\t\t\t\tclaims: flowState.session?.claims,\n\t\t\t\t\t},\n\t\t\t\t]);\n\t\t\t\toptions.logging?.debug('Session refresh successful');\n\t\t\t} catch (error) {\n\t\t\t\tconst failedRefreshToken = flowState.session?.refresh_token;\n\n\t\t\t\t// NOTE: Transient Network/Server failures must not destroy a session that could still be refreshed later.\n\t\t\t\tif (!(error instanceof NetworkError) && !(error instanceof ServerError)) {\n\t\t\t\t\tawait cleanupSession();\n\t\t\t\t}\n\n\t\t\t\tdispatchEvent('tokenRefreshFailed', [{ refreshToken: failedRefreshToken }]);\n\t\t\t\toptions.logging?.error('Session refresh failed', error);\n\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tpromises.refresh = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.refresh;\n\t}\n\n\tasync function revoke(): ReturnType<SDK<URLHandlerParams>['revoke']> {\n\t\tawait init();\n\n\t\tif (promises.revoke) {\n\t\t\treturn promises.revoke;\n\t\t}\n\n\t\tif (promises.refresh) {\n\t\t\ttry {\n\t\t\t\tawait promises.refresh;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.logout) {\n\t\t\ttry {\n\t\t\t\tawait promises.logout;\n\t\t\t} catch {}\n\t\t}\n\n\t\tpromises.revoke = (async () => {\n\t\t\ttry {\n\t\t\t\tif (flowState.session?.refresh_token) {\n\t\t\t\t\toptions.logging?.debug('Attempting to revoke refresh token');\n\t\t\t\t} else if (flowState.session?.access_token) {\n\t\t\t\t\toptions.logging?.debug('Attempting to revoke access token');\n\t\t\t\t}\n\n\t\t\t\t// NOTE: Cleanup session before revocation\n\t\t\t\tconst currentSession = flowState.session;\n\t\t\t\tawait cleanupSession();\n\n\t\t\t\tif (!currentSession?.access_token && !currentSession?.refresh_token) {\n\t\t\t\t\toptions.logging?.debug('Revoke called without session');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst tokenTypeHint = currentSession.refresh_token ? 'refresh_token' : 'access_token';\n\t\t\t\tconst token = (tokenTypeHint === 'refresh_token' ? currentSession.refresh_token : currentSession.access_token)!;\n\n\t\t\t\ttry {\n\t\t\t\t\tawait revokeToken({ tokenTypeHint, token, options });\n\n\t\t\t\t\tif (tokenTypeHint === 'refresh_token') {\n\t\t\t\t\t\tdispatchEvent('tokenRevoked', [{ token: currentSession.refresh_token, tokenTypeHint: 'refresh_token' }]);\n\t\t\t\t\t\toptions.logging?.info('Refresh token successfully revoked');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdispatchEvent('tokenRevoked', [{ token: currentSession.access_token, tokenTypeHint: 'access_token' }]);\n\t\t\t\t\t\toptions.logging?.info('Access token successfully revoked');\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (tokenTypeHint === 'refresh_token') {\n\t\t\t\t\t\tdispatchEvent('tokenRevokeFailed', [{ token: currentSession.refresh_token, tokenTypeHint: 'refresh_token' }]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdispatchEvent('tokenRevokeFailed', [{ token: currentSession.access_token, tokenTypeHint: 'access_token' }]);\n\t\t\t\t\t}\n\n\t\t\t\t\toptions.logging?.error('Token revocation failed', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.revoke = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.revoke;\n\t}\n\n\tasync function logout(params?: Parameters<SDK<URLHandlerParams>['logout']>[0]): ReturnType<SDK<URLHandlerParams>['logout']> {\n\t\tawait init();\n\n\t\tif (promises.logout) {\n\t\t\treturn promises.logout;\n\t\t}\n\n\t\tif (promises.revoke) {\n\t\t\ttry {\n\t\t\t\tawait promises.revoke;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.refresh) {\n\t\t\ttry {\n\t\t\t\tawait promises.refresh;\n\t\t\t} catch {}\n\t\t}\n\n\t\tpromises.logout = (async () => {\n\t\t\ttry {\n\t\t\t\toptions.logging?.debug('Attempting to logout');\n\n\t\t\t\t// NOTE: Cleanup session before logout\n\t\t\t\tconst currentSession = flowState.session;\n\t\t\t\tawait cleanupSession();\n\n\t\t\t\tdispatchEvent('logoutInitiated', [{ idToken: currentSession?.id_token, claims: currentSession?.claims }]);\n\t\t\t\toptions.logging?.debug('Logout initiated');\n\n\t\t\t\tif (!currentSession?.id_token) {\n\t\t\t\t\toptions.logging?.debug('Logout called without id token');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tconst metadata = await getDiscoveryDocument(options);\n\t\t\t\t\tconst logoutUrl = buildEndSessionUrl({\n\t\t\t\t\t\turl: metadata.end_session_endpoint,\n\t\t\t\t\t\tidToken: currentSession.id_token,\n\t\t\t\t\t\tpostLogoutRedirectUri: params?.postLogoutRedirectUri,\n\t\t\t\t\t});\n\n\t\t\t\t\tawait options.urlHandler(logoutUrl, params);\n\t\t\t\t} catch (error) {\n\t\t\t\t\toptions.logging?.error('Unable to redirect to the end-session endpoint', error);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.logout = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.logout;\n\t}\n\n\treturn {\n\t\tdispatchEvent,\n\t\tsubscribeToEvent,\n\t\tsubscribeToAllEvents,\n\t\tgetSession,\n\t\tupdateSession,\n\t\tcleanupSession,\n\t\tcheckAuthentication,\n\t\tinit,\n\t\ttokenExchange,\n\t\thandleCallback,\n\t\trefresh,\n\t\trevoke,\n\t\tlogout,\n\t};\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"base.cjs","names":[],"sources":["../../src/flows/base.ts"],"sourcesContent":["import type { EventFunctions, ExtraRequestArgs, FlowState, SDK, SDKOptions, SessionData } from '../types/oidc';\nimport { buildEndSessionUrl, exchangeCode, getDiscoveryDocument, refreshToken, revokeToken, verifyIdToken } from '../utils/oidc';\nimport { loadSession, serializeSession, isSessionExpired } from '../utils/session';\nimport { ConfigurationError, NetworkError, ProtocolError, ServerError } from '../utils/errors';\n\n/**\n * Creates a base flow for the Strivacity SDK, providing common functionality for managing authentication sessions.\n *\n * @param flowState - The initial state of the flow, including session data and initialization status.\n * @param options - The SDK options, including issuer, clientId, redirectUri, scopes, and storage configuration.\n * @template URLHandlerParams - The type of additional request arguments for URL handling.\n * @returns An object implementing the SDK interface, with methods for initializing the flow, managing sessions, and handling authentication events.\n */\nexport function createBaseFlow<URLHandlerParams extends ExtraRequestArgs = ExtraRequestArgs>(flowState: FlowState, options: SDKOptions) {\n\tconst promises: Record<'init' | 'refresh' | 'revoke' | 'logout', Promise<void> | null> & { tokenExchange: Map<string, Promise<void>> } = {\n\t\tinit: null,\n\t\trefresh: null,\n\t\trevoke: null,\n\t\tlogout: null,\n\t\ttokenExchange: new Map(),\n\t};\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tconst eventCallbacks: Record<keyof EventFunctions, Set<(...args: Array<any>) => Promise<void> | void>> = {\n\t\taccessTokenExpired: new Set(),\n\t\tinit: new Set(),\n\t\tloggedIn: new Set(),\n\t\tsessionUpdated: new Set(),\n\t\tsessionCleared: new Set(),\n\t\tloginInitiated: new Set(),\n\t\tflowInitiated: new Set(),\n\t\tlogoutInitiated: new Set(),\n\t\tsessionLoaded: new Set(),\n\t\ttokenRefreshed: new Set(),\n\t\ttokenRefreshFailed: new Set(),\n\t\ttokenRevoked: new Set(),\n\t\ttokenRevokeFailed: new Set(),\n\t};\n\n\tfunction dispatchEvent<T extends keyof EventFunctions>(eventName: T, args: Parameters<EventFunctions[T]>): void {\n\t\tfor (const fn of eventCallbacks[eventName]) {\n\t\t\tvoid fn(...args);\n\t\t}\n\t}\n\n\tfunction subscribeToEvent<T extends keyof EventFunctions>(\n\t\teventName: T,\n\t\tcallbackFn: (...params: Parameters<EventFunctions[T]>) => Promise<void> | void,\n\t): ReturnType<SDK<URLHandlerParams>['subscribeToEvent']> {\n\t\teventCallbacks[eventName].add(callbackFn);\n\t\treturn { dispose: () => eventCallbacks[eventName].delete(callbackFn) };\n\t}\n\n\tfunction subscribeToAllEvents(callbackFn: (...params: Array<unknown>) => Promise<void> | void): ReturnType<SDK<URLHandlerParams>['subscribeToAllEvents']> {\n\t\tfor (const eventName in eventCallbacks) {\n\t\t\teventCallbacks[eventName as keyof EventFunctions].add(callbackFn);\n\t\t}\n\n\t\treturn {\n\t\t\tdispose: () => {\n\t\t\t\tfor (const eventName in eventCallbacks) {\n\t\t\t\t\teventCallbacks[eventName as keyof EventFunctions].delete(callbackFn);\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\tasync function getSession(): Promise<SessionData | null> {\n\t\tawait init();\n\n\t\treturn flowState.session;\n\t}\n\n\tasync function updateSession(newData: SessionData): ReturnType<SDK<URLHandlerParams>['updateSession']> {\n\t\tawait init();\n\n\t\t// NOTE: only unverified callers (e.g. direct API use) need validating here\n\t\tif (newData.id_token && !newData.claims) {\n\t\t\tnewData.claims = await verifyIdToken({ idToken: newData.id_token, options });\n\t\t}\n\n\t\tif (!options.serverSessionUri) {\n\t\t\tawait options.storage.set(options.storageTokenName, serializeSession(newData));\n\t\t}\n\n\t\tflowState.session = newData;\n\n\t\tdispatchEvent('sessionUpdated', [\n\t\t\t{\n\t\t\t\tidToken: flowState.session.id_token,\n\t\t\t\taccessToken: flowState.session.access_token,\n\t\t\t\trefreshToken: flowState.session.refresh_token,\n\t\t\t\tclaims: flowState.session.claims,\n\t\t\t},\n\t\t]);\n\t}\n\n\tasync function cleanupSession(): ReturnType<SDK<URLHandlerParams>['cleanupSession']> {\n\t\tawait init();\n\n\t\tif (!options.serverSessionUri) {\n\t\t\tawait options.storage.delete(options.storageTokenName);\n\t\t}\n\n\t\tflowState.session = null;\n\n\t\tdispatchEvent('sessionCleared', []);\n\t}\n\n\tasync function checkAuthentication(\n\t\tparams: { autoRefresh: boolean } = { autoRefresh: options.autoRefresh },\n\t): ReturnType<SDK<URLHandlerParams>['checkAuthentication']> {\n\t\tif (flowState.session?.access_token && !isSessionExpired(flowState.session, options.refreshSkew)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (params?.autoRefresh && flowState.session?.refresh_token) {\n\t\t\ttry {\n\t\t\t\tawait refresh();\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn !isSessionExpired(flowState.session);\n\t}\n\n\tasync function init(): ReturnType<SDK<URLHandlerParams>['init']> {\n\t\tif (flowState.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (promises.init) {\n\t\t\treturn promises.init;\n\t\t}\n\n\t\tpromises.init = (async () => {\n\t\t\ttry {\n\t\t\t\tif (!options.issuer) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: issuer');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (!options.clientId) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: clientId');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (!options.redirectUri) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: redirectUri');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (options.scopes && !Array.isArray(options.scopes)) {\n\t\t\t\t\tconst error = new ConfigurationError('Invalid option: scopes');\n\t\t\t\t\toptions.logging?.error('Invalid option provided', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\tif (!options.serverSessionUri) {\n\t\t\t\t\tflowState.session = loadSession(await options.storage.get(options.storageTokenName));\n\t\t\t\t}\n\n\t\t\t\tflowState.initialized = true;\n\n\t\t\t\tdispatchEvent('init', []);\n\t\t\t\toptions.logging?.debug('SDK initialized');\n\n\t\t\t\tif (!flowState.session && !options.serverSessionUri) {\n\t\t\t\t\toptions.logging?.debug('No session found in storage');\n\t\t\t\t}\n\n\t\t\t\tif (flowState.session?.access_token) {\n\t\t\t\t\tdispatchEvent('sessionLoaded', [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tidToken: flowState.session.id_token,\n\t\t\t\t\t\t\taccessToken: flowState.session.access_token,\n\t\t\t\t\t\t\trefreshToken: flowState.session.refresh_token,\n\t\t\t\t\t\t\tclaims: flowState.session.claims,\n\t\t\t\t\t\t},\n\t\t\t\t\t]);\n\t\t\t\t\toptions.logging?.debug('Session loaded from storage');\n\t\t\t\t}\n\n\t\t\t\tif (flowState.session?.access_token && isSessionExpired(flowState.session)) {\n\t\t\t\t\tdispatchEvent('accessTokenExpired', [{ accessToken: flowState.session.access_token, refreshToken: flowState.session.refresh_token }]);\n\t\t\t\t\toptions.logging?.debug('Access token has expired');\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.init = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.init;\n\t}\n\n\tasync function tokenExchange(params: Parameters<SDK<URLHandlerParams>['tokenExchange']>[0] = {}): ReturnType<SDK<URLHandlerParams>['tokenExchange']> {\n\t\tawait init();\n\n\t\tconst exchangeKey = params.state ?? '';\n\t\tconst inFlight = promises.tokenExchange.get(exchangeKey);\n\n\t\tif (inFlight) {\n\t\t\treturn inFlight;\n\t\t}\n\n\t\tconst exchangePromise = (async () => {\n\t\t\toptions.logging?.debug('Exchanging authorization code for tokens');\n\n\t\t\ttry {\n\t\t\t\tconst session = await exchangeCode({ params, options });\n\n\t\t\t\tif (!session.access_token) {\n\t\t\t\t\tthrow new ProtocolError('Missing access_token');\n\t\t\t\t}\n\n\t\t\t\tawait updateSession(session);\n\n\t\t\t\toptions.logging?.debug('Token exchange successful');\n\n\t\t\t\tdispatchEvent('loggedIn', [\n\t\t\t\t\t{ idToken: session.id_token, accessToken: session.access_token, refreshToken: session.refresh_token, claims: session.claims },\n\t\t\t\t]);\n\n\t\t\t\tif (options.logging) {\n\t\t\t\t\toptions.logging.xEventId = undefined;\n\t\t\t\t\toptions.logging.info('Login successful');\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\toptions.logging?.error('Token exchange failed', error);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tpromises.tokenExchange.delete(exchangeKey);\n\t\t\t}\n\t\t})();\n\n\t\tpromises.tokenExchange.set(exchangeKey, exchangePromise);\n\n\t\treturn exchangePromise;\n\t}\n\n\tasync function handleCallback(url?: string | URL): ReturnType<SDK<URLHandlerParams>['handleCallback']> {\n\t\tawait init();\n\n\t\tconst callbackUrl = url ?? globalThis.window?.location.href;\n\t\tconst params = (await options.callbackHandler(callbackUrl, options.responseMode)) as Record<string, string>;\n\n\t\tawait tokenExchange(params);\n\t}\n\n\tasync function refresh(): ReturnType<SDK<URLHandlerParams>['refresh']> {\n\t\tawait init();\n\n\t\tif (promises.refresh) {\n\t\t\treturn promises.refresh;\n\t\t}\n\n\t\tif (promises.revoke) {\n\t\t\ttry {\n\t\t\t\tawait promises.revoke;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.logout) {\n\t\t\ttry {\n\t\t\t\tawait promises.logout;\n\t\t\t} catch {}\n\t\t}\n\n\t\toptions.logging?.debug('Attempting to refresh session');\n\n\t\tif (typeof flowState.session?.refresh_token !== 'string') {\n\t\t\toptions.logging?.debug('Refresh called without refresh token');\n\t\t\treturn;\n\t\t}\n\n\t\tpromises.refresh = (async () => {\n\t\t\ttry {\n\t\t\t\tconst session = await refreshToken({ refreshToken: flowState.session!.refresh_token!, options, expectedSub: flowState.session?.claims?.sub });\n\t\t\t\tawait updateSession(session);\n\n\t\t\t\tdispatchEvent('tokenRefreshed', [\n\t\t\t\t\t{\n\t\t\t\t\t\tidToken: flowState.session?.id_token,\n\t\t\t\t\t\taccessToken: flowState.session?.access_token,\n\t\t\t\t\t\trefreshToken: flowState.session?.refresh_token,\n\t\t\t\t\t\tclaims: flowState.session?.claims,\n\t\t\t\t\t},\n\t\t\t\t]);\n\t\t\t\toptions.logging?.debug('Session refresh successful');\n\t\t\t} catch (error) {\n\t\t\t\tconst failedRefreshToken = flowState.session?.refresh_token;\n\n\t\t\t\t// NOTE: Transient Network/Server failures must not destroy a session that could still be refreshed later.\n\t\t\t\tif (!(error instanceof NetworkError) && !(error instanceof ServerError)) {\n\t\t\t\t\tawait cleanupSession();\n\t\t\t\t}\n\n\t\t\t\tdispatchEvent('tokenRefreshFailed', [{ refreshToken: failedRefreshToken }]);\n\t\t\t\toptions.logging?.error('Session refresh failed', error);\n\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tpromises.refresh = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.refresh;\n\t}\n\n\tasync function revoke(): ReturnType<SDK<URLHandlerParams>['revoke']> {\n\t\tawait init();\n\n\t\tif (promises.revoke) {\n\t\t\treturn promises.revoke;\n\t\t}\n\n\t\tif (promises.refresh) {\n\t\t\ttry {\n\t\t\t\tawait promises.refresh;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.logout) {\n\t\t\ttry {\n\t\t\t\tawait promises.logout;\n\t\t\t} catch {}\n\t\t}\n\n\t\tpromises.revoke = (async () => {\n\t\t\ttry {\n\t\t\t\tif (flowState.session?.refresh_token) {\n\t\t\t\t\toptions.logging?.debug('Attempting to revoke refresh token');\n\t\t\t\t} else if (flowState.session?.access_token) {\n\t\t\t\t\toptions.logging?.debug('Attempting to revoke access token');\n\t\t\t\t}\n\n\t\t\t\t// NOTE: Cleanup session before revocation\n\t\t\t\tconst currentSession = flowState.session;\n\t\t\t\tawait cleanupSession();\n\n\t\t\t\tif (!currentSession?.access_token && !currentSession?.refresh_token) {\n\t\t\t\t\toptions.logging?.debug('Revoke called without session');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst tokenTypeHint = currentSession.refresh_token ? 'refresh_token' : 'access_token';\n\t\t\t\tconst token = (tokenTypeHint === 'refresh_token' ? currentSession.refresh_token : currentSession.access_token)!;\n\n\t\t\t\ttry {\n\t\t\t\t\tawait revokeToken({ tokenTypeHint, token, options });\n\n\t\t\t\t\tif (tokenTypeHint === 'refresh_token') {\n\t\t\t\t\t\tdispatchEvent('tokenRevoked', [{ token: currentSession.refresh_token, tokenTypeHint: 'refresh_token' }]);\n\t\t\t\t\t\toptions.logging?.info('Refresh token successfully revoked');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdispatchEvent('tokenRevoked', [{ token: currentSession.access_token, tokenTypeHint: 'access_token' }]);\n\t\t\t\t\t\toptions.logging?.info('Access token successfully revoked');\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (tokenTypeHint === 'refresh_token') {\n\t\t\t\t\t\tdispatchEvent('tokenRevokeFailed', [{ token: currentSession.refresh_token, tokenTypeHint: 'refresh_token' }]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdispatchEvent('tokenRevokeFailed', [{ token: currentSession.access_token, tokenTypeHint: 'access_token' }]);\n\t\t\t\t\t}\n\n\t\t\t\t\toptions.logging?.error('Token revocation failed', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.revoke = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.revoke;\n\t}\n\n\tasync function logout(params?: Parameters<SDK<URLHandlerParams>['logout']>[0]): ReturnType<SDK<URLHandlerParams>['logout']> {\n\t\tawait init();\n\n\t\tif (promises.logout) {\n\t\t\treturn promises.logout;\n\t\t}\n\n\t\tif (promises.revoke) {\n\t\t\ttry {\n\t\t\t\tawait promises.revoke;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.refresh) {\n\t\t\ttry {\n\t\t\t\tawait promises.refresh;\n\t\t\t} catch {}\n\t\t}\n\n\t\tpromises.logout = (async () => {\n\t\t\ttry {\n\t\t\t\toptions.logging?.debug('Attempting to logout');\n\n\t\t\t\t// NOTE: Cleanup session before logout\n\t\t\t\tconst currentSession = flowState.session;\n\t\t\t\tawait cleanupSession();\n\n\t\t\t\tdispatchEvent('logoutInitiated', [{ idToken: currentSession?.id_token, claims: currentSession?.claims }]);\n\t\t\t\toptions.logging?.debug('Logout initiated');\n\n\t\t\t\tif (!currentSession?.id_token) {\n\t\t\t\t\toptions.logging?.debug('Logout called without id token');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tconst metadata = await getDiscoveryDocument(options);\n\t\t\t\t\tconst logoutUrl = buildEndSessionUrl({\n\t\t\t\t\t\turl: metadata.end_session_endpoint,\n\t\t\t\t\t\tidToken: currentSession.id_token,\n\t\t\t\t\t\tpostLogoutRedirectUri: params?.postLogoutRedirectUri,\n\t\t\t\t\t});\n\n\t\t\t\t\tawait options.urlHandler(logoutUrl, params);\n\t\t\t\t} catch (error) {\n\t\t\t\t\toptions.logging?.error('Unable to redirect to the end-session endpoint', error);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.logout = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.logout;\n\t}\n\n\treturn {\n\t\tdispatchEvent,\n\t\tsubscribeToEvent,\n\t\tsubscribeToAllEvents,\n\t\tgetSession,\n\t\tupdateSession,\n\t\tcleanupSession,\n\t\tcheckAuthentication,\n\t\tinit,\n\t\ttokenExchange,\n\t\thandleCallback,\n\t\trefresh,\n\t\trevoke,\n\t\tlogout,\n\t};\n}\n"],"mappings":"4KAaA,SAAgB,EAA6E,EAAsB,EAAqB,CACvI,IAAM,EAAmI,CACxI,KAAM,KACN,QAAS,KACT,OAAQ,KACR,OAAQ,KACR,cAAe,IAAI,GACpB,EAEM,EAAmG,CACxG,mBAAoB,IAAI,IACxB,KAAM,IAAI,IACV,SAAU,IAAI,IACd,eAAgB,IAAI,IACpB,eAAgB,IAAI,IACpB,eAAgB,IAAI,IACpB,cAAe,IAAI,IACnB,gBAAiB,IAAI,IACrB,cAAe,IAAI,IACnB,eAAgB,IAAI,IACpB,mBAAoB,IAAI,IACxB,aAAc,IAAI,IAClB,kBAAmB,IAAI,GACxB,EAEA,SAAS,EAA8C,EAAc,EAA2C,CAC/G,IAAK,IAAM,KAAM,EAAe,GAC/B,EAAQ,GAAG,CAAI,CAEjB,CAEA,SAAS,EACR,EACA,EACwD,CAExD,OADA,EAAe,EAAU,CAAC,IAAI,CAAU,EACjC,CAAE,YAAe,EAAe,EAAU,CAAC,OAAO,CAAU,CAAE,CACtE,CAEA,SAAS,EAAqB,EAA4H,CACzJ,IAAK,IAAM,KAAa,EACvB,EAAe,EAAkC,CAAC,IAAI,CAAU,EAGjE,MAAO,CACN,YAAe,CACd,IAAK,IAAM,KAAa,EACvB,EAAe,EAAkC,CAAC,OAAO,CAAU,CAErE,CACD,CACD,CAEA,eAAe,GAA0C,CAGxD,OAFA,MAAM,EAAK,EAEJ,EAAU,OAClB,CAEA,eAAe,EAAc,EAA0E,CACtG,MAAM,EAAK,EAGP,EAAQ,UAAY,CAAC,EAAQ,SAChC,EAAQ,OAAS,MAAM,EAAA,EAAc,CAAE,QAAS,EAAQ,SAAU,SAAQ,CAAC,GAGvE,EAAQ,kBACZ,MAAM,EAAQ,QAAQ,IAAI,EAAQ,iBAAkB,EAAA,iBAAiB,CAAO,CAAC,EAG9E,EAAU,QAAU,EAEpB,EAAc,iBAAkB,CAC/B,CACC,QAAS,EAAU,QAAQ,SAC3B,YAAa,EAAU,QAAQ,aAC/B,aAAc,EAAU,QAAQ,cAChC,OAAQ,EAAU,QAAQ,MAC3B,CACD,CAAC,CACF,CAEA,eAAe,GAAsE,CACpF,MAAM,EAAK,EAEN,EAAQ,kBACZ,MAAM,EAAQ,QAAQ,OAAO,EAAQ,gBAAgB,EAGtD,EAAU,QAAU,KAEpB,EAAc,iBAAkB,CAAC,CAAC,CACnC,CAEA,eAAe,EACd,EAAmC,CAAE,YAAa,EAAQ,WAAY,EACX,CAC3D,GAAI,EAAU,SAAS,cAAgB,CAAC,EAAA,iBAAiB,EAAU,QAAS,EAAQ,WAAW,EAC9F,MAAO,GAGR,GAAI,GAAQ,aAAe,EAAU,SAAS,cAC7C,GAAI,CACH,MAAM,EAAQ,CACf,MAAQ,CACP,MAAO,EACR,CAGD,MAAO,CAAC,EAAA,iBAAiB,EAAU,OAAO,CAC3C,CAEA,eAAe,GAAkD,CAC5D,MAAU,YAiEd,MA7DI,CAIJ,EAAS,QAAQ,SAAY,CAC5B,GAAI,CACH,GAAI,CAAC,EAAQ,OAAQ,CACpB,IAAM,EAAQ,IAAI,EAAA,mBAAmB,wBAAwB,EAE7D,MADA,EAAQ,SAAS,MAAM,0BAA2B,CAAK,EACjD,CACP,CACA,GAAI,CAAC,EAAQ,SAAU,CACtB,IAAM,EAAQ,IAAI,EAAA,mBAAmB,0BAA0B,EAE/D,MADA,EAAQ,SAAS,MAAM,0BAA2B,CAAK,EACjD,CACP,CACA,GAAI,CAAC,EAAQ,YAAa,CACzB,IAAM,EAAQ,IAAI,EAAA,mBAAmB,6BAA6B,EAElE,MADA,EAAQ,SAAS,MAAM,0BAA2B,CAAK,EACjD,CACP,CACA,GAAI,EAAQ,QAAU,CAAC,MAAM,QAAQ,EAAQ,MAAM,EAAG,CACrD,IAAM,EAAQ,IAAI,EAAA,mBAAmB,wBAAwB,EAE7D,MADA,EAAQ,SAAS,MAAM,0BAA2B,CAAK,EACjD,CACP,CAEK,EAAQ,mBACZ,EAAU,QAAU,EAAA,YAAY,MAAM,EAAQ,QAAQ,IAAI,EAAQ,gBAAgB,CAAC,GAGpF,EAAU,YAAc,GAExB,EAAc,OAAQ,CAAC,CAAC,EACxB,EAAQ,SAAS,MAAM,iBAAiB,EAEpC,CAAC,EAAU,SAAW,CAAC,EAAQ,kBAClC,EAAQ,SAAS,MAAM,6BAA6B,EAGjD,EAAU,SAAS,eACtB,EAAc,gBAAiB,CAC9B,CACC,QAAS,EAAU,QAAQ,SAC3B,YAAa,EAAU,QAAQ,aAC/B,aAAc,EAAU,QAAQ,cAChC,OAAQ,EAAU,QAAQ,MAC3B,CACD,CAAC,EACD,EAAQ,SAAS,MAAM,6BAA6B,GAGjD,EAAU,SAAS,cAAgB,EAAA,iBAAiB,EAAU,OAAO,IACxE,EAAc,qBAAsB,CAAC,CAAE,YAAa,EAAU,QAAQ,aAAc,aAAc,EAAU,QAAQ,aAAc,CAAC,CAAC,EACpI,EAAQ,SAAS,MAAM,0BAA0B,EAEnD,QAAU,CACT,EAAS,KAAO,IACjB,CACD,EAAA,CAAG,EA1DK,EAAS,IA6DlB,CAEA,eAAe,EAAc,EAAgE,CAAC,EAAuD,CACpJ,MAAM,EAAK,EAEX,IAAM,EAAc,EAAO,OAAS,GAC9B,EAAW,EAAS,cAAc,IAAI,CAAW,EAEvD,GAAI,EACH,OAAO,EAGR,IAAM,GAAmB,SAAY,CACpC,EAAQ,SAAS,MAAM,0CAA0C,EAEjE,GAAI,CACH,IAAM,EAAU,MAAM,EAAA,EAAa,CAAE,SAAQ,SAAQ,CAAC,EAEtD,GAAI,CAAC,EAAQ,aACZ,MAAM,IAAI,EAAA,cAAc,sBAAsB,EAG/C,MAAM,EAAc,CAAO,EAE3B,EAAQ,SAAS,MAAM,2BAA2B,EAElD,EAAc,WAAY,CACzB,CAAE,QAAS,EAAQ,SAAU,YAAa,EAAQ,aAAc,aAAc,EAAQ,cAAe,OAAQ,EAAQ,MAAO,CAC7H,CAAC,EAEG,EAAQ,UACX,EAAQ,QAAQ,SAAW,IAAA,GAC3B,EAAQ,QAAQ,KAAK,kBAAkB,EAEzC,OAAS,EAAO,CAEf,MADA,EAAQ,SAAS,MAAM,wBAAyB,CAAK,EAC/C,CACP,QAAU,CACT,EAAS,cAAc,OAAO,CAAW,CAC1C,CACD,EAAA,CAAG,EAIH,OAFA,EAAS,cAAc,IAAI,EAAa,CAAe,EAEhD,CACR,CAEA,eAAe,EAAe,EAAyE,CACtG,MAAM,EAAK,EAEX,IAAM,EAAc,GAAO,WAAW,QAAQ,SAAS,KAGvD,MAAM,EAAc,MAFE,EAAQ,gBAAgB,EAAa,EAAQ,YAAY,CAErD,CAC3B,CAEA,eAAe,GAAwD,CAGtE,GAFA,MAAM,EAAK,EAEP,EAAS,QACZ,OAAO,EAAS,QAGjB,GAAI,EAAS,OACZ,GAAI,CACH,MAAM,EAAS,MAChB,MAAQ,CAAC,CAGV,GAAI,EAAS,OACZ,GAAI,CACH,MAAM,EAAS,MAChB,MAAQ,CAAC,CAKV,GAFA,EAAQ,SAAS,MAAM,+BAA+B,EAElD,OAAO,EAAU,SAAS,eAAkB,SAAU,CACzD,EAAQ,SAAS,MAAM,sCAAsC,EAC7D,MACD,CAiCA,MA/BA,GAAS,SAAW,SAAY,CAC/B,GAAI,CAEH,MAAM,EAAc,MADE,EAAA,EAAa,CAAE,aAAc,EAAU,QAAS,cAAgB,UAAS,YAAa,EAAU,SAAS,QAAQ,GAAI,CAAC,CACjH,EAE3B,EAAc,iBAAkB,CAC/B,CACC,QAAS,EAAU,SAAS,SAC5B,YAAa,EAAU,SAAS,aAChC,aAAc,EAAU,SAAS,cACjC,OAAQ,EAAU,SAAS,MAC5B,CACD,CAAC,EACD,EAAQ,SAAS,MAAM,4BAA4B,CACpD,OAAS,EAAO,CACf,IAAM,EAAqB,EAAU,SAAS,cAU9C,KAPI,EAAE,aAAiB,EAAA,eAAiB,EAAE,aAAiB,EAAA,cAC1D,MAAM,EAAe,EAGtB,EAAc,qBAAsB,CAAC,CAAE,aAAc,CAAmB,CAAC,CAAC,EAC1E,EAAQ,SAAS,MAAM,yBAA0B,CAAK,EAEhD,CACP,QAAU,CACT,EAAS,QAAU,IACpB,CACD,EAAA,CAAG,EAEI,EAAS,OACjB,CAEA,eAAe,GAAsD,CAGpE,GAFA,MAAM,EAAK,EAEP,EAAS,OACZ,OAAO,EAAS,OAGjB,GAAI,EAAS,QACZ,GAAI,CACH,MAAM,EAAS,OAChB,MAAQ,CAAC,CAGV,GAAI,EAAS,OACZ,GAAI,CACH,MAAM,EAAS,MAChB,MAAQ,CAAC,CAgDV,MA7CA,GAAS,QAAU,SAAY,CAC9B,GAAI,CACC,EAAU,SAAS,cACtB,EAAQ,SAAS,MAAM,oCAAoC,EACjD,EAAU,SAAS,cAC7B,EAAQ,SAAS,MAAM,mCAAmC,EAI3D,IAAM,EAAiB,EAAU,QAGjC,GAFA,MAAM,EAAe,EAEjB,CAAC,GAAgB,cAAgB,CAAC,GAAgB,cAAe,CACpE,EAAQ,SAAS,MAAM,+BAA+B,EACtD,MACD,CAEA,IAAM,EAAgB,EAAe,cAAgB,gBAAkB,eACjE,EAAS,IAAkB,gBAAkB,EAAe,cAAgB,EAAe,aAEjG,GAAI,CACH,MAAM,EAAA,EAAY,CAAE,gBAAe,QAAO,SAAQ,CAAC,EAE/C,IAAkB,iBACrB,EAAc,eAAgB,CAAC,CAAE,MAAO,EAAe,cAAe,cAAe,eAAgB,CAAC,CAAC,EACvG,EAAQ,SAAS,KAAK,oCAAoC,IAE1D,EAAc,eAAgB,CAAC,CAAE,MAAO,EAAe,aAAc,cAAe,cAAe,CAAC,CAAC,EACrG,EAAQ,SAAS,KAAK,mCAAmC,EAE3D,OAAS,EAAO,CAQf,MAPI,IAAkB,gBACrB,EAAc,oBAAqB,CAAC,CAAE,MAAO,EAAe,cAAe,cAAe,eAAgB,CAAC,CAAC,EAE5G,EAAc,oBAAqB,CAAC,CAAE,MAAO,EAAe,aAAc,cAAe,cAAe,CAAC,CAAC,EAG3G,EAAQ,SAAS,MAAM,0BAA2B,CAAK,EACjD,CACP,CACD,QAAU,CACT,EAAS,OAAS,IACnB,CACD,EAAA,CAAG,EAEI,EAAS,MACjB,CAEA,eAAe,EAAO,EAAsG,CAG3H,GAFA,MAAM,EAAK,EAEP,EAAS,OACZ,OAAO,EAAS,OAGjB,GAAI,EAAS,OACZ,GAAI,CACH,MAAM,EAAS,MAChB,MAAQ,CAAC,CAGV,GAAI,EAAS,QACZ,GAAI,CACH,MAAM,EAAS,OAChB,MAAQ,CAAC,CAoCV,MAjCA,GAAS,QAAU,SAAY,CAC9B,GAAI,CACH,EAAQ,SAAS,MAAM,sBAAsB,EAG7C,IAAM,EAAiB,EAAU,QAMjC,GALA,MAAM,EAAe,EAErB,EAAc,kBAAmB,CAAC,CAAE,QAAS,GAAgB,SAAU,OAAQ,GAAgB,MAAO,CAAC,CAAC,EACxG,EAAQ,SAAS,MAAM,kBAAkB,EAErC,CAAC,GAAgB,SAAU,CAC9B,EAAQ,SAAS,MAAM,gCAAgC,EACvD,MACD,CAEA,GAAI,CACH,IAAM,EAAW,MAAM,EAAA,EAAqB,CAAO,EAC7C,EAAY,EAAA,EAAmB,CACpC,IAAK,EAAS,qBACd,QAAS,EAAe,SACxB,sBAAuB,GAAQ,qBAChC,CAAC,EAED,MAAM,EAAQ,WAAW,EAAW,CAAM,CAC3C,OAAS,EAAO,CACf,EAAQ,SAAS,MAAM,iDAAkD,CAAK,CAC/E,CACD,QAAU,CACT,EAAS,OAAS,IACnB,CACD,EAAA,CAAG,EAEI,EAAS,MACjB,CAEA,MAAO,CACN,gBACA,mBACA,uBACA,aACA,gBACA,iBACA,sBACA,OACA,gBACA,iBACA,UACA,SACA,QACD,CACD"}
|
package/dist/flows/base.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ConfigurationError as e,NetworkError as t,ProtocolError as n,ServerError as r}from"../utils/errors.mjs";import{isSessionExpired as i,loadSession as a,serializeSession as o}from"../utils/session.mjs";import{a as s,g as c,h as l,n as u,p as d,v as f}from"../assets/oidc.mjs";function p(p,m){let h={init:null,refresh:null,revoke:null,logout:null,tokenExchange:new Map},g={accessTokenExpired:new Set,init:new Set,loggedIn:new Set,sessionUpdated:new Set,sessionCleared:new Set,loginInitiated:new Set,flowInitiated:new Set,logoutInitiated:new Set,sessionLoaded:new Set,tokenRefreshed:new Set,tokenRefreshFailed:new Set,tokenRevoked:new Set,tokenRevokeFailed:new Set};function _(e,t){for(let n of g[e])n(...t)}function v(e,t){return g[e].add(t),{dispose:()=>g[e].delete(t)}}function y(e){for(let t in g)g[t].add(e);return{dispose:()=>{for(let t in g)g[t].delete(e)}}}async function b(){return await w(),p.session}async function x(e){await w(),e.id_token&&!e.claims&&(e.claims=await f({idToken:e.id_token,options:m})),m.serverSessionUri||await m.storage.set(m.storageTokenName,o(e)),p.session=e,_(`sessionUpdated`,[{idToken:p.session.id_token,accessToken:p.session.access_token,refreshToken:p.session.refresh_token,claims:p.session.claims}])}async function S(){await w(),m.serverSessionUri||await m.storage.delete(m.storageTokenName),p.session=null,_(`sessionCleared`,[])}async function C(e={autoRefresh:m.autoRefresh}){if(p.session?.access_token&&!i(p.session))return!0;if(e?.autoRefresh&&p.session?.refresh_token)try{await D()}catch{return!1}return!i(p.session)}async function w(){if(!p.initialized)return h.init||=(async()=>{try{if(!m.issuer){let t=new e(`Missing option: issuer`);throw m.logging?.error(`Required option missing`,t),t}if(!m.clientId){let t=new e(`Missing option: clientId`);throw m.logging?.error(`Required option missing`,t),t}if(!m.redirectUri){let t=new e(`Missing option: redirectUri`);throw m.logging?.error(`Required option missing`,t),t}if(m.scopes&&!Array.isArray(m.scopes)){let t=new e(`Invalid option: scopes`);throw m.logging?.error(`Invalid option provided`,t),t}m.serverSessionUri||(p.session=a(await m.storage.get(m.storageTokenName))),p.initialized=!0,_(`init`,[]),m.logging?.debug(`SDK initialized`),!p.session&&!m.serverSessionUri&&m.logging?.debug(`No session found in storage`),p.session?.access_token&&(_(`sessionLoaded`,[{idToken:p.session.id_token,accessToken:p.session.access_token,refreshToken:p.session.refresh_token,claims:p.session.claims}]),m.logging?.debug(`Session loaded from storage`)),p.session?.access_token&&i(p.session)&&(_(`accessTokenExpired`,[{accessToken:p.session.access_token,refreshToken:p.session.refresh_token}]),m.logging?.debug(`Access token has expired`))}finally{h.init=null}})(),h.init}async function T(e={}){await w();let t=e.state??``,r=h.tokenExchange.get(t);if(r)return r;let i=(async()=>{m.logging?.debug(`Exchanging authorization code for tokens`);try{let t=await s({params:e,options:m});if(!t.access_token)throw new n(`Missing access_token`);await x(t),m.logging?.debug(`Token exchange successful`),_(`loggedIn`,[{idToken:t.id_token,accessToken:t.access_token,refreshToken:t.refresh_token,claims:t.claims}]),m.logging&&(m.logging.xEventId=void 0,m.logging.info(`Login successful`))}catch(e){throw m.logging?.error(`Token exchange failed`,e),e}finally{h.tokenExchange.delete(t)}})();return h.tokenExchange.set(t,i),i}async function E(e){await w();let t=e??globalThis.window?.location.href;await T(await m.callbackHandler(t,m.responseMode))}async function D(){if(await w(),h.refresh)return h.refresh;if(h.revoke)try{await h.revoke}catch{}if(h.logout)try{await h.logout}catch{}if(m.logging?.debug(`Attempting to refresh session`),typeof p.session?.refresh_token!=`string`){m.logging?.debug(`Refresh called without refresh token`);return}return h.refresh=(async()=>{try{await x(await l({refreshToken:p.session.refresh_token,options:m,expectedSub:p.session?.claims?.sub})),_(`tokenRefreshed`,[{idToken:p.session?.id_token,accessToken:p.session?.access_token,refreshToken:p.session?.refresh_token,claims:p.session?.claims}]),m.logging?.debug(`Session refresh successful`)}catch(e){let n=p.session?.refresh_token;throw!(e instanceof t)&&!(e instanceof r)&&await S(),_(`tokenRefreshFailed`,[{refreshToken:n}]),m.logging?.error(`Session refresh failed`,e),e}finally{h.refresh=null}})(),h.refresh}async function O(){if(await w(),h.revoke)return h.revoke;if(h.refresh)try{await h.refresh}catch{}if(h.logout)try{await h.logout}catch{}return h.revoke=(async()=>{try{p.session?.refresh_token?m.logging?.debug(`Attempting to revoke refresh token`):p.session?.access_token&&m.logging?.debug(`Attempting to revoke access token`);let e=p.session;if(await S(),!e?.access_token&&!e?.refresh_token){m.logging?.debug(`Revoke called without session`);return}let t=e.refresh_token?`refresh_token`:`access_token`,n=t===`refresh_token`?e.refresh_token:e.access_token;try{await c({tokenTypeHint:t,token:n,options:m}),t===`refresh_token`?(_(`tokenRevoked`,[{token:e.refresh_token,tokenTypeHint:`refresh_token`}]),m.logging?.info(`Refresh token successfully revoked`)):(_(`tokenRevoked`,[{token:e.access_token,tokenTypeHint:`access_token`}]),m.logging?.info(`Access token successfully revoked`))}catch(n){throw t===`refresh_token`?_(`tokenRevokeFailed`,[{token:e.refresh_token,tokenTypeHint:`refresh_token`}]):_(`tokenRevokeFailed`,[{token:e.access_token,tokenTypeHint:`access_token`}]),m.logging?.error(`Token revocation failed`,n),n}}finally{h.revoke=null}})(),h.revoke}async function k(e){if(await w(),h.logout)return h.logout;if(h.revoke)try{await h.revoke}catch{}if(h.refresh)try{await h.refresh}catch{}return h.logout=(async()=>{try{m.logging?.debug(`Attempting to logout`);let t=p.session;if(await S(),_(`logoutInitiated`,[{idToken:t?.id_token,claims:t?.claims}]),m.logging?.debug(`Logout initiated`),!t?.id_token){m.logging?.debug(`Logout called without id token`);return}try{let n=await d(m),r=u({url:n.end_session_endpoint,idToken:t.id_token,postLogoutRedirectUri:e?.postLogoutRedirectUri});await m.urlHandler(r,e)}catch(e){m.logging?.error(`Unable to redirect to the end-session endpoint`,e)}}finally{h.logout=null}})(),h.logout}return{dispatchEvent:_,subscribeToEvent:v,subscribeToAllEvents:y,getSession:b,updateSession:x,cleanupSession:S,checkAuthentication:C,init:w,tokenExchange:T,handleCallback:E,refresh:D,revoke:O,logout:k}}export{p as createBaseFlow};
|
|
1
|
+
import{ConfigurationError as e,NetworkError as t,ProtocolError as n,ServerError as r}from"../utils/errors.mjs";import{isSessionExpired as i,loadSession as a,serializeSession as o}from"../utils/session.mjs";import{a as s,g as c,h as l,n as u,p as d,v as f}from"../assets/oidc.mjs";function p(p,m){let h={init:null,refresh:null,revoke:null,logout:null,tokenExchange:new Map},g={accessTokenExpired:new Set,init:new Set,loggedIn:new Set,sessionUpdated:new Set,sessionCleared:new Set,loginInitiated:new Set,flowInitiated:new Set,logoutInitiated:new Set,sessionLoaded:new Set,tokenRefreshed:new Set,tokenRefreshFailed:new Set,tokenRevoked:new Set,tokenRevokeFailed:new Set};function _(e,t){for(let n of g[e])n(...t)}function v(e,t){return g[e].add(t),{dispose:()=>g[e].delete(t)}}function y(e){for(let t in g)g[t].add(e);return{dispose:()=>{for(let t in g)g[t].delete(e)}}}async function b(){return await w(),p.session}async function x(e){await w(),e.id_token&&!e.claims&&(e.claims=await f({idToken:e.id_token,options:m})),m.serverSessionUri||await m.storage.set(m.storageTokenName,o(e)),p.session=e,_(`sessionUpdated`,[{idToken:p.session.id_token,accessToken:p.session.access_token,refreshToken:p.session.refresh_token,claims:p.session.claims}])}async function S(){await w(),m.serverSessionUri||await m.storage.delete(m.storageTokenName),p.session=null,_(`sessionCleared`,[])}async function C(e={autoRefresh:m.autoRefresh}){if(p.session?.access_token&&!i(p.session,m.refreshSkew))return!0;if(e?.autoRefresh&&p.session?.refresh_token)try{await D()}catch{return!1}return!i(p.session)}async function w(){if(!p.initialized)return h.init||=(async()=>{try{if(!m.issuer){let t=new e(`Missing option: issuer`);throw m.logging?.error(`Required option missing`,t),t}if(!m.clientId){let t=new e(`Missing option: clientId`);throw m.logging?.error(`Required option missing`,t),t}if(!m.redirectUri){let t=new e(`Missing option: redirectUri`);throw m.logging?.error(`Required option missing`,t),t}if(m.scopes&&!Array.isArray(m.scopes)){let t=new e(`Invalid option: scopes`);throw m.logging?.error(`Invalid option provided`,t),t}m.serverSessionUri||(p.session=a(await m.storage.get(m.storageTokenName))),p.initialized=!0,_(`init`,[]),m.logging?.debug(`SDK initialized`),!p.session&&!m.serverSessionUri&&m.logging?.debug(`No session found in storage`),p.session?.access_token&&(_(`sessionLoaded`,[{idToken:p.session.id_token,accessToken:p.session.access_token,refreshToken:p.session.refresh_token,claims:p.session.claims}]),m.logging?.debug(`Session loaded from storage`)),p.session?.access_token&&i(p.session)&&(_(`accessTokenExpired`,[{accessToken:p.session.access_token,refreshToken:p.session.refresh_token}]),m.logging?.debug(`Access token has expired`))}finally{h.init=null}})(),h.init}async function T(e={}){await w();let t=e.state??``,r=h.tokenExchange.get(t);if(r)return r;let i=(async()=>{m.logging?.debug(`Exchanging authorization code for tokens`);try{let t=await s({params:e,options:m});if(!t.access_token)throw new n(`Missing access_token`);await x(t),m.logging?.debug(`Token exchange successful`),_(`loggedIn`,[{idToken:t.id_token,accessToken:t.access_token,refreshToken:t.refresh_token,claims:t.claims}]),m.logging&&(m.logging.xEventId=void 0,m.logging.info(`Login successful`))}catch(e){throw m.logging?.error(`Token exchange failed`,e),e}finally{h.tokenExchange.delete(t)}})();return h.tokenExchange.set(t,i),i}async function E(e){await w();let t=e??globalThis.window?.location.href;await T(await m.callbackHandler(t,m.responseMode))}async function D(){if(await w(),h.refresh)return h.refresh;if(h.revoke)try{await h.revoke}catch{}if(h.logout)try{await h.logout}catch{}if(m.logging?.debug(`Attempting to refresh session`),typeof p.session?.refresh_token!=`string`){m.logging?.debug(`Refresh called without refresh token`);return}return h.refresh=(async()=>{try{await x(await l({refreshToken:p.session.refresh_token,options:m,expectedSub:p.session?.claims?.sub})),_(`tokenRefreshed`,[{idToken:p.session?.id_token,accessToken:p.session?.access_token,refreshToken:p.session?.refresh_token,claims:p.session?.claims}]),m.logging?.debug(`Session refresh successful`)}catch(e){let n=p.session?.refresh_token;throw!(e instanceof t)&&!(e instanceof r)&&await S(),_(`tokenRefreshFailed`,[{refreshToken:n}]),m.logging?.error(`Session refresh failed`,e),e}finally{h.refresh=null}})(),h.refresh}async function O(){if(await w(),h.revoke)return h.revoke;if(h.refresh)try{await h.refresh}catch{}if(h.logout)try{await h.logout}catch{}return h.revoke=(async()=>{try{p.session?.refresh_token?m.logging?.debug(`Attempting to revoke refresh token`):p.session?.access_token&&m.logging?.debug(`Attempting to revoke access token`);let e=p.session;if(await S(),!e?.access_token&&!e?.refresh_token){m.logging?.debug(`Revoke called without session`);return}let t=e.refresh_token?`refresh_token`:`access_token`,n=t===`refresh_token`?e.refresh_token:e.access_token;try{await c({tokenTypeHint:t,token:n,options:m}),t===`refresh_token`?(_(`tokenRevoked`,[{token:e.refresh_token,tokenTypeHint:`refresh_token`}]),m.logging?.info(`Refresh token successfully revoked`)):(_(`tokenRevoked`,[{token:e.access_token,tokenTypeHint:`access_token`}]),m.logging?.info(`Access token successfully revoked`))}catch(n){throw t===`refresh_token`?_(`tokenRevokeFailed`,[{token:e.refresh_token,tokenTypeHint:`refresh_token`}]):_(`tokenRevokeFailed`,[{token:e.access_token,tokenTypeHint:`access_token`}]),m.logging?.error(`Token revocation failed`,n),n}}finally{h.revoke=null}})(),h.revoke}async function k(e){if(await w(),h.logout)return h.logout;if(h.revoke)try{await h.revoke}catch{}if(h.refresh)try{await h.refresh}catch{}return h.logout=(async()=>{try{m.logging?.debug(`Attempting to logout`);let t=p.session;if(await S(),_(`logoutInitiated`,[{idToken:t?.id_token,claims:t?.claims}]),m.logging?.debug(`Logout initiated`),!t?.id_token){m.logging?.debug(`Logout called without id token`);return}try{let n=await d(m),r=u({url:n.end_session_endpoint,idToken:t.id_token,postLogoutRedirectUri:e?.postLogoutRedirectUri});await m.urlHandler(r,e)}catch(e){m.logging?.error(`Unable to redirect to the end-session endpoint`,e)}}finally{h.logout=null}})(),h.logout}return{dispatchEvent:_,subscribeToEvent:v,subscribeToAllEvents:y,getSession:b,updateSession:x,cleanupSession:S,checkAuthentication:C,init:w,tokenExchange:T,handleCallback:E,refresh:D,revoke:O,logout:k}}export{p as createBaseFlow};
|
|
2
2
|
//# sourceMappingURL=base.mjs.map
|
package/dist/flows/base.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.mjs","names":[],"sources":["../../src/flows/base.ts"],"sourcesContent":["import type { EventFunctions, ExtraRequestArgs, FlowState, SDK, SDKOptions, SessionData } from '../types/oidc';\nimport { buildEndSessionUrl, exchangeCode, getDiscoveryDocument, refreshToken, revokeToken, verifyIdToken } from '../utils/oidc';\nimport { loadSession, serializeSession, isSessionExpired } from '../utils/session';\nimport { ConfigurationError, NetworkError, ProtocolError, ServerError } from '../utils/errors';\n\n/**\n * Creates a base flow for the Strivacity SDK, providing common functionality for managing authentication sessions.\n *\n * @param flowState - The initial state of the flow, including session data and initialization status.\n * @param options - The SDK options, including issuer, clientId, redirectUri, scopes, and storage configuration.\n * @template URLHandlerParams - The type of additional request arguments for URL handling.\n * @returns An object implementing the SDK interface, with methods for initializing the flow, managing sessions, and handling authentication events.\n */\nexport function createBaseFlow<URLHandlerParams extends ExtraRequestArgs = ExtraRequestArgs>(flowState: FlowState, options: SDKOptions) {\n\tconst promises: Record<'init' | 'refresh' | 'revoke' | 'logout', Promise<void> | null> & { tokenExchange: Map<string, Promise<void>> } = {\n\t\tinit: null,\n\t\trefresh: null,\n\t\trevoke: null,\n\t\tlogout: null,\n\t\ttokenExchange: new Map(),\n\t};\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tconst eventCallbacks: Record<keyof EventFunctions, Set<(...args: Array<any>) => Promise<void> | void>> = {\n\t\taccessTokenExpired: new Set(),\n\t\tinit: new Set(),\n\t\tloggedIn: new Set(),\n\t\tsessionUpdated: new Set(),\n\t\tsessionCleared: new Set(),\n\t\tloginInitiated: new Set(),\n\t\tflowInitiated: new Set(),\n\t\tlogoutInitiated: new Set(),\n\t\tsessionLoaded: new Set(),\n\t\ttokenRefreshed: new Set(),\n\t\ttokenRefreshFailed: new Set(),\n\t\ttokenRevoked: new Set(),\n\t\ttokenRevokeFailed: new Set(),\n\t};\n\n\tfunction dispatchEvent<T extends keyof EventFunctions>(eventName: T, args: Parameters<EventFunctions[T]>): void {\n\t\tfor (const fn of eventCallbacks[eventName]) {\n\t\t\tvoid fn(...args);\n\t\t}\n\t}\n\n\tfunction subscribeToEvent<T extends keyof EventFunctions>(\n\t\teventName: T,\n\t\tcallbackFn: (...params: Parameters<EventFunctions[T]>) => Promise<void> | void,\n\t): ReturnType<SDK<URLHandlerParams>['subscribeToEvent']> {\n\t\teventCallbacks[eventName].add(callbackFn);\n\t\treturn { dispose: () => eventCallbacks[eventName].delete(callbackFn) };\n\t}\n\n\tfunction subscribeToAllEvents(callbackFn: (...params: Array<unknown>) => Promise<void> | void): ReturnType<SDK<URLHandlerParams>['subscribeToAllEvents']> {\n\t\tfor (const eventName in eventCallbacks) {\n\t\t\teventCallbacks[eventName as keyof EventFunctions].add(callbackFn);\n\t\t}\n\n\t\treturn {\n\t\t\tdispose: () => {\n\t\t\t\tfor (const eventName in eventCallbacks) {\n\t\t\t\t\teventCallbacks[eventName as keyof EventFunctions].delete(callbackFn);\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\tasync function getSession(): Promise<SessionData | null> {\n\t\tawait init();\n\n\t\treturn flowState.session;\n\t}\n\n\tasync function updateSession(newData: SessionData): ReturnType<SDK<URLHandlerParams>['updateSession']> {\n\t\tawait init();\n\n\t\t// NOTE: only unverified callers (e.g. direct API use) need validating here\n\t\tif (newData.id_token && !newData.claims) {\n\t\t\tnewData.claims = await verifyIdToken({ idToken: newData.id_token, options });\n\t\t}\n\n\t\tif (!options.serverSessionUri) {\n\t\t\tawait options.storage.set(options.storageTokenName, serializeSession(newData));\n\t\t}\n\n\t\tflowState.session = newData;\n\n\t\tdispatchEvent('sessionUpdated', [\n\t\t\t{\n\t\t\t\tidToken: flowState.session.id_token,\n\t\t\t\taccessToken: flowState.session.access_token,\n\t\t\t\trefreshToken: flowState.session.refresh_token,\n\t\t\t\tclaims: flowState.session.claims,\n\t\t\t},\n\t\t]);\n\t}\n\n\tasync function cleanupSession(): ReturnType<SDK<URLHandlerParams>['cleanupSession']> {\n\t\tawait init();\n\n\t\tif (!options.serverSessionUri) {\n\t\t\tawait options.storage.delete(options.storageTokenName);\n\t\t}\n\n\t\tflowState.session = null;\n\n\t\tdispatchEvent('sessionCleared', []);\n\t}\n\n\tasync function checkAuthentication(\n\t\tparams: { autoRefresh: boolean } = { autoRefresh: options.autoRefresh },\n\t): ReturnType<SDK<URLHandlerParams>['checkAuthentication']> {\n\t\tif (flowState.session?.access_token && !isSessionExpired(flowState.session)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (params?.autoRefresh && flowState.session?.refresh_token) {\n\t\t\ttry {\n\t\t\t\tawait refresh();\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn !isSessionExpired(flowState.session);\n\t}\n\n\tasync function init(): ReturnType<SDK<URLHandlerParams>['init']> {\n\t\tif (flowState.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (promises.init) {\n\t\t\treturn promises.init;\n\t\t}\n\n\t\tpromises.init = (async () => {\n\t\t\ttry {\n\t\t\t\tif (!options.issuer) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: issuer');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (!options.clientId) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: clientId');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (!options.redirectUri) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: redirectUri');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (options.scopes && !Array.isArray(options.scopes)) {\n\t\t\t\t\tconst error = new ConfigurationError('Invalid option: scopes');\n\t\t\t\t\toptions.logging?.error('Invalid option provided', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\tif (!options.serverSessionUri) {\n\t\t\t\t\tflowState.session = loadSession(await options.storage.get(options.storageTokenName));\n\t\t\t\t}\n\n\t\t\t\tflowState.initialized = true;\n\n\t\t\t\tdispatchEvent('init', []);\n\t\t\t\toptions.logging?.debug('SDK initialized');\n\n\t\t\t\tif (!flowState.session && !options.serverSessionUri) {\n\t\t\t\t\toptions.logging?.debug('No session found in storage');\n\t\t\t\t}\n\n\t\t\t\tif (flowState.session?.access_token) {\n\t\t\t\t\tdispatchEvent('sessionLoaded', [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tidToken: flowState.session.id_token,\n\t\t\t\t\t\t\taccessToken: flowState.session.access_token,\n\t\t\t\t\t\t\trefreshToken: flowState.session.refresh_token,\n\t\t\t\t\t\t\tclaims: flowState.session.claims,\n\t\t\t\t\t\t},\n\t\t\t\t\t]);\n\t\t\t\t\toptions.logging?.debug('Session loaded from storage');\n\t\t\t\t}\n\n\t\t\t\tif (flowState.session?.access_token && isSessionExpired(flowState.session)) {\n\t\t\t\t\tdispatchEvent('accessTokenExpired', [{ accessToken: flowState.session.access_token, refreshToken: flowState.session.refresh_token }]);\n\t\t\t\t\toptions.logging?.debug('Access token has expired');\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.init = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.init;\n\t}\n\n\tasync function tokenExchange(params: Parameters<SDK<URLHandlerParams>['tokenExchange']>[0] = {}): ReturnType<SDK<URLHandlerParams>['tokenExchange']> {\n\t\tawait init();\n\n\t\tconst exchangeKey = params.state ?? '';\n\t\tconst inFlight = promises.tokenExchange.get(exchangeKey);\n\n\t\tif (inFlight) {\n\t\t\treturn inFlight;\n\t\t}\n\n\t\tconst exchangePromise = (async () => {\n\t\t\toptions.logging?.debug('Exchanging authorization code for tokens');\n\n\t\t\ttry {\n\t\t\t\tconst session = await exchangeCode({ params, options });\n\n\t\t\t\tif (!session.access_token) {\n\t\t\t\t\tthrow new ProtocolError('Missing access_token');\n\t\t\t\t}\n\n\t\t\t\tawait updateSession(session);\n\n\t\t\t\toptions.logging?.debug('Token exchange successful');\n\n\t\t\t\tdispatchEvent('loggedIn', [\n\t\t\t\t\t{ idToken: session.id_token, accessToken: session.access_token, refreshToken: session.refresh_token, claims: session.claims },\n\t\t\t\t]);\n\n\t\t\t\tif (options.logging) {\n\t\t\t\t\toptions.logging.xEventId = undefined;\n\t\t\t\t\toptions.logging.info('Login successful');\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\toptions.logging?.error('Token exchange failed', error);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tpromises.tokenExchange.delete(exchangeKey);\n\t\t\t}\n\t\t})();\n\n\t\tpromises.tokenExchange.set(exchangeKey, exchangePromise);\n\n\t\treturn exchangePromise;\n\t}\n\n\tasync function handleCallback(url?: string | URL): ReturnType<SDK<URLHandlerParams>['handleCallback']> {\n\t\tawait init();\n\n\t\tconst callbackUrl = url ?? globalThis.window?.location.href;\n\t\tconst params = (await options.callbackHandler(callbackUrl, options.responseMode)) as Record<string, string>;\n\n\t\tawait tokenExchange(params);\n\t}\n\n\tasync function refresh(): ReturnType<SDK<URLHandlerParams>['refresh']> {\n\t\tawait init();\n\n\t\tif (promises.refresh) {\n\t\t\treturn promises.refresh;\n\t\t}\n\n\t\tif (promises.revoke) {\n\t\t\ttry {\n\t\t\t\tawait promises.revoke;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.logout) {\n\t\t\ttry {\n\t\t\t\tawait promises.logout;\n\t\t\t} catch {}\n\t\t}\n\n\t\toptions.logging?.debug('Attempting to refresh session');\n\n\t\tif (typeof flowState.session?.refresh_token !== 'string') {\n\t\t\toptions.logging?.debug('Refresh called without refresh token');\n\t\t\treturn;\n\t\t}\n\n\t\tpromises.refresh = (async () => {\n\t\t\ttry {\n\t\t\t\tconst session = await refreshToken({ refreshToken: flowState.session!.refresh_token!, options, expectedSub: flowState.session?.claims?.sub });\n\t\t\t\tawait updateSession(session);\n\n\t\t\t\tdispatchEvent('tokenRefreshed', [\n\t\t\t\t\t{\n\t\t\t\t\t\tidToken: flowState.session?.id_token,\n\t\t\t\t\t\taccessToken: flowState.session?.access_token,\n\t\t\t\t\t\trefreshToken: flowState.session?.refresh_token,\n\t\t\t\t\t\tclaims: flowState.session?.claims,\n\t\t\t\t\t},\n\t\t\t\t]);\n\t\t\t\toptions.logging?.debug('Session refresh successful');\n\t\t\t} catch (error) {\n\t\t\t\tconst failedRefreshToken = flowState.session?.refresh_token;\n\n\t\t\t\t// NOTE: Transient Network/Server failures must not destroy a session that could still be refreshed later.\n\t\t\t\tif (!(error instanceof NetworkError) && !(error instanceof ServerError)) {\n\t\t\t\t\tawait cleanupSession();\n\t\t\t\t}\n\n\t\t\t\tdispatchEvent('tokenRefreshFailed', [{ refreshToken: failedRefreshToken }]);\n\t\t\t\toptions.logging?.error('Session refresh failed', error);\n\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tpromises.refresh = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.refresh;\n\t}\n\n\tasync function revoke(): ReturnType<SDK<URLHandlerParams>['revoke']> {\n\t\tawait init();\n\n\t\tif (promises.revoke) {\n\t\t\treturn promises.revoke;\n\t\t}\n\n\t\tif (promises.refresh) {\n\t\t\ttry {\n\t\t\t\tawait promises.refresh;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.logout) {\n\t\t\ttry {\n\t\t\t\tawait promises.logout;\n\t\t\t} catch {}\n\t\t}\n\n\t\tpromises.revoke = (async () => {\n\t\t\ttry {\n\t\t\t\tif (flowState.session?.refresh_token) {\n\t\t\t\t\toptions.logging?.debug('Attempting to revoke refresh token');\n\t\t\t\t} else if (flowState.session?.access_token) {\n\t\t\t\t\toptions.logging?.debug('Attempting to revoke access token');\n\t\t\t\t}\n\n\t\t\t\t// NOTE: Cleanup session before revocation\n\t\t\t\tconst currentSession = flowState.session;\n\t\t\t\tawait cleanupSession();\n\n\t\t\t\tif (!currentSession?.access_token && !currentSession?.refresh_token) {\n\t\t\t\t\toptions.logging?.debug('Revoke called without session');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst tokenTypeHint = currentSession.refresh_token ? 'refresh_token' : 'access_token';\n\t\t\t\tconst token = (tokenTypeHint === 'refresh_token' ? currentSession.refresh_token : currentSession.access_token)!;\n\n\t\t\t\ttry {\n\t\t\t\t\tawait revokeToken({ tokenTypeHint, token, options });\n\n\t\t\t\t\tif (tokenTypeHint === 'refresh_token') {\n\t\t\t\t\t\tdispatchEvent('tokenRevoked', [{ token: currentSession.refresh_token, tokenTypeHint: 'refresh_token' }]);\n\t\t\t\t\t\toptions.logging?.info('Refresh token successfully revoked');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdispatchEvent('tokenRevoked', [{ token: currentSession.access_token, tokenTypeHint: 'access_token' }]);\n\t\t\t\t\t\toptions.logging?.info('Access token successfully revoked');\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (tokenTypeHint === 'refresh_token') {\n\t\t\t\t\t\tdispatchEvent('tokenRevokeFailed', [{ token: currentSession.refresh_token, tokenTypeHint: 'refresh_token' }]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdispatchEvent('tokenRevokeFailed', [{ token: currentSession.access_token, tokenTypeHint: 'access_token' }]);\n\t\t\t\t\t}\n\n\t\t\t\t\toptions.logging?.error('Token revocation failed', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.revoke = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.revoke;\n\t}\n\n\tasync function logout(params?: Parameters<SDK<URLHandlerParams>['logout']>[0]): ReturnType<SDK<URLHandlerParams>['logout']> {\n\t\tawait init();\n\n\t\tif (promises.logout) {\n\t\t\treturn promises.logout;\n\t\t}\n\n\t\tif (promises.revoke) {\n\t\t\ttry {\n\t\t\t\tawait promises.revoke;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.refresh) {\n\t\t\ttry {\n\t\t\t\tawait promises.refresh;\n\t\t\t} catch {}\n\t\t}\n\n\t\tpromises.logout = (async () => {\n\t\t\ttry {\n\t\t\t\toptions.logging?.debug('Attempting to logout');\n\n\t\t\t\t// NOTE: Cleanup session before logout\n\t\t\t\tconst currentSession = flowState.session;\n\t\t\t\tawait cleanupSession();\n\n\t\t\t\tdispatchEvent('logoutInitiated', [{ idToken: currentSession?.id_token, claims: currentSession?.claims }]);\n\t\t\t\toptions.logging?.debug('Logout initiated');\n\n\t\t\t\tif (!currentSession?.id_token) {\n\t\t\t\t\toptions.logging?.debug('Logout called without id token');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tconst metadata = await getDiscoveryDocument(options);\n\t\t\t\t\tconst logoutUrl = buildEndSessionUrl({\n\t\t\t\t\t\turl: metadata.end_session_endpoint,\n\t\t\t\t\t\tidToken: currentSession.id_token,\n\t\t\t\t\t\tpostLogoutRedirectUri: params?.postLogoutRedirectUri,\n\t\t\t\t\t});\n\n\t\t\t\t\tawait options.urlHandler(logoutUrl, params);\n\t\t\t\t} catch (error) {\n\t\t\t\t\toptions.logging?.error('Unable to redirect to the end-session endpoint', error);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.logout = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.logout;\n\t}\n\n\treturn {\n\t\tdispatchEvent,\n\t\tsubscribeToEvent,\n\t\tsubscribeToAllEvents,\n\t\tgetSession,\n\t\tupdateSession,\n\t\tcleanupSession,\n\t\tcheckAuthentication,\n\t\tinit,\n\t\ttokenExchange,\n\t\thandleCallback,\n\t\trefresh,\n\t\trevoke,\n\t\tlogout,\n\t};\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"base.mjs","names":[],"sources":["../../src/flows/base.ts"],"sourcesContent":["import type { EventFunctions, ExtraRequestArgs, FlowState, SDK, SDKOptions, SessionData } from '../types/oidc';\nimport { buildEndSessionUrl, exchangeCode, getDiscoveryDocument, refreshToken, revokeToken, verifyIdToken } from '../utils/oidc';\nimport { loadSession, serializeSession, isSessionExpired } from '../utils/session';\nimport { ConfigurationError, NetworkError, ProtocolError, ServerError } from '../utils/errors';\n\n/**\n * Creates a base flow for the Strivacity SDK, providing common functionality for managing authentication sessions.\n *\n * @param flowState - The initial state of the flow, including session data and initialization status.\n * @param options - The SDK options, including issuer, clientId, redirectUri, scopes, and storage configuration.\n * @template URLHandlerParams - The type of additional request arguments for URL handling.\n * @returns An object implementing the SDK interface, with methods for initializing the flow, managing sessions, and handling authentication events.\n */\nexport function createBaseFlow<URLHandlerParams extends ExtraRequestArgs = ExtraRequestArgs>(flowState: FlowState, options: SDKOptions) {\n\tconst promises: Record<'init' | 'refresh' | 'revoke' | 'logout', Promise<void> | null> & { tokenExchange: Map<string, Promise<void>> } = {\n\t\tinit: null,\n\t\trefresh: null,\n\t\trevoke: null,\n\t\tlogout: null,\n\t\ttokenExchange: new Map(),\n\t};\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tconst eventCallbacks: Record<keyof EventFunctions, Set<(...args: Array<any>) => Promise<void> | void>> = {\n\t\taccessTokenExpired: new Set(),\n\t\tinit: new Set(),\n\t\tloggedIn: new Set(),\n\t\tsessionUpdated: new Set(),\n\t\tsessionCleared: new Set(),\n\t\tloginInitiated: new Set(),\n\t\tflowInitiated: new Set(),\n\t\tlogoutInitiated: new Set(),\n\t\tsessionLoaded: new Set(),\n\t\ttokenRefreshed: new Set(),\n\t\ttokenRefreshFailed: new Set(),\n\t\ttokenRevoked: new Set(),\n\t\ttokenRevokeFailed: new Set(),\n\t};\n\n\tfunction dispatchEvent<T extends keyof EventFunctions>(eventName: T, args: Parameters<EventFunctions[T]>): void {\n\t\tfor (const fn of eventCallbacks[eventName]) {\n\t\t\tvoid fn(...args);\n\t\t}\n\t}\n\n\tfunction subscribeToEvent<T extends keyof EventFunctions>(\n\t\teventName: T,\n\t\tcallbackFn: (...params: Parameters<EventFunctions[T]>) => Promise<void> | void,\n\t): ReturnType<SDK<URLHandlerParams>['subscribeToEvent']> {\n\t\teventCallbacks[eventName].add(callbackFn);\n\t\treturn { dispose: () => eventCallbacks[eventName].delete(callbackFn) };\n\t}\n\n\tfunction subscribeToAllEvents(callbackFn: (...params: Array<unknown>) => Promise<void> | void): ReturnType<SDK<URLHandlerParams>['subscribeToAllEvents']> {\n\t\tfor (const eventName in eventCallbacks) {\n\t\t\teventCallbacks[eventName as keyof EventFunctions].add(callbackFn);\n\t\t}\n\n\t\treturn {\n\t\t\tdispose: () => {\n\t\t\t\tfor (const eventName in eventCallbacks) {\n\t\t\t\t\teventCallbacks[eventName as keyof EventFunctions].delete(callbackFn);\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\tasync function getSession(): Promise<SessionData | null> {\n\t\tawait init();\n\n\t\treturn flowState.session;\n\t}\n\n\tasync function updateSession(newData: SessionData): ReturnType<SDK<URLHandlerParams>['updateSession']> {\n\t\tawait init();\n\n\t\t// NOTE: only unverified callers (e.g. direct API use) need validating here\n\t\tif (newData.id_token && !newData.claims) {\n\t\t\tnewData.claims = await verifyIdToken({ idToken: newData.id_token, options });\n\t\t}\n\n\t\tif (!options.serverSessionUri) {\n\t\t\tawait options.storage.set(options.storageTokenName, serializeSession(newData));\n\t\t}\n\n\t\tflowState.session = newData;\n\n\t\tdispatchEvent('sessionUpdated', [\n\t\t\t{\n\t\t\t\tidToken: flowState.session.id_token,\n\t\t\t\taccessToken: flowState.session.access_token,\n\t\t\t\trefreshToken: flowState.session.refresh_token,\n\t\t\t\tclaims: flowState.session.claims,\n\t\t\t},\n\t\t]);\n\t}\n\n\tasync function cleanupSession(): ReturnType<SDK<URLHandlerParams>['cleanupSession']> {\n\t\tawait init();\n\n\t\tif (!options.serverSessionUri) {\n\t\t\tawait options.storage.delete(options.storageTokenName);\n\t\t}\n\n\t\tflowState.session = null;\n\n\t\tdispatchEvent('sessionCleared', []);\n\t}\n\n\tasync function checkAuthentication(\n\t\tparams: { autoRefresh: boolean } = { autoRefresh: options.autoRefresh },\n\t): ReturnType<SDK<URLHandlerParams>['checkAuthentication']> {\n\t\tif (flowState.session?.access_token && !isSessionExpired(flowState.session, options.refreshSkew)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (params?.autoRefresh && flowState.session?.refresh_token) {\n\t\t\ttry {\n\t\t\t\tawait refresh();\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn !isSessionExpired(flowState.session);\n\t}\n\n\tasync function init(): ReturnType<SDK<URLHandlerParams>['init']> {\n\t\tif (flowState.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (promises.init) {\n\t\t\treturn promises.init;\n\t\t}\n\n\t\tpromises.init = (async () => {\n\t\t\ttry {\n\t\t\t\tif (!options.issuer) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: issuer');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (!options.clientId) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: clientId');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (!options.redirectUri) {\n\t\t\t\t\tconst error = new ConfigurationError('Missing option: redirectUri');\n\t\t\t\t\toptions.logging?.error('Required option missing', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tif (options.scopes && !Array.isArray(options.scopes)) {\n\t\t\t\t\tconst error = new ConfigurationError('Invalid option: scopes');\n\t\t\t\t\toptions.logging?.error('Invalid option provided', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\tif (!options.serverSessionUri) {\n\t\t\t\t\tflowState.session = loadSession(await options.storage.get(options.storageTokenName));\n\t\t\t\t}\n\n\t\t\t\tflowState.initialized = true;\n\n\t\t\t\tdispatchEvent('init', []);\n\t\t\t\toptions.logging?.debug('SDK initialized');\n\n\t\t\t\tif (!flowState.session && !options.serverSessionUri) {\n\t\t\t\t\toptions.logging?.debug('No session found in storage');\n\t\t\t\t}\n\n\t\t\t\tif (flowState.session?.access_token) {\n\t\t\t\t\tdispatchEvent('sessionLoaded', [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tidToken: flowState.session.id_token,\n\t\t\t\t\t\t\taccessToken: flowState.session.access_token,\n\t\t\t\t\t\t\trefreshToken: flowState.session.refresh_token,\n\t\t\t\t\t\t\tclaims: flowState.session.claims,\n\t\t\t\t\t\t},\n\t\t\t\t\t]);\n\t\t\t\t\toptions.logging?.debug('Session loaded from storage');\n\t\t\t\t}\n\n\t\t\t\tif (flowState.session?.access_token && isSessionExpired(flowState.session)) {\n\t\t\t\t\tdispatchEvent('accessTokenExpired', [{ accessToken: flowState.session.access_token, refreshToken: flowState.session.refresh_token }]);\n\t\t\t\t\toptions.logging?.debug('Access token has expired');\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.init = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.init;\n\t}\n\n\tasync function tokenExchange(params: Parameters<SDK<URLHandlerParams>['tokenExchange']>[0] = {}): ReturnType<SDK<URLHandlerParams>['tokenExchange']> {\n\t\tawait init();\n\n\t\tconst exchangeKey = params.state ?? '';\n\t\tconst inFlight = promises.tokenExchange.get(exchangeKey);\n\n\t\tif (inFlight) {\n\t\t\treturn inFlight;\n\t\t}\n\n\t\tconst exchangePromise = (async () => {\n\t\t\toptions.logging?.debug('Exchanging authorization code for tokens');\n\n\t\t\ttry {\n\t\t\t\tconst session = await exchangeCode({ params, options });\n\n\t\t\t\tif (!session.access_token) {\n\t\t\t\t\tthrow new ProtocolError('Missing access_token');\n\t\t\t\t}\n\n\t\t\t\tawait updateSession(session);\n\n\t\t\t\toptions.logging?.debug('Token exchange successful');\n\n\t\t\t\tdispatchEvent('loggedIn', [\n\t\t\t\t\t{ idToken: session.id_token, accessToken: session.access_token, refreshToken: session.refresh_token, claims: session.claims },\n\t\t\t\t]);\n\n\t\t\t\tif (options.logging) {\n\t\t\t\t\toptions.logging.xEventId = undefined;\n\t\t\t\t\toptions.logging.info('Login successful');\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\toptions.logging?.error('Token exchange failed', error);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tpromises.tokenExchange.delete(exchangeKey);\n\t\t\t}\n\t\t})();\n\n\t\tpromises.tokenExchange.set(exchangeKey, exchangePromise);\n\n\t\treturn exchangePromise;\n\t}\n\n\tasync function handleCallback(url?: string | URL): ReturnType<SDK<URLHandlerParams>['handleCallback']> {\n\t\tawait init();\n\n\t\tconst callbackUrl = url ?? globalThis.window?.location.href;\n\t\tconst params = (await options.callbackHandler(callbackUrl, options.responseMode)) as Record<string, string>;\n\n\t\tawait tokenExchange(params);\n\t}\n\n\tasync function refresh(): ReturnType<SDK<URLHandlerParams>['refresh']> {\n\t\tawait init();\n\n\t\tif (promises.refresh) {\n\t\t\treturn promises.refresh;\n\t\t}\n\n\t\tif (promises.revoke) {\n\t\t\ttry {\n\t\t\t\tawait promises.revoke;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.logout) {\n\t\t\ttry {\n\t\t\t\tawait promises.logout;\n\t\t\t} catch {}\n\t\t}\n\n\t\toptions.logging?.debug('Attempting to refresh session');\n\n\t\tif (typeof flowState.session?.refresh_token !== 'string') {\n\t\t\toptions.logging?.debug('Refresh called without refresh token');\n\t\t\treturn;\n\t\t}\n\n\t\tpromises.refresh = (async () => {\n\t\t\ttry {\n\t\t\t\tconst session = await refreshToken({ refreshToken: flowState.session!.refresh_token!, options, expectedSub: flowState.session?.claims?.sub });\n\t\t\t\tawait updateSession(session);\n\n\t\t\t\tdispatchEvent('tokenRefreshed', [\n\t\t\t\t\t{\n\t\t\t\t\t\tidToken: flowState.session?.id_token,\n\t\t\t\t\t\taccessToken: flowState.session?.access_token,\n\t\t\t\t\t\trefreshToken: flowState.session?.refresh_token,\n\t\t\t\t\t\tclaims: flowState.session?.claims,\n\t\t\t\t\t},\n\t\t\t\t]);\n\t\t\t\toptions.logging?.debug('Session refresh successful');\n\t\t\t} catch (error) {\n\t\t\t\tconst failedRefreshToken = flowState.session?.refresh_token;\n\n\t\t\t\t// NOTE: Transient Network/Server failures must not destroy a session that could still be refreshed later.\n\t\t\t\tif (!(error instanceof NetworkError) && !(error instanceof ServerError)) {\n\t\t\t\t\tawait cleanupSession();\n\t\t\t\t}\n\n\t\t\t\tdispatchEvent('tokenRefreshFailed', [{ refreshToken: failedRefreshToken }]);\n\t\t\t\toptions.logging?.error('Session refresh failed', error);\n\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tpromises.refresh = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.refresh;\n\t}\n\n\tasync function revoke(): ReturnType<SDK<URLHandlerParams>['revoke']> {\n\t\tawait init();\n\n\t\tif (promises.revoke) {\n\t\t\treturn promises.revoke;\n\t\t}\n\n\t\tif (promises.refresh) {\n\t\t\ttry {\n\t\t\t\tawait promises.refresh;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.logout) {\n\t\t\ttry {\n\t\t\t\tawait promises.logout;\n\t\t\t} catch {}\n\t\t}\n\n\t\tpromises.revoke = (async () => {\n\t\t\ttry {\n\t\t\t\tif (flowState.session?.refresh_token) {\n\t\t\t\t\toptions.logging?.debug('Attempting to revoke refresh token');\n\t\t\t\t} else if (flowState.session?.access_token) {\n\t\t\t\t\toptions.logging?.debug('Attempting to revoke access token');\n\t\t\t\t}\n\n\t\t\t\t// NOTE: Cleanup session before revocation\n\t\t\t\tconst currentSession = flowState.session;\n\t\t\t\tawait cleanupSession();\n\n\t\t\t\tif (!currentSession?.access_token && !currentSession?.refresh_token) {\n\t\t\t\t\toptions.logging?.debug('Revoke called without session');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst tokenTypeHint = currentSession.refresh_token ? 'refresh_token' : 'access_token';\n\t\t\t\tconst token = (tokenTypeHint === 'refresh_token' ? currentSession.refresh_token : currentSession.access_token)!;\n\n\t\t\t\ttry {\n\t\t\t\t\tawait revokeToken({ tokenTypeHint, token, options });\n\n\t\t\t\t\tif (tokenTypeHint === 'refresh_token') {\n\t\t\t\t\t\tdispatchEvent('tokenRevoked', [{ token: currentSession.refresh_token, tokenTypeHint: 'refresh_token' }]);\n\t\t\t\t\t\toptions.logging?.info('Refresh token successfully revoked');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdispatchEvent('tokenRevoked', [{ token: currentSession.access_token, tokenTypeHint: 'access_token' }]);\n\t\t\t\t\t\toptions.logging?.info('Access token successfully revoked');\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (tokenTypeHint === 'refresh_token') {\n\t\t\t\t\t\tdispatchEvent('tokenRevokeFailed', [{ token: currentSession.refresh_token, tokenTypeHint: 'refresh_token' }]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdispatchEvent('tokenRevokeFailed', [{ token: currentSession.access_token, tokenTypeHint: 'access_token' }]);\n\t\t\t\t\t}\n\n\t\t\t\t\toptions.logging?.error('Token revocation failed', error);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.revoke = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.revoke;\n\t}\n\n\tasync function logout(params?: Parameters<SDK<URLHandlerParams>['logout']>[0]): ReturnType<SDK<URLHandlerParams>['logout']> {\n\t\tawait init();\n\n\t\tif (promises.logout) {\n\t\t\treturn promises.logout;\n\t\t}\n\n\t\tif (promises.revoke) {\n\t\t\ttry {\n\t\t\t\tawait promises.revoke;\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (promises.refresh) {\n\t\t\ttry {\n\t\t\t\tawait promises.refresh;\n\t\t\t} catch {}\n\t\t}\n\n\t\tpromises.logout = (async () => {\n\t\t\ttry {\n\t\t\t\toptions.logging?.debug('Attempting to logout');\n\n\t\t\t\t// NOTE: Cleanup session before logout\n\t\t\t\tconst currentSession = flowState.session;\n\t\t\t\tawait cleanupSession();\n\n\t\t\t\tdispatchEvent('logoutInitiated', [{ idToken: currentSession?.id_token, claims: currentSession?.claims }]);\n\t\t\t\toptions.logging?.debug('Logout initiated');\n\n\t\t\t\tif (!currentSession?.id_token) {\n\t\t\t\t\toptions.logging?.debug('Logout called without id token');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tconst metadata = await getDiscoveryDocument(options);\n\t\t\t\t\tconst logoutUrl = buildEndSessionUrl({\n\t\t\t\t\t\turl: metadata.end_session_endpoint,\n\t\t\t\t\t\tidToken: currentSession.id_token,\n\t\t\t\t\t\tpostLogoutRedirectUri: params?.postLogoutRedirectUri,\n\t\t\t\t\t});\n\n\t\t\t\t\tawait options.urlHandler(logoutUrl, params);\n\t\t\t\t} catch (error) {\n\t\t\t\t\toptions.logging?.error('Unable to redirect to the end-session endpoint', error);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tpromises.logout = null;\n\t\t\t}\n\t\t})();\n\n\t\treturn promises.logout;\n\t}\n\n\treturn {\n\t\tdispatchEvent,\n\t\tsubscribeToEvent,\n\t\tsubscribeToAllEvents,\n\t\tgetSession,\n\t\tupdateSession,\n\t\tcleanupSession,\n\t\tcheckAuthentication,\n\t\tinit,\n\t\ttokenExchange,\n\t\thandleCallback,\n\t\trefresh,\n\t\trevoke,\n\t\tlogout,\n\t};\n}\n"],"mappings":"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"}
|
package/dist/server/base.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../utils/errors.cjs"),t=require("../utils/common.cjs"),n=require("../utils/session.cjs"),r=require("../assets/oidc.cjs"),i=require("../assets/server.cjs");var a=`strivacity-session-v1`,o=3900,s=new Set([`transfer-encoding`,`connection`,`keep-alive`,`content-encoding`]),c=`sty.returnTo`,l=120;function u(a,o){let s=i.o(a,o),l=new Map;function u(){if(!s.issuer){let t=new e.ConfigurationError(`Missing option: issuer`);throw s.logging?.error(`Required option missing`,t),t}if(!s.clientId){let t=new e.ConfigurationError(`Missing option: clientId`);throw s.logging?.error(`Required option missing`,t),t}if(!s.redirectUri){let t=new e.ConfigurationError(`Missing option: redirectUri`);throw s.logging?.error(`Required option missing`,t),t}if(s.scopes&&!Array.isArray(s.scopes)){let t=new e.ConfigurationError(`Invalid option: scopes`);throw s.logging?.error(`Invalid option provided`,t),t}}async function d(e,t=302,n){return a.redirect?await a.redirect(e,t,n):new Response(null,{status:t,headers:{location:e.toString()}})}async function f(t,n,r){let i=new URL(`/error`,t);return n instanceof e.OidcError?(i.searchParams.set(`type`,n.category.toLowerCase()),i.searchParams.set(`error`,n.error),n.errorDescription&&i.searchParams.set(`error_description`,n.errorDescription)):n instanceof Error&&`category`in n?(i.searchParams.set(`type`,n.category.toLowerCase()),i.searchParams.set(`error`,n.name),i.searchParams.set(`error_description`,n.message)):(i.searchParams.set(`type`,`unknown`),i.searchParams.set(`error`,`unknown_error`),i.searchParams.set(`error_description`,n instanceof Error?n.message:`Unknown error`)),d(i,302,r)}async function p(e){return n.loadSession(await s.storage.get(s.storageTokenName,e))}async function m(e,t){await s.storage.set(s.storageTokenName,n.serializeSession(e),t)}async function h(e){await s.storage.delete(s.storageTokenName,e)}async function g(t){s.logging?.debug(`Attempting to refresh session`);let n=await p(t);if(!n)throw new e.ProtocolError(`No session available to refresh`);if(typeof n.refresh_token!=`string`)throw new e.ConfigurationError(`No refresh token available`);try{let e=await r.h({refreshToken:n.refresh_token,options:s,expectedSub:n.claims?.sub});return await m(e,t),s.logging?.debug(`Session refresh successful`),e}catch(e){throw await h(t),s.logging?.error(`Session refresh failed`,e),e}}async function _(e){let t=await p(e);if(t?.refresh_token?s.logging?.debug(`Attempting to revoke refresh token`):s.logging?.debug(`Attempting to revoke access token`),await h(e),!t?.access_token&&!t?.refresh_token){s.logging?.debug(`Revoke called without session`);return}let n=t.refresh_token?`refresh_token`:`access_token`,i=n===`refresh_token`?t.refresh_token:t.access_token;try{await r.g({tokenTypeHint:n,token:i,options:s}),n===`refresh_token`?s.logging?.info(`Refresh token successfully revoked`):s.logging?.info(`Access token successfully revoked`)}catch(e){throw s.logging?.error(`Token revocation failed`,e),e}}async function v(e){s.logging?.debug(`Attempting entry request`);let{searchParams:t}=new URL(e);try{let e=new URL(`/provider/flow/entry`,s.issuer),n=await r.o({url:e,params:t,sdkMode:s.mode===`embedded`?`web-embedded`:`web`,options:s});return s.logging?.debug(`Entry request successful - ${JSON.stringify(n)}`),n}catch(e){throw s.logging?.error(`Entry request failed`,e),e}}async function y(t,n){s.logging?.debug(`Exchanging authorization code for tokens`);try{let i=await r.a({params:t,options:s});if(!i.access_token)throw new e.ProtocolError(`Missing access_token`);return await m(i,n),s.logging?.debug(`Token exchange successful`),s.logging&&(s.logging.xEventId=void 0,s.logging.info(`Login successful`)),i}catch(e){throw s.logging?.error(`Token exchange failed`,e),e}}async function b(e,t){s.logging?.debug(`Attempting to logout`);let n=await p(t);if(await h(t),s.logging?.debug(`Logout initiated`),!n?.id_token)return s.logging?.debug(`Logout called without id token`),new URL(e);let i=await r.p(s);return r.n({url:i.end_session_endpoint,idToken:n.id_token,postLogoutRedirectUri:new URL(e).toString()})}async function x(t,n={}){let o=await a.toRequest(t),l=new URL(o.url),{returnTo:u,...
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../utils/errors.cjs"),t=require("../utils/common.cjs"),n=require("../utils/session.cjs"),r=require("../assets/oidc.cjs"),i=require("../assets/server.cjs");var a=`strivacity-session-v1`,o=3900,s=new Set([`transfer-encoding`,`connection`,`keep-alive`,`content-encoding`]),c=`sty.returnTo`,l=120;function u(a,o){let s=i.o(a,o),l=new Map;function u(){if(!s.issuer){let t=new e.ConfigurationError(`Missing option: issuer`);throw s.logging?.error(`Required option missing`,t),t}if(!s.clientId){let t=new e.ConfigurationError(`Missing option: clientId`);throw s.logging?.error(`Required option missing`,t),t}if(!s.redirectUri){let t=new e.ConfigurationError(`Missing option: redirectUri`);throw s.logging?.error(`Required option missing`,t),t}if(s.scopes&&!Array.isArray(s.scopes)){let t=new e.ConfigurationError(`Invalid option: scopes`);throw s.logging?.error(`Invalid option provided`,t),t}}async function d(e,t=302,n){return a.redirect?await a.redirect(e,t,n):new Response(null,{status:t,headers:{location:e.toString()}})}async function f(t,n,r){let i=new URL(`/error`,t);return n instanceof e.OidcError?(i.searchParams.set(`type`,n.category.toLowerCase()),i.searchParams.set(`error`,n.error),n.errorDescription&&i.searchParams.set(`error_description`,n.errorDescription)):n instanceof Error&&`category`in n?(i.searchParams.set(`type`,n.category.toLowerCase()),i.searchParams.set(`error`,n.name),i.searchParams.set(`error_description`,n.message)):(i.searchParams.set(`type`,`unknown`),i.searchParams.set(`error`,`unknown_error`),i.searchParams.set(`error_description`,n instanceof Error?n.message:`Unknown error`)),d(i,302,r)}async function p(e){return n.loadSession(await s.storage.get(s.storageTokenName,e))}async function m(e,t){await s.storage.set(s.storageTokenName,n.serializeSession(e),t)}async function h(e){await s.storage.delete(s.storageTokenName,e)}async function g(t){s.logging?.debug(`Attempting to refresh session`);let n=await p(t);if(!n)throw new e.ProtocolError(`No session available to refresh`);if(typeof n.refresh_token!=`string`)throw new e.ConfigurationError(`No refresh token available`);try{let e=await r.h({refreshToken:n.refresh_token,options:s,expectedSub:n.claims?.sub});return await m(e,t),s.logging?.debug(`Session refresh successful`),e}catch(e){throw await h(t),s.logging?.error(`Session refresh failed`,e),e}}async function _(e){let t=await p(e);if(t?.refresh_token?s.logging?.debug(`Attempting to revoke refresh token`):s.logging?.debug(`Attempting to revoke access token`),await h(e),!t?.access_token&&!t?.refresh_token){s.logging?.debug(`Revoke called without session`);return}let n=t.refresh_token?`refresh_token`:`access_token`,i=n===`refresh_token`?t.refresh_token:t.access_token;try{await r.g({tokenTypeHint:n,token:i,options:s}),n===`refresh_token`?s.logging?.info(`Refresh token successfully revoked`):s.logging?.info(`Access token successfully revoked`)}catch(e){throw s.logging?.error(`Token revocation failed`,e),e}}async function v(e){s.logging?.debug(`Attempting entry request`);let{searchParams:t}=new URL(e);try{let e=new URL(`/provider/flow/entry`,s.issuer),n=await r.o({url:e,params:t,sdkMode:s.mode===`embedded`?`web-embedded`:`web`,options:s});return s.logging?.debug(`Entry request successful - ${JSON.stringify(n)}`),n}catch(e){throw s.logging?.error(`Entry request failed`,e),e}}async function y(t,n){s.logging?.debug(`Exchanging authorization code for tokens`);try{let i=await r.a({params:t,options:s});if(!i.access_token)throw new e.ProtocolError(`Missing access_token`);return await m(i,n),s.logging?.debug(`Token exchange successful`),s.logging&&(s.logging.xEventId=void 0,s.logging.info(`Login successful`)),i}catch(e){throw s.logging?.error(`Token exchange failed`,e),e}}async function b(e,t){s.logging?.debug(`Attempting to logout`);let n=await p(t);if(await h(t),s.logging?.debug(`Logout initiated`),!n?.id_token)return s.logging?.debug(`Logout called without id token`),new URL(e);let i=await r.p(s);return r.n({url:i.end_session_endpoint,idToken:n.id_token,postLogoutRedirectUri:new URL(e).toString()})}async function x(t,n={}){let o=await a.toRequest(t),l=new URL(o.url),{returnTo:u,prompt:d,display:f,login_hint:p,acr_values:m,ui_locales:h,audience:g,..._}=Object.fromEntries(l.searchParams),v=i.d(u,l.origin),y=await r.t({params:{prompt:d??_.prompt,display:f??_.display,loginHint:p??_.loginHint,acrValues:(m??_.acrValues)?.split(` `),uiLocales:(h??_.uiLocales)?.split(` `),audiences:(g??_.audiences)?.split(` `),...n},options:s});if(u&&!v)throw new e.ProtocolError(`Invalid returnTo URL: ${u}. Expected a URL with the same origin as the request: ${l.origin}`);[`embedded`,`native`].includes(s.mode)&&_.sdk&&y.searchParams.set(`sdk`,_.sdk);let b=await s.httpClient.request(y,{method:`GET`,credentials:`include`,redirect:`manual`});return s.logging?.debug(`Attempting to redirect for login`),v&&i.l(t,i.u(c,v)),i.a(t,i.c(b))}async function S(e){return x(e,{prompt:`create`})}async function C(t){let n=await a.toRequest(t),o=new URL(n.url),l=Object.fromEntries(o.searchParams);try{let a=await s.stateStorage.get(`sty.${l.state}`);if(!a)throw new e.ProtocolError(`State not found or expired. Please try logging in again.`);await y(l,t);let u=r.x(a),f=i.s(n.headers.get(`cookie`))[`sty.returnTo`]??s.postLoginRedirectUri;return i.l(t,i.u(c,``,{expires:new Date(0)})),u.metadata?.display===`popup`?i.a(t,new Response(`<!DOCTYPE html><html><body><script>window.opener?.postMessage({}, '*');window.close();<\/script></body></html>`,{headers:{"content-type":`text/html; charset=utf-8`}})):i.a(t,await d(new URL(f,o.origin),302,t))}catch(e){return i.a(t,await f(o.origin,e,t))}}async function w(t){let n=await a.toRequest(t),r=new URL(n.url),o=r.origin,s=r.searchParams.get(`returnTo`),c=i.d(s,o);if(s&&!c)throw new e.ProtocolError(`Invalid returnTo URL: ${s}. Expected a URL with the same origin as the request: ${r.origin}`);try{return await g(t),c?i.a(t,await d(new URL(c,o),302,t)):i.a(t,new Response(null,{status:204}))}catch(e){return i.a(t,await f(o,e,t))}}async function T(e){let t=await a.toRequest(e),n=new URL(t.url).origin;try{return await _(e),i.a(e,await d(new URL(s.postLogoutRedirectUri,n),302,e))}catch(t){return i.a(e,await f(n,t,e))}}async function E(e){let t=await a.toRequest(e),n=new URL(t.url).origin;try{let r=await v(t.url),a=new URL(s.loginUri,n);return a.searchParams.set(`session_id`,r.session_id),a.searchParams.set(`short_app_id`,r.short_app_id),a.searchParams.set(`language`,r.language),i.a(e,await d(a,302,e))}catch(t){return i.a(e,await f(n,t,e))}}async function D(e){let t=await a.toRequest(e),n=new URL(t.url).origin;try{let t=await b(new URL(s.postLogoutRedirectUri,n),e);return i.a(e,await d(t,302,e))}catch(t){return i.a(e,await f(n,t,e))}}async function O(e){if(typeof s.storage.deleteByLogoutToken!=`function`)return new Response(`Back-channel logout requires a storage with deleteByLogoutToken`,{status:501});let n=await a.toRequest(e),o;try{if((n.headers.get(`content-type`)??``).includes(`application/x-www-form-urlencoded`))o=(await n.formData()).get(`logout_token`);else return new Response(`Invalid content type: expected application/x-www-form-urlencoded`,{status:400})}catch{return new Response(`Failed to parse request body`,{status:400})}if(!o)return new Response(`Missing logout_token`,{status:400});let c=t.timestamp();for(let[e,t]of l)t<=c&&l.delete(e);if(l.has(o))return new Response(`Invalid logout_token: token already used`,{status:400});l.set(o,c+120);let u,d;try{d=await r.p(s),u=await r.y({token:o,jwksUri:d.jwks_uri,options:s})}catch(e){return new Response(`Invalid logout_token: ${e.message}`,{status:400})}if(u.iss!==d.issuer)return new Response(`Invalid logout_token: invalid iss claim`,{status:400});if(Array.isArray(u.aud)?!u.aud.includes(s.clientId):u.aud!==s.clientId)return new Response(`Invalid logout_token: invalid aud claim`,{status:400});if(typeof u.iat!=`number`||Math.abs(c-u.iat)>120)return new Response(`Invalid logout_token: invalid or stale iat claim`,{status:400});if(!u.jti)return new Response(`Invalid logout_token: missing jti claim`,{status:400});if(u.nonce!==void 0)return new Response(`Invalid logout_token: nonce claim must not be present`,{status:400});if(!u.events||!(`http://schemas.openid.net/event/backchannel-logout`in u.events))return new Response(`Invalid logout_token: missing ${i.t} in events`,{status:400});if(!u.sid&&!u.sub)return new Response(`Invalid logout_token: must contain sid or sub claim`,{status:400});let f={};u.sid&&(f.sid=u.sid),u.sub&&(f.sub=u.sub);try{await s.storage.deleteByLogoutToken(f)}catch(e){return new Response(`Failed to delete session: ${e.message}`,{status:500})}return new Response(null,{status:200})}async function k(e){let t=await a.toRequest(e),n=new URL(t.url);return t.method===`GET`&&n.pathname===`${s.authUrlPrefix}/login`?x(e):t.method===`GET`&&n.pathname===`${s.authUrlPrefix}/register`?S(e):t.method===`GET`&&n.pathname===`${s.authUrlPrefix}/callback`?C(e):t.method===`GET`&&n.pathname===`${s.authUrlPrefix}/refresh`?w(e):t.method===`GET`&&n.pathname===`${s.authUrlPrefix}/revoke`?T(e):t.method===`GET`&&n.pathname===`${s.authUrlPrefix}/entry`?E(e):t.method===`GET`&&n.pathname===`${s.authUrlPrefix}/logout`?D(e):t.method===`POST`&&n.pathname===`${s.authUrlPrefix}/backchannel-logout`?O(e):null}return u(),{get options(){return s},getSession:p,updateSession:m,refreshSession:g,revokeSession:_,getEntrySession:v,completeLogin:y,logout:b,handleLogin:x,handleRegister:S,handleCallback:C,handleRefresh:w,handleRevoke:T,handleEntry:E,handleLogout:D,handleBackChannelLogout:O,handler:k}}exports.BACKCHANNEL_LOGOUT_TOKEN_MAX_AGE_SECONDS=l,exports.COOKIE_CHUNK_SIZE=o,exports.COOKIE_CONTEXT=a,exports.DISALLOWED_PROXY_HEADERS=s,exports.RETURN_TO_COOKIE=c,exports.createBaseServerSDK=u;
|
|
2
2
|
//# sourceMappingURL=base.cjs.map
|