@auth0/auth0-api-js
Advanced tools
+397
-33
@@ -34,4 +34,7 @@ "use strict"; | ||
| ApiClient: () => ApiClient, | ||
| AuthError: () => AuthError, | ||
| BearerMethod: () => BearerMethod, | ||
| GrantType: () => GrantType, | ||
| InvalidConfigurationError: () => InvalidConfigurationError, | ||
| InvalidDpopProofError: () => InvalidDpopProofError, | ||
| InvalidRequestError: () => InvalidRequestError, | ||
@@ -41,2 +44,3 @@ MissingClientAuthError: () => import_auth0_auth_js2.MissingClientAuthError, | ||
| MissingTransactionError: () => MissingTransactionError, | ||
| ProtectedResourceMetadata: () => ProtectedResourceMetadata, | ||
| ProtectedResourceMetadataBuilder: () => ProtectedResourceMetadataBuilder, | ||
@@ -52,35 +56,223 @@ SigningAlgorithm: () => SigningAlgorithm, | ||
| var oauth = __toESM(require("oauth4webapi"), 1); | ||
| var import_jose = require("jose"); | ||
| var import_jose2 = require("jose"); | ||
| var import_auth0_auth_js = require("@auth0/auth0-auth-js"); | ||
| // src/errors.ts | ||
| var MissingTransactionError = class extends Error { | ||
| code = "missing_transaction_error"; | ||
| constructor(message) { | ||
| super(message ?? "The transaction is missing."); | ||
| this.name = "MissingTransactionError"; | ||
| var MissingRequiredArgumentError = class extends Error { | ||
| code = "missing_required_argument_error"; | ||
| constructor(argument) { | ||
| super(`The argument '${argument}' is required but was not provided.`); | ||
| this.name = "MissingRequiredArgumentError"; | ||
| } | ||
| }; | ||
| var VerifyAccessTokenError = class extends Error { | ||
| code = "verify_access_token_error"; | ||
| var InvalidConfigurationError = class extends Error { | ||
| code = "invalid_configuration_error"; | ||
| constructor(message) { | ||
| super(message); | ||
| this.name = "VerifyAccessTokenError"; | ||
| this.name = "InvalidConfigurationError"; | ||
| } | ||
| }; | ||
| var InvalidRequestError = class extends Error { | ||
| code = "invalid_request"; | ||
| constructor(message) { | ||
| var AuthError = class extends Error { | ||
| code; | ||
| statusCode; | ||
| headers; | ||
| constructor(message, code, statusCode, headers) { | ||
| super(message); | ||
| this.name = "InvalidRequestError"; | ||
| this.name = this.constructor.name; | ||
| this.code = code; | ||
| this.statusCode = statusCode; | ||
| this.headers = headers; | ||
| } | ||
| }; | ||
| var MissingRequiredArgumentError = class extends Error { | ||
| code = "missing_required_argument_error"; | ||
| constructor(argument) { | ||
| super(`The argument '${argument}' is required but was not provided.`); | ||
| this.name = "MissingRequiredArgumentError"; | ||
| var MissingTransactionError = class extends AuthError { | ||
| constructor(message) { | ||
| super(message ?? "The transaction is missing.", "missing_transaction_error"); | ||
| } | ||
| }; | ||
| var VerifyAccessTokenError = class extends AuthError { | ||
| constructor(message, headers) { | ||
| super(message, "verify_access_token_error", 401, headers); | ||
| } | ||
| }; | ||
| var InvalidDpopProofError = class extends AuthError { | ||
| constructor(message = "", headers) { | ||
| super(message, "invalid_dpop_proof", 400, headers); | ||
| } | ||
| }; | ||
| var InvalidRequestError = class extends AuthError { | ||
| constructor(message, headers) { | ||
| super(message, "invalid_request", 400, headers); | ||
| } | ||
| }; | ||
| // src/dpop-api.ts | ||
| var import_crypto = require("crypto"); | ||
| var import_jose = require("jose"); | ||
| var DPOP_ERROR_MESSAGES = { | ||
| PROOF_VERIFICATION_FAILED: "Failed to verify DPoP proof", | ||
| MISSING_PROOF: "Missing DPoP proof", | ||
| MULTIPLE_PROOFS: "Multiple DPoP proofs are not allowed", | ||
| MISSING_CNF_JKT: "Access token is missing cnf.jkt confirmation claim", | ||
| INVALID_IAT: '"iat" claim must be a number', | ||
| INVALID_JTI: '"jti" claim must be a string', | ||
| INVALID_HTM: '"htm" claim must be a string', | ||
| INVALID_HTU: '"htu" claim must be a string', | ||
| INVALID_HTU_URL: '"htu" claim URL must be valid URL', | ||
| INVALID_HTU_URL_HOST: 'Invalid "htu" claim URL: Host contains illegal characters or format', | ||
| INVALID_HTU_URL_PATH: 'Invalid "htu" claim URL: Path must not start with "//"', | ||
| INVALID_HTTP_URL: '"httpUrl" must be a valid URL', | ||
| INVALID_HTTP_URL_HOST: 'Invalid "httpUrl": Host contains illegal characters or format', | ||
| INVALID_HTTP_URL_PATH: 'Invalid "httpUrl": Path must not start with "//"', | ||
| INVALID_ATH: '"ath" claim must be a string', | ||
| IAT_MISMATCH: 'DPoP proof "iat" is outside the acceptable range', | ||
| HTM_MISMATCH: 'DPoP proof "htm" mismatch', | ||
| HTU_MISMATCH: 'DPoP proof "htu" mismatch', | ||
| ATH_MISMATCH: 'DPoP proof "ath" mismatch', | ||
| JWT_AT_MISMATCH: "JWT Access Token confirmation mismatch", | ||
| MISSING_JWK: "Missing or invalid jwk in DPoP proof header", | ||
| PRIVATE_KEY_MATERIAL: "DPoP proof header must not contain private key material" | ||
| }; | ||
| var ALLOWED_DPOP_ALGORITHMS = ["ES256"]; | ||
| function normalizePercentEncodings(s) { | ||
| const UNRESERVED = /[A-Za-z0-9\-._~]/; | ||
| return s.replace(/%[0-9a-fA-F]{2}/g, (m) => { | ||
| const byte = parseInt(m.slice(1), 16); | ||
| const ch = String.fromCharCode(byte); | ||
| return UNRESERVED.test(ch) ? ch : `%${m.slice(1).toUpperCase()}`; | ||
| }); | ||
| } | ||
| function normalizeUrl(input, source) { | ||
| const HOST_RE = /^(?:[A-Za-z0-9.-]+|\[[0-9A-Fa-f:.]+\])(?::\d{1,5})?$/; | ||
| const PROTOCOL_IN_PATH_RE = /^\/[a-z][a-z0-9+.-]*:\/\//i; | ||
| try { | ||
| const url = new URL(input); | ||
| const host = url.host; | ||
| if (typeof host !== "string" || host.length === 0 || host.includes("://") || host.includes("/") || host.includes("?") || host.includes("#") || !HOST_RE.test(host)) { | ||
| if (source === "request") { | ||
| throw new InvalidRequestError(DPOP_ERROR_MESSAGES.INVALID_HTTP_URL_HOST); | ||
| } else { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTU_URL_HOST); | ||
| } | ||
| } | ||
| if (source === "request") { | ||
| const path = url.pathname; | ||
| if (PROTOCOL_IN_PATH_RE.test(path)) { | ||
| throw new InvalidRequestError(DPOP_ERROR_MESSAGES.INVALID_HTTP_URL_PATH); | ||
| } | ||
| } | ||
| url.search = ""; | ||
| url.hash = ""; | ||
| url.pathname = normalizePercentEncodings(url.pathname); | ||
| return url.origin + url.pathname; | ||
| } catch (err) { | ||
| if (source === "request") { | ||
| if (err instanceof InvalidRequestError) throw err; | ||
| throw new InvalidRequestError(DPOP_ERROR_MESSAGES.INVALID_HTTP_URL); | ||
| } | ||
| if (err instanceof InvalidDpopProofError) throw err; | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTU_URL); | ||
| } | ||
| } | ||
| async function verifyProofJwt(proof, algorithms) { | ||
| try { | ||
| const { payload, protectedHeader } = await (0, import_jose.jwtVerify)(proof, import_jose.EmbeddedJWK, { | ||
| typ: "dpop+jwt", | ||
| algorithms: [...algorithms] | ||
| }); | ||
| return { header: protectedHeader, claims: payload }; | ||
| } catch (err) { | ||
| let message = DPOP_ERROR_MESSAGES.PROOF_VERIFICATION_FAILED; | ||
| if (err instanceof Error && err.message) { | ||
| message = err.message; | ||
| } | ||
| throw new InvalidDpopProofError(message); | ||
| } | ||
| } | ||
| async function verifyDpopProof(options) { | ||
| const { proof, accessToken, method, url, cnfJkt, iatOffset, iatLeeway, algorithms } = options; | ||
| if (!proof) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.MISSING_PROOF); | ||
| } | ||
| if (proof.includes(",")) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.MULTIPLE_PROOFS); | ||
| } | ||
| if (!cnfJkt) { | ||
| const err = new VerifyAccessTokenError(DPOP_ERROR_MESSAGES.MISSING_CNF_JKT); | ||
| err.cause = { code: "dpop_binding_mismatch" }; | ||
| throw err; | ||
| } | ||
| const normalizedRequestUrl = normalizeUrl(url, "request"); | ||
| const { claims, header } = await verifyProofJwt(proof, algorithms); | ||
| const { htm, htu, iat, ath, jti } = claims; | ||
| if (typeof jti !== "string" || !jti) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_JTI); | ||
| } | ||
| if (typeof iat !== "number") { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_IAT); | ||
| } | ||
| const now = Math.floor(Date.now() / 1e3); | ||
| if (iat < now - iatOffset || iat > now + iatLeeway) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.IAT_MISMATCH); | ||
| } | ||
| if (typeof htm !== "string") { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTM); | ||
| } | ||
| if (htm.toUpperCase() !== method.toUpperCase()) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.HTM_MISMATCH); | ||
| } | ||
| if (typeof htu !== "string") { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTU); | ||
| } | ||
| const normalizedProofUrl = normalizeUrl(htu, "proof"); | ||
| if (normalizedProofUrl !== normalizedRequestUrl) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.HTU_MISMATCH); | ||
| } | ||
| if (typeof ath !== "string") { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_ATH); | ||
| } | ||
| const hash = (0, import_crypto.createHash)("sha256").update(accessToken).digest(); | ||
| const encodedHash = import_jose.base64url.encode(hash); | ||
| if (ath !== encodedHash) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.ATH_MISMATCH); | ||
| } | ||
| const jwk = header.jwk; | ||
| if (!jwk || typeof jwk !== "object") { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.MISSING_JWK); | ||
| } | ||
| if ("d" in jwk) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.PRIVATE_KEY_MATERIAL); | ||
| } | ||
| const thumbprint = await (0, import_jose.calculateJwkThumbprint)(jwk); | ||
| if (thumbprint !== cnfJkt) { | ||
| const err = new VerifyAccessTokenError(DPOP_ERROR_MESSAGES.JWT_AT_MISMATCH); | ||
| err.cause = { code: "dpop_binding_mismatch" }; | ||
| throw err; | ||
| } | ||
| } | ||
| function buildChallenges(dpopMode, algorithms = ALLOWED_DPOP_ALGORITHMS, params = {}) { | ||
| const bearerParams = [ | ||
| 'realm="api"', | ||
| params.error ? `error="${params.error}"` : void 0, | ||
| params.errorDescription ? `error_description="${params.errorDescription}"` : void 0 | ||
| ].filter(Boolean).join(", "); | ||
| const dpopParams = [ | ||
| params.dpopError ? `error="${params.dpopError}"` : void 0, | ||
| params.dpopErrorDescription ? `error_description="${params.dpopErrorDescription}"` : void 0, | ||
| `algs="${algorithms.join(" ")}"` | ||
| ].filter(Boolean).join(", "); | ||
| const bearerValue = `Bearer ${bearerParams}`; | ||
| const dpopValue = `DPoP ${dpopParams}`; | ||
| const challenges = []; | ||
| if (dpopMode === "allowed") { | ||
| challenges.push(bearerValue, dpopValue); | ||
| } else if (dpopMode === "required") { | ||
| challenges.push(dpopValue); | ||
| } else { | ||
| challenges.push(bearerValue); | ||
| } | ||
| return { | ||
| "www-authenticate": challenges | ||
| }; | ||
| } | ||
| // src/api-client.ts | ||
@@ -93,2 +285,29 @@ var ApiClient = class { | ||
| constructor(options) { | ||
| if (options.dpop !== void 0 && (typeof options.dpop !== "object" || options.dpop === null)) { | ||
| throw new InvalidConfigurationError('Invalid DPoP configuration: "dpop" must be an object'); | ||
| } | ||
| if (options.dpop) { | ||
| const { mode, iatOffset, iatLeeway } = options.dpop; | ||
| if (mode !== void 0 && !["allowed", "required", "disabled"].includes(mode)) { | ||
| throw new InvalidConfigurationError( | ||
| 'Invalid DPoP configuration: "mode" must be allowed, required, or disabled' | ||
| ); | ||
| } | ||
| if (iatOffset !== void 0) { | ||
| if (!Number.isFinite(iatOffset)) { | ||
| throw new InvalidConfigurationError('Invalid DPoP configuration: "iatOffset" must be a number'); | ||
| } | ||
| if (iatOffset < 0) { | ||
| throw new InvalidConfigurationError('Invalid DPoP configuration: "iatOffset" must be a non-negative number'); | ||
| } | ||
| } | ||
| if (iatLeeway !== void 0) { | ||
| if (!Number.isFinite(iatLeeway)) { | ||
| throw new InvalidConfigurationError('Invalid DPoP configuration: "iatLeeway" must be a number'); | ||
| } | ||
| if (iatLeeway < 0) { | ||
| throw new InvalidConfigurationError('Invalid DPoP configuration: "iatLeeway" must be a non-negative number'); | ||
| } | ||
| } | ||
| } | ||
| this.#options = options; | ||
@@ -122,6 +341,3 @@ if (options.clientId) { | ||
| }); | ||
| this.#serverMetadata = await oauth.processDiscoveryResponse( | ||
| issuer, | ||
| response | ||
| ); | ||
| this.#serverMetadata = await oauth.processDiscoveryResponse(issuer, response); | ||
| return { | ||
@@ -138,3 +354,9 @@ serverMetadata: this.#serverMetadata | ||
| * | ||
| * DPoP support: | ||
| * - `dpop.mode` controls behavior: `allowed` (default) accepts Bearer or DPoP; `required` enforces DPoP; `disabled` ignores DPoP. | ||
| * - When validating a DPoP-bound token, you must provide `scheme: 'dpop'`, the `dpopProof` header value, and the actual `httpMethod`/`httpUrl` used for the request. | ||
| * - Bearer tokens omit DPoP params; DPoP params are validated together and proof binding is enforced. | ||
| * | ||
| * @param options Options containing the access token and optional required claims. | ||
| * @see README.md and EXAMPLES.md for usage in allowed/required/disabled modes. | ||
| * @returns Promise resolving to the verified token payload containing all JWT claims. | ||
@@ -146,21 +368,70 @@ * @throws {VerifyAccessTokenError} When verification fails due to invalid signature, | ||
| * ```typescript | ||
| * @example Bearer token validation | ||
| * const apiClient = new ApiClient({ | ||
| * domain: 'example.auth0.com', | ||
| * audience: 'https://api.example.com', // This audience is used for verification | ||
| * clientId: 'client123', | ||
| * clientSecret: 'secret' | ||
| * }); | ||
| * | ||
| * const payload = await apiClient.verifyAccessToken({ | ||
| * accessToken: 'eyJhbGc...' | ||
| * accessToken: 'eyJhbGc...', | ||
| * }); | ||
| * | ||
| * @example DPoP-bound token validation (allowed/required mode) | ||
| * const apiClient = new ApiClient({ | ||
| * domain: 'example.auth0.com', | ||
| * audience: 'https://api.example.com', | ||
| * dpop: { mode: 'required' }, // default is 'allowed' | ||
| * }); | ||
| * const dpopPayload = await apiClient.verifyAccessToken({ | ||
| * accessToken: 'eyJhbGc...', // JWT with cnf.jkt claim | ||
| * scheme: 'dpop', | ||
| * dpopProof: 'eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3A...', // value from DPoP header | ||
| * httpMethod: 'GET', // actual request method | ||
| * httpUrl: 'https://api.example.com/resource', // actual request URL | ||
| * }); | ||
| * ``` | ||
| */ | ||
| async verifyAccessToken(options) { | ||
| const mode = this.#options.dpop?.mode ?? "allowed"; | ||
| const iatOffset = this.#options.dpop?.iatOffset ?? 300; | ||
| const iatLeeway = this.#options.dpop?.iatLeeway ?? 30; | ||
| const scheme = (options.scheme ?? "bearer").toLowerCase(); | ||
| const dpopProof = options.dpopProof; | ||
| const httpMethod = options.httpMethod; | ||
| const httpUrl = options.httpUrl; | ||
| const hasDpopParams = dpopProof !== void 0 || httpMethod !== void 0 || httpUrl !== void 0; | ||
| if (mode !== "disabled" && scheme && !["bearer", "dpop"].includes(scheme)) { | ||
| const err = new InvalidRequestError(""); | ||
| err.cause = { code: "invalid_auth_scheme" }; | ||
| throw this.#addChallenges(err, mode, scheme, { includeError: false }); | ||
| } | ||
| if (mode === "required" && scheme !== "dpop") { | ||
| const err = new InvalidRequestError(""); | ||
| err.cause = { code: "invalid_auth_scheme" }; | ||
| throw this.#addChallenges(err, mode, scheme, { | ||
| includeError: false, | ||
| dpopSpecific: true | ||
| }); | ||
| } | ||
| if (mode === "disabled" && scheme && scheme !== "bearer") { | ||
| const err = new InvalidRequestError(""); | ||
| err.cause = { code: "invalid_auth_scheme" }; | ||
| throw this.#addChallenges(err, mode, scheme, { includeError: false }); | ||
| } | ||
| if (mode !== "disabled" && hasDpopParams && options.scheme === void 0) { | ||
| const err = new InvalidRequestError(""); | ||
| err.cause = { code: "invalid_auth_scheme" }; | ||
| throw this.#addChallenges(err, mode, scheme, { | ||
| includeError: false, | ||
| dpopSpecific: true | ||
| }); | ||
| } | ||
| if (typeof options.accessToken !== "string" || !options.accessToken) { | ||
| throw this.#addChallenges(new VerifyAccessTokenError(""), mode, scheme, { includeError: false }); | ||
| } | ||
| const { serverMetadata } = await this.#discover(); | ||
| this.#jwks ||= (0, import_jose.createRemoteJWKSet)(new URL(serverMetadata.jwks_uri), { | ||
| [import_jose.customFetch]: this.#options.customFetch | ||
| this.#jwks ||= (0, import_jose2.createRemoteJWKSet)(new URL(serverMetadata.jwks_uri), { | ||
| [import_jose2.customFetch]: this.#options.customFetch | ||
| }); | ||
| try { | ||
| const { payload } = await (0, import_jose.jwtVerify)(options.accessToken, this.#jwks, { | ||
| const { payload } = await (0, import_jose2.jwtVerify)(options.accessToken, this.#jwks, { | ||
| issuer: this.#serverMetadata.issuer, | ||
@@ -171,7 +442,98 @@ audience: this.#options.audience, | ||
| }); | ||
| let cnfJkt; | ||
| const cnf = payload.cnf; | ||
| if (cnf && typeof cnf === "object") { | ||
| const maybeJkt = cnf.jkt; | ||
| if (typeof maybeJkt === "string") { | ||
| cnfJkt = maybeJkt; | ||
| } | ||
| } | ||
| const hasProof = typeof dpopProof === "string"; | ||
| if (mode !== "disabled" && scheme === "bearer" && hasProof && !cnfJkt) { | ||
| throw this.#addChallenges( | ||
| new InvalidRequestError("DPoP proof requires the DPoP authentication scheme, not Bearer"), | ||
| mode, | ||
| scheme | ||
| ); | ||
| } | ||
| const shouldVerifyDpop = mode !== "disabled" && (mode === "required" || scheme === "dpop" || hasProof || !!cnfJkt); | ||
| if (mode !== "disabled" && scheme === "dpop" && !cnfJkt) { | ||
| const err = new VerifyAccessTokenError("JWT Access Token has no jkt confirmation claim"); | ||
| err.cause = { code: "dpop_binding_mismatch" }; | ||
| throw this.#addChallenges(err, mode, scheme, { dpopSpecific: true }); | ||
| } | ||
| if (scheme === "bearer" && cnfJkt && mode !== "disabled") { | ||
| throw this.#addChallenges( | ||
| new VerifyAccessTokenError("DPoP-bound token requires the DPoP authentication scheme, not Bearer"), | ||
| mode, | ||
| scheme | ||
| ); | ||
| } | ||
| if (!shouldVerifyDpop) { | ||
| return payload; | ||
| } | ||
| if (!dpopProof) { | ||
| throw this.#addChallenges(new InvalidRequestError(""), mode, scheme, { | ||
| dpopSpecific: true, | ||
| includeError: false | ||
| }); | ||
| } | ||
| if (typeof httpMethod !== "string" || !httpMethod) { | ||
| throw this.#addChallenges( | ||
| new InvalidRequestError("HTTP method is required for DPoP validation"), | ||
| mode, | ||
| scheme, | ||
| { dpopSpecific: true } | ||
| ); | ||
| } | ||
| if (typeof httpUrl !== "string" || !httpUrl) { | ||
| throw this.#addChallenges(new InvalidRequestError("HTTP URL is required for DPoP validation"), mode, scheme, { | ||
| dpopSpecific: true | ||
| }); | ||
| } | ||
| try { | ||
| await verifyDpopProof({ | ||
| proof: dpopProof, | ||
| accessToken: options.accessToken, | ||
| method: httpMethod, | ||
| url: httpUrl, | ||
| cnfJkt, | ||
| iatOffset, | ||
| iatLeeway, | ||
| algorithms: ALLOWED_DPOP_ALGORITHMS | ||
| }); | ||
| } catch (err) { | ||
| if (err instanceof VerifyAccessTokenError || err instanceof InvalidDpopProofError || err instanceof InvalidRequestError) { | ||
| throw this.#addChallenges(err, mode, scheme, { dpopSpecific: true }); | ||
| } | ||
| throw err; | ||
| } | ||
| return payload; | ||
| } catch (e) { | ||
| throw new VerifyAccessTokenError(e.message); | ||
| if (e instanceof AuthError) { | ||
| throw e; | ||
| } | ||
| const message = e instanceof Error ? e.message : String(e); | ||
| const err = new VerifyAccessTokenError(message); | ||
| throw this.#addChallenges(err, mode, scheme); | ||
| } | ||
| } | ||
| #addChallenges(err, mode, scheme, params) { | ||
| const authErr = err; | ||
| if (!authErr.headers) { | ||
| const includeError = params?.includeError ?? true; | ||
| const target = params?.target ?? (params?.dpopSpecific === true ? "dpop" : scheme === "dpop" ? "dpop" : "bearer"); | ||
| let challengeCode = authErr.code; | ||
| if (authErr instanceof VerifyAccessTokenError) { | ||
| challengeCode = "invalid_token"; | ||
| } else if (authErr instanceof InvalidRequestError) { | ||
| challengeCode = "invalid_request"; | ||
| } else if (authErr instanceof InvalidDpopProofError) { | ||
| challengeCode = "invalid_dpop_proof"; | ||
| } | ||
| const challengeParams = includeError && target === "dpop" ? { dpopError: challengeCode, dpopErrorDescription: authErr.message } : includeError && target === "bearer" ? { error: challengeCode, errorDescription: authErr.message } : {}; | ||
| authErr.headers = buildChallenges(mode, ALLOWED_DPOP_ALGORITHMS, challengeParams); | ||
| } | ||
| return authErr; | ||
| } | ||
| /** | ||
@@ -188,5 +550,3 @@ * Retrieves an access token for a connection. | ||
| if (!this.#authClient) { | ||
| throw new import_auth0_auth_js.TokenForConnectionError( | ||
| "Client credentials are required to use getAccessTokenForConnection" | ||
| ); | ||
| throw new import_auth0_auth_js.TokenForConnectionError("Client credentials are required to use getAccessTokenForConnection"); | ||
| } | ||
@@ -535,4 +895,7 @@ const tokenEndpointResponse = await this.#authClient.getTokenForConnection({ | ||
| ApiClient, | ||
| AuthError, | ||
| BearerMethod, | ||
| GrantType, | ||
| InvalidConfigurationError, | ||
| InvalidDpopProofError, | ||
| InvalidRequestError, | ||
@@ -542,2 +905,3 @@ MissingClientAuthError, | ||
| MissingTransactionError, | ||
| ProtectedResourceMetadata, | ||
| ProtectedResourceMetadataBuilder, | ||
@@ -544,0 +908,0 @@ SigningAlgorithm, |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/index.ts","../src/api-client.ts","../src/errors.ts","../src/protected-resource-metadata.ts","../src/token.ts"],"sourcesContent":["export { ApiClient } from './api-client.js';\nexport * from './protected-resource-metadata.js';\nexport * from './errors.js';\nexport * from './types.js';\nexport { getToken } from './token.js';\n\n// Re-export shared errors from auth0-auth-js for convenience\nexport {\n MissingClientAuthError,\n TokenExchangeError,\n} from '@auth0/auth0-auth-js';\n","import * as oauth from 'oauth4webapi';\nimport { createRemoteJWKSet, jwtVerify, customFetch } from 'jose';\nimport { AuthClient, TokenForConnectionError, MissingClientAuthError } from '@auth0/auth0-auth-js';\nimport { AccessTokenForConnectionOptions, ApiClientOptions, ConnectionTokenSet, ExchangeProfileOptions, TokenExchangeProfileResult, VerifyAccessTokenOptions } from './types.js';\nimport {\n MissingRequiredArgumentError,\n VerifyAccessTokenError,\n} from './errors.js';\n\nexport class ApiClient {\n #serverMetadata: oauth.AuthorizationServer | undefined;\n readonly #options: ApiClientOptions;\n #jwks?: ReturnType<typeof createRemoteJWKSet>;\n readonly #authClient: AuthClient | undefined;\n\n constructor(options: ApiClientOptions) {\n this.#options = options;\n\n if (options.clientId) {\n this.#authClient = new AuthClient({\n domain: options.domain,\n clientId: options.clientId,\n clientSecret: options.clientSecret,\n clientAssertionSigningKey: options.clientAssertionSigningKey,\n clientAssertionSigningAlg: options.clientAssertionSigningAlg,\n customFetch: options.customFetch,\n });\n }\n\n if (!this.#options.audience) {\n throw new MissingRequiredArgumentError('audience');\n }\n }\n\n /**\n * Initialized the SDK by performing Metadata Discovery.\n */\n async #discover() {\n if (this.#serverMetadata) {\n return {\n serverMetadata: this.#serverMetadata,\n };\n }\n\n const issuer = new URL(`https://${this.#options.domain}`);\n const response = await oauth.discoveryRequest(issuer, {\n [oauth.customFetch]: this.#options.customFetch,\n });\n\n this.#serverMetadata = await oauth.processDiscoveryResponse(\n issuer,\n response\n );\n\n return {\n serverMetadata: this.#serverMetadata,\n };\n }\n\n /**\n * Verifies the provided access token against the ApiClient's configured audience.\n *\n * This method validates the JWT signature using the Auth0 tenant's JWKS and verifies\n * standard claims including issuer, expiration, and issued-at time. The audience claim\n * is verified against the audience configured when constructing the ApiClient.\n *\n * @param options Options containing the access token and optional required claims.\n * @returns Promise resolving to the verified token payload containing all JWT claims.\n * @throws {VerifyAccessTokenError} When verification fails due to invalid signature,\n * expired token, mismatched audience, or missing required claims.\n *\n * @example\n * ```typescript\n * const apiClient = new ApiClient({\n * domain: 'example.auth0.com',\n * audience: 'https://api.example.com', // This audience is used for verification\n * clientId: 'client123',\n * clientSecret: 'secret'\n * });\n *\n * const payload = await apiClient.verifyAccessToken({\n * accessToken: 'eyJhbGc...'\n * });\n * ```\n */\n async verifyAccessToken(options: VerifyAccessTokenOptions) {\n const { serverMetadata } = await this.#discover();\n\n this.#jwks ||= createRemoteJWKSet(new URL(serverMetadata!.jwks_uri!), {\n [customFetch]: this.#options.customFetch,\n });\n\n try {\n const { payload } = await jwtVerify(options.accessToken, this.#jwks, {\n issuer: this.#serverMetadata!.issuer,\n audience: this.#options.audience,\n algorithms: ['RS256'],\n requiredClaims: ['iat', 'exp', ...(options.requiredClaims || [])],\n });\n return payload;\n } catch (e) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n throw new VerifyAccessTokenError((e as any).message);\n }\n }\n\n /**\n * Retrieves an access token for a connection.\n *\n * @param options - Options for retrieving an access token for a connection.\n *\n * @throws {TokenForConnectionError} If there was an issue requesting the access token.\n *\n * @returns The Connection Token Set, containing the access token for the connection, as well as additional information.\n */\n public async getAccessTokenForConnection(options: AccessTokenForConnectionOptions): Promise<ConnectionTokenSet> {\n if (!this.#authClient) {\n throw new TokenForConnectionError(\n 'Client credentials are required to use getAccessTokenForConnection'\n );\n }\n\n const tokenEndpointResponse = await this.#authClient.getTokenForConnection({\n connection: options.connection,\n loginHint: options.loginHint,\n accessToken: options.accessToken,\n });\n\n return {\n accessToken: tokenEndpointResponse.accessToken,\n scope: tokenEndpointResponse.scope,\n expiresAt: tokenEndpointResponse.expiresAt,\n connection: options.connection,\n loginHint: options.loginHint,\n };\n }\n\n /**\n * Exchanges a token via a Custom Token Exchange Profile for a different API audience while preserving user identity (RFC 8693).\n *\n * This method supports **Custom Token Exchange** for custom token types via a configured Token Exchange Profile.\n *\n * For **Access Token Exchange with Token Vault** (external provider's access tokens), use {@link getAccessTokenForConnection} instead.\n *\n * **Note**: This method requires a confidential client (client credentials must be configured).\n * While Custom Token Exchange Early Access technically permits public clients, this implementation\n * currently requires client authentication. Public client support may be added in a future release.\n *\n * @param subjectToken - The raw token to be exchanged (without \"Bearer \" prefix)\n * @param options - Configuration for the token exchange\n *\n * @returns A promise that resolves with the {@link TokenExchangeProfileResult}\n *\n * @throws {TokenExchangeError} When client credentials are not configured or exchange fails\n *\n * @see {@link https://auth0.com/docs/authenticate/custom-token-exchange Custom Token Exchange Documentation}\n *\n * @example\n * ```typescript\n * // Exchange custom token (organization is optional)\n * const result = await apiClient.getTokenByExchangeProfile(\n * userToken,\n * {\n * subjectTokenType: 'urn:example:custom-token',\n * audience: 'https://api.backend.com',\n * organization: 'org_abc123', // Optional - Organization ID or name\n * scope: 'read:data write:data',\n * }\n * );\n * // When organization is provided, the access token will include the organization ID in its payload\n * ```\n */\n public async getTokenByExchangeProfile(\n subjectToken: string,\n options: ExchangeProfileOptions\n ): Promise<TokenExchangeProfileResult> {\n if (!this.#authClient) {\n throw new MissingClientAuthError();\n }\n\n const response = await this.#authClient.exchangeToken({\n subjectTokenType: options.subjectTokenType,\n subjectToken,\n audience: options.audience,\n scope: options.scope,\n requestedTokenType: options.requestedTokenType,\n organization: options.organization,\n });\n\n return {\n accessToken: response.accessToken,\n expiresAt: response.expiresAt,\n ...(response.scope && { scope: response.scope }),\n ...(response.idToken && { idToken: response.idToken }),\n ...(response.refreshToken && { refreshToken: response.refreshToken }),\n ...(response.tokenType && { tokenType: response.tokenType }),\n ...(response.issuedTokenType && { issuedTokenType: response.issuedTokenType }),\n };\n }\n}\n","/**\n * Error thrown when the transaction is missing.\n */\nexport class MissingTransactionError extends Error {\n public code: string = 'missing_transaction_error';\n\n constructor(message?: string) {\n super(message ?? 'The transaction is missing.');\n this.name = 'MissingTransactionError';\n }\n}\n\n/**\n * Error thrown when verifying the access token.\n */\nexport class VerifyAccessTokenError extends Error {\n public code: string = 'verify_access_token_error';\n\n constructor(message: string) {\n super(message);\n this.name = 'VerifyAccessTokenError';\n }\n}\n\n/**\n * Error thrown when request is missing a valid token or\n * multiple auth methods used\n */\nexport class InvalidRequestError extends Error {\n public code: string = 'invalid_request';\n\n constructor(message: string) {\n super(message);\n this.name = 'InvalidRequestError';\n }\n}\n\n/**\n * Error thrown when a required argument is missing.\n */\nexport class MissingRequiredArgumentError extends Error {\n public code: string = 'missing_required_argument_error';\n\n constructor(argument: string) {\n super(`The argument '${argument}' is required but was not provided.`);\n this.name = 'MissingRequiredArgumentError';\n }\n}\n","/**\n * RFC 9728 - OAuth 2.0 Protected Resource Metadata\n * https://datatracker.ietf.org/doc/html/rfc9728\n */\n\nimport { MissingRequiredArgumentError } from \"./errors.js\";\n\n/**\n * Supported methods of sending an OAuth 2.0 bearer token\n */\nexport enum BearerMethod {\n HEADER = \"header\",\n BODY = \"body\",\n QUERY = \"query\",\n}\n\n/**\n * Supported signing algorithms\n */\nexport enum SigningAlgorithm {\n RS256 = \"RS256\",\n RS384 = \"RS384\",\n RS512 = \"RS512\",\n ES256 = \"ES256\",\n ES384 = \"ES384\",\n ES512 = \"ES512\",\n PS256 = \"PS256\",\n PS384 = \"PS384\",\n PS512 = \"PS512\",\n HS256 = \"HS256\",\n HS384 = \"HS384\",\n HS512 = \"HS512\",\n}\n\n/**\n * Grant types supported\n */\nexport enum GrantType {\n AUTHORIZATION_CODE = \"authorization_code\",\n IMPLICIT = \"implicit\",\n PASSWORD = \"password\",\n CLIENT_CREDENTIALS = \"client_credentials\",\n REFRESH_TOKEN = \"refresh_token\",\n JWT_BEARER = \"urn:ietf:params:oauth:grant-type:jwt-bearer\",\n SAML2_BEARER = \"urn:ietf:params:oauth:grant-type:saml2-bearer\",\n DEVICE_CODE = \"urn:ietf:params:oauth:grant-type:device_code\",\n}\n\n/**\n * Interface for Protected Resource Metadata\n */\nexport interface IProtectedResourceMetadata {\n resource: string;\n authorization_servers: string[];\n jwks_uri?: string;\n scopes_supported?: string[];\n bearer_methods_supported?: BearerMethod[];\n resource_signing_alg_values_supported?: SigningAlgorithm[];\n resource_name?: string;\n resource_documentation?: string;\n resource_policy_uri?: string;\n resource_tos_uri?: string;\n tls_client_certificate_bound_access_tokens?: boolean;\n authorization_details_types_supported?: string[];\n dpop_signing_alg_values_supported?: string[];\n dpop_bound_access_tokens_required?: boolean;\n}\n\n/**\n * Builder for creating a ProtectedResourceMetadata instance\n *\n * @example\n * ```typescript\n * const metadata = new ProtectedResourceMetadataBuilder('https://api.example.com', ['https://auth.example.com'])\n * .withJwksUri('https://api.example.com/.well-known/jwks.json')\n * .withScopesSupported(['read', 'write'])\n * .build();\n * // serialize to json\n * const json = metadata.toJSON();\n * ```\n */\nexport class ProtectedResourceMetadataBuilder {\n private readonly props: Partial<IProtectedResourceMetadata> &\n Pick<IProtectedResourceMetadata, \"resource\" | \"authorization_servers\">;\n\n /**\n * Constructor for the builder\n * @param resource - The protected resource identifier (REQUIRED)\n * @param authorization_servers - Array of authorization server URLs (REQUIRED)\n */\n constructor(resource: string, authorization_servers: string[]) {\n if (!resource?.trim()) {\n throw new MissingRequiredArgumentError(\"resource\");\n }\n if (\n !Array.isArray(authorization_servers) ||\n authorization_servers.length === 0\n ) {\n throw new MissingRequiredArgumentError(\"authorization_servers\");\n }\n this.props = { resource, authorization_servers };\n }\n\n get properties(): IProtectedResourceMetadata {\n return this.props;\n }\n\n /**\n * Builds the ProtectedResourceMetadata\n */\n public build() {\n return new ProtectedResourceMetadata(this);\n }\n\n /**\n * Builder method to add JWKS URI\n */\n withJwksUri(jwks_uri: string): this {\n this.props.jwks_uri = jwks_uri;\n return this;\n }\n\n /**\n * Builder method to add supported scopes\n */\n withScopesSupported(scopes_supported: string[]): this {\n this.props.scopes_supported = [...scopes_supported];\n return this;\n }\n\n /**\n * Builder method to add supported bearer methods\n */\n withBearerMethodsSupported(\n bearer_methods_supported: BearerMethod[]\n ): this {\n this.props.bearer_methods_supported = [...bearer_methods_supported];\n return this;\n }\n\n /**\n * Builder method to add supported resource signing algorithms\n */\n withResourceSigningAlgValuesSupported(\n resource_signing_alg_values_supported: SigningAlgorithm[]\n ): this {\n this.props.resource_signing_alg_values_supported = [...resource_signing_alg_values_supported];\n return this;\n }\n\n /**\n * Builder method to add resource_name\n */\n withResourceName(resource_name: string): this {\n this.props.resource_name = resource_name;\n return this;\n }\n\n /**\n * Builder method to add resource documentation URL\n */\n withResourceDocumentation(resource_documentation: string): this {\n this.props.resource_documentation = resource_documentation;\n return this;\n }\n\n /**\n * Builder method to add resource policy URI\n */\n withResourcePolicyUri(resource_policy_uri: string): this {\n this.props.resource_policy_uri = resource_policy_uri;\n return this;\n }\n\n /**\n * Builder method to add resource terms of service URI\n */\n withResourceTosUri(resource_tos_uri: string): this {\n this.props.resource_tos_uri = resource_tos_uri;\n return this;\n }\n\n /**\n * Builder method to enable TLS client certificate bound access tokens\n */\n withTlsClientCertificateBoundAccessTokens(tls_client_certificate_bound_access_tokens: boolean): this {\n this.props.tls_client_certificate_bound_access_tokens = tls_client_certificate_bound_access_tokens;\n return this;\n }\n\n /**\n * Builder method to add supported authorization details types\n */\n withAuthorizationDetailsTypesSupported(authorization_details_types_supported: string[]): this {\n this.props.authorization_details_types_supported = [...authorization_details_types_supported];\n return this;\n }\n\n /**\n * Builder method to add supported DPoP signing algorithms\n */\n withDpopSigningAlgValuesSupported(dpop_signing_alg_values_supported: string[]): this {\n this.props.dpop_signing_alg_values_supported = [...dpop_signing_alg_values_supported];\n return this;\n }\n\n /**\n * Builder method to require DPoP bound access tokens\n */\n withDpopBoundAccessTokensRequired(dpop_bound_access_tokens_required: boolean): this {\n this.props.dpop_bound_access_tokens_required = dpop_bound_access_tokens_required;\n return this;\n }\n\n\n}\n\nclass ProtectedResourceMetadata {\n readonly #resource: string;\n readonly #authorization_servers: string[];\n readonly #jwks_uri?: string;\n readonly #scopes_supported?: string[];\n readonly #bearer_methods_supported?: BearerMethod[];\n readonly #resource_signing_alg_values_supported?: SigningAlgorithm[];\n readonly #resource_documentation?: string;\n readonly #resource_policy_uri?: string;\n readonly #resource_tos_uri?: string;\n readonly #resource_name?: string;\n readonly #tls_client_certificate_bound_access_tokens?: boolean;\n readonly #authorization_details_types_supported?: string[];\n readonly #dpop_signing_alg_values_supported?: string[];\n readonly #dpop_bound_access_tokens_required?: boolean;\n\n constructor(builder: ProtectedResourceMetadataBuilder) {\n const props = builder.properties;\n this.#resource = props.resource;\n this.#authorization_servers = [...props.authorization_servers];\n this.#jwks_uri = props.jwks_uri;\n this.#scopes_supported = props.scopes_supported\n ? [...props.scopes_supported]\n : undefined;\n this.#bearer_methods_supported = props.bearer_methods_supported\n ? [...props.bearer_methods_supported]\n : undefined;\n this.#resource_signing_alg_values_supported = props.resource_signing_alg_values_supported\n ? [...props.resource_signing_alg_values_supported]\n : undefined;\n this.#resource_documentation = props.resource_documentation;\n this.#resource_policy_uri = props.resource_policy_uri;\n this.#resource_tos_uri = props.resource_tos_uri;\n this.#resource_name = props.resource_name;\n this.#tls_client_certificate_bound_access_tokens = props.tls_client_certificate_bound_access_tokens;\n this.#authorization_details_types_supported = props.authorization_details_types_supported\n ? [...props.authorization_details_types_supported]\n : undefined;\n this.#dpop_signing_alg_values_supported = props.dpop_signing_alg_values_supported\n ? [...props.dpop_signing_alg_values_supported]\n : undefined;\n this.#dpop_bound_access_tokens_required = props.dpop_bound_access_tokens_required;\n }\n\n /**\n * Convert to JSON representation\n */\n public toJSON(): IProtectedResourceMetadata {\n return {\n resource: this.#resource,\n authorization_servers: [...this.#authorization_servers],\n\n ...(this.#jwks_uri !== undefined && { jwks_uri: this.#jwks_uri }),\n ...(this.#scopes_supported !== undefined && {\n scopes_supported: [...this.#scopes_supported],\n }),\n ...(this.#bearer_methods_supported !== undefined && {\n bearer_methods_supported: [...this.#bearer_methods_supported],\n }),\n ...(this.#resource_signing_alg_values_supported !== undefined && {\n resource_signing_alg_values_supported: [...this.#resource_signing_alg_values_supported],\n }),\n ...(this.#resource_documentation !== undefined && {\n resource_documentation: this.#resource_documentation,\n }),\n ...(this.#resource_policy_uri !== undefined && {\n resource_policy_uri: this.#resource_policy_uri,\n }),\n ...(this.#resource_tos_uri !== undefined && {\n resource_tos_uri: this.#resource_tos_uri,\n }),\n ...(this.#resource_name !== undefined && {\n resource_name: this.#resource_name,\n }),\n ...(this.#tls_client_certificate_bound_access_tokens !== undefined && {\n tls_client_certificate_bound_access_tokens: this.#tls_client_certificate_bound_access_tokens,\n }),\n ...(this.#authorization_details_types_supported !== undefined && {\n authorization_details_types_supported: [...this.#authorization_details_types_supported],\n }),\n ...(this.#dpop_signing_alg_values_supported !== undefined && {\n dpop_signing_alg_values_supported: [...this.#dpop_signing_alg_values_supported],\n }),\n ...(this.#dpop_bound_access_tokens_required !== undefined && {\n dpop_bound_access_tokens_required: this.#dpop_bound_access_tokens_required,\n }),\n };\n }\n}\n","import { InvalidRequestError } from './errors.js';\n/**\n * Header-like object that can represent headers from different HTTP frameworks\n */\ntype HeadersLike = Record<string, unknown> & {\n authorization?: string;\n 'content-type'?: string;\n};\n\n/**\n * Query-like object for URL query parameters\n */\ntype QueryLike = Record<string, unknown> & { access_token?: string };\n\n/**\n * Body-like object for form-encoded request body\n */\ntype BodyLike = QueryLike;\n\n/**\n * Regular expression to match Bearer token in Authorization header\n */\nconst TOKEN_RE = /^Bearer (.+)$/i;\n\n/**\n * Extracts a Bearer token from HTTP request according to RFC 6750.\n * Supports all three methods defined in the RFC:\n * - Authorization header (Section 2.1)\n * - Form-encoded body parameter (Section 2.2)\n * - URI query parameter (Section 2.3)\n *\n * @param headers - HTTP headers object\n * @param query - Query parameters object (optional)\n * @param body - Request body object (optional)\n * @returns The extracted token string\n * @throws {InvalidRequestError} When no token is found or multiple methods are used\n *\n * @example\n * ```typescript\n * // Authorization header method (recommended)\n * const token1 = getToken({ authorization: 'Bearer mF_9.B5f-4.1JqM' });\n *\n * // Query parameter method\n * const token2 = getToken({}, { access_token: 'mF_9.B5f-4.1JqM' });\n *\n * // Form body method\n * const token3 = getToken(\n * { 'content-type': 'application/x-www-form-urlencoded' },\n * {},\n * { access_token: 'mF_9.B5f-4.1JqM' }\n * );\n *\n * // Express.js usage\n * const token4 = getToken(req.headers, req.query, req.body);\n * ```\n *\n * @see https://datatracker.ietf.org/doc/html/rfc6750#section-2 - RFC 6750 Section 2\n */\nexport function getToken(\n headers: HeadersLike,\n query?: QueryLike,\n body?: BodyLike\n): string {\n const fromHeader = getTokenFromHeader(headers);\n const fromQuery = getTokenFromQuery(query);\n const fromBody = getTokenFromBody(headers, body);\n\n if (!fromQuery && !fromHeader && !fromBody) {\n throw new InvalidRequestError('No Bearer token found in request');\n }\n\n // If multiple methods are used, throw an error\n if (+!!fromQuery + +!!fromBody + +!!fromHeader > 1) {\n throw new InvalidRequestError(\n 'More than one method used for authentication'\n );\n }\n\n return (fromQuery || fromBody || fromHeader) as string;\n}\n\n/**\n * Extract token from Authorization header\n */\nfunction getTokenFromHeader(headers: HeadersLike) {\n const authHeader = headers.authorization;\n if (typeof authHeader !== 'string') {\n return undefined;\n }\n\n const match = authHeader.match(TOKEN_RE);\n return match?.[1];\n}\n\n/**\n * Extract token from query parameters\n */\nfunction getTokenFromQuery(query?: QueryLike): string | undefined {\n const accessToken = query?.access_token;\n if (typeof accessToken === 'string') {\n return accessToken;\n }\n}\n\n/**\n * Extract token from form-encoded body\n */\nfunction getTokenFromBody(\n headers: HeadersLike,\n body?: BodyLike\n): string | undefined {\n if (!body || typeof body.access_token !== 'string') {\n return undefined;\n }\n\n const contentType = headers['content-type'];\n if (!contentType) {\n return undefined;\n }\n\n // Handle content-type with charset, e.g., \"application/x-www-form-urlencoded; charset=utf-8\"\n const isFormEncoded = contentType\n .toLowerCase()\n .includes('application/x-www-form-urlencoded');\n if (!isFormEncoded) {\n return undefined;\n }\n\n return body.access_token;\n}\n"],"mappings":"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","names":["BearerMethod","SigningAlgorithm","GrantType","import_auth0_auth_js"]} | ||
| {"version":3,"sources":["../src/index.ts","../src/api-client.ts","../src/errors.ts","../src/dpop-api.ts","../src/protected-resource-metadata.ts","../src/token.ts"],"sourcesContent":["export { ApiClient } from './api-client.js';\nexport * from './protected-resource-metadata.js';\nexport * from './errors.js';\nexport * from './types.js';\nexport { getToken } from './token.js';\nexport type { QueryLike, HeadersLike, BodyLike } from './token.js';\n\n// Re-export shared errors from auth0-auth-js for convenience\nexport {\n MissingClientAuthError,\n TokenExchangeError,\n} from '@auth0/auth0-auth-js';\n","import * as oauth from 'oauth4webapi';\nimport { createRemoteJWKSet, jwtVerify, customFetch } from 'jose';\nimport { AuthClient, TokenForConnectionError, MissingClientAuthError } from '@auth0/auth0-auth-js';\nimport {\n AccessTokenForConnectionOptions,\n ApiClientOptions,\n ConnectionTokenSet,\n DPoPOptions,\n ExchangeProfileOptions,\n TokenExchangeProfileResult,\n VerifyAccessTokenOptions,\n} from './types.js';\nimport {\n AuthError,\n InvalidConfigurationError,\n InvalidDpopProofError,\n InvalidRequestError,\n MissingRequiredArgumentError,\n VerifyAccessTokenError,\n} from './errors.js';\nimport { ALLOWED_DPOP_ALGORITHMS, buildChallenges, verifyDpopProof } from './dpop-api.js';\n\nexport class ApiClient {\n #serverMetadata: oauth.AuthorizationServer | undefined;\n readonly #options: ApiClientOptions;\n #jwks?: ReturnType<typeof createRemoteJWKSet>;\n readonly #authClient: AuthClient | undefined;\n\n constructor(options: ApiClientOptions) {\n if (options.dpop !== undefined && (typeof options.dpop !== 'object' || options.dpop === null)) {\n throw new InvalidConfigurationError('Invalid DPoP configuration: \"dpop\" must be an object');\n }\n\n if (options.dpop) {\n const { mode, iatOffset, iatLeeway } = options.dpop;\n if (mode !== undefined && !['allowed', 'required', 'disabled'].includes(mode)) {\n throw new InvalidConfigurationError(\n 'Invalid DPoP configuration: \"mode\" must be allowed, required, or disabled'\n );\n }\n if (iatOffset !== undefined) {\n if (!Number.isFinite(iatOffset)) {\n throw new InvalidConfigurationError('Invalid DPoP configuration: \"iatOffset\" must be a number');\n }\n if (iatOffset < 0) {\n throw new InvalidConfigurationError('Invalid DPoP configuration: \"iatOffset\" must be a non-negative number');\n }\n }\n if (iatLeeway !== undefined) {\n if (!Number.isFinite(iatLeeway)) {\n throw new InvalidConfigurationError('Invalid DPoP configuration: \"iatLeeway\" must be a number');\n }\n if (iatLeeway < 0) {\n throw new InvalidConfigurationError('Invalid DPoP configuration: \"iatLeeway\" must be a non-negative number');\n }\n }\n }\n\n this.#options = options;\n\n if (options.clientId) {\n this.#authClient = new AuthClient({\n domain: options.domain,\n clientId: options.clientId,\n clientSecret: options.clientSecret,\n clientAssertionSigningKey: options.clientAssertionSigningKey,\n clientAssertionSigningAlg: options.clientAssertionSigningAlg,\n customFetch: options.customFetch,\n });\n }\n\n if (!this.#options.audience) {\n throw new MissingRequiredArgumentError('audience');\n }\n }\n\n /**\n * Initialized the SDK by performing Metadata Discovery.\n */\n async #discover() {\n if (this.#serverMetadata) {\n return {\n serverMetadata: this.#serverMetadata,\n };\n }\n\n const issuer = new URL(`https://${this.#options.domain}`);\n const response = await oauth.discoveryRequest(issuer, {\n [oauth.customFetch]: this.#options.customFetch,\n });\n\n this.#serverMetadata = await oauth.processDiscoveryResponse(issuer, response);\n\n return {\n serverMetadata: this.#serverMetadata,\n };\n }\n\n /**\n * Verifies the provided access token against the ApiClient's configured audience.\n *\n * This method validates the JWT signature using the Auth0 tenant's JWKS and verifies\n * standard claims including issuer, expiration, and issued-at time. The audience claim\n * is verified against the audience configured when constructing the ApiClient.\n *\n * DPoP support:\n * - `dpop.mode` controls behavior: `allowed` (default) accepts Bearer or DPoP; `required` enforces DPoP; `disabled` ignores DPoP.\n * - When validating a DPoP-bound token, you must provide `scheme: 'dpop'`, the `dpopProof` header value, and the actual `httpMethod`/`httpUrl` used for the request.\n * - Bearer tokens omit DPoP params; DPoP params are validated together and proof binding is enforced.\n *\n * @param options Options containing the access token and optional required claims.\n * @see README.md and EXAMPLES.md for usage in allowed/required/disabled modes.\n * @returns Promise resolving to the verified token payload containing all JWT claims.\n * @throws {VerifyAccessTokenError} When verification fails due to invalid signature,\n * expired token, mismatched audience, or missing required claims.\n *\n * @example\n * ```typescript\n * @example Bearer token validation\n * const apiClient = new ApiClient({\n * domain: 'example.auth0.com',\n * audience: 'https://api.example.com', // This audience is used for verification\n * });\n * const payload = await apiClient.verifyAccessToken({\n * accessToken: 'eyJhbGc...',\n * });\n *\n * @example DPoP-bound token validation (allowed/required mode)\n * const apiClient = new ApiClient({\n * domain: 'example.auth0.com',\n * audience: 'https://api.example.com',\n * dpop: { mode: 'required' }, // default is 'allowed'\n * });\n * const dpopPayload = await apiClient.verifyAccessToken({\n * accessToken: 'eyJhbGc...', // JWT with cnf.jkt claim\n * scheme: 'dpop',\n * dpopProof: 'eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3A...', // value from DPoP header\n * httpMethod: 'GET', // actual request method\n * httpUrl: 'https://api.example.com/resource', // actual request URL\n * });\n * ```\n */\n async verifyAccessToken(options: VerifyAccessTokenOptions) {\n const mode: NonNullable<DPoPOptions['mode']> = this.#options.dpop?.mode ?? 'allowed';\n // Default timing options\n const iatOffset = this.#options.dpop?.iatOffset ?? 300;\n const iatLeeway = this.#options.dpop?.iatLeeway ?? 30;\n\n // Normalize scheme to lowercase; default to 'bearer' if not provided.\n const scheme = (options.scheme ?? 'bearer').toLowerCase();\n const dpopProof = options.dpopProof;\n const httpMethod = options.httpMethod;\n const httpUrl = options.httpUrl;\n const hasDpopParams = dpopProof !== undefined || httpMethod !== undefined || httpUrl !== undefined;\n\n // When DPoP is enabled, only 'bearer' and 'dpop' schemes are allowed.\n if (mode !== 'disabled' && scheme && !['bearer', 'dpop'].includes(scheme)) {\n const err = new InvalidRequestError('');\n err.cause = { code: 'invalid_auth_scheme' };\n throw this.#addChallenges(err, mode, scheme, { includeError: false });\n }\n\n // When DPoP is required, only 'dpop' scheme is allowed.\n if (mode === 'required' && scheme !== 'dpop') {\n const err = new InvalidRequestError('');\n err.cause = { code: 'invalid_auth_scheme' };\n throw this.#addChallenges(err, mode, scheme, {\n includeError: false,\n dpopSpecific: true,\n });\n }\n\n // When DPoP is disabled, only 'bearer' scheme is allowed.\n if (mode === 'disabled' && scheme && scheme !== 'bearer') {\n const err = new InvalidRequestError('');\n err.cause = { code: 'invalid_auth_scheme' };\n throw this.#addChallenges(err, mode, scheme, { includeError: false });\n }\n\n // When `scheme` is not provided, but `dpopProof`, `httpMethod`, or `httpUrl` are present.\n if (mode !== 'disabled' && hasDpopParams && options.scheme === undefined) {\n const err = new InvalidRequestError('');\n err.cause = { code: 'invalid_auth_scheme' };\n throw this.#addChallenges(err, mode, scheme, {\n includeError: false,\n dpopSpecific: true,\n });\n }\n\n // Access token must always be present.\n if (typeof options.accessToken !== 'string' || !options.accessToken) {\n throw this.#addChallenges(new VerifyAccessTokenError(''), mode, scheme, { includeError: false });\n }\n\n const { serverMetadata } = await this.#discover();\n\n this.#jwks ||= createRemoteJWKSet(new URL(serverMetadata!.jwks_uri!), {\n [customFetch]: this.#options.customFetch,\n });\n\n try {\n const { payload } = await jwtVerify(options.accessToken, this.#jwks, {\n issuer: this.#serverMetadata!.issuer,\n audience: this.#options.audience,\n algorithms: ['RS256'],\n requiredClaims: ['iat', 'exp', ...(options.requiredClaims || [])],\n });\n\n let cnfJkt: string | undefined;\n const cnf = (payload as Record<string, unknown> & { cnf?: unknown }).cnf;\n\n // Extract `jkt` from `cnf` claim if present\n if (cnf && typeof cnf === 'object') {\n const maybeJkt = (cnf as Record<string, unknown>).jkt;\n if (typeof maybeJkt === 'string') {\n cnfJkt = maybeJkt;\n }\n }\n\n const hasProof = typeof dpopProof === 'string';\n\n // DPoP validation logic\n if (mode !== 'disabled' && scheme === 'bearer' && hasProof && !cnfJkt) {\n throw this.#addChallenges(\n new InvalidRequestError('DPoP proof requires the DPoP authentication scheme, not Bearer'),\n mode,\n scheme\n );\n }\n\n // Determine if DPoP verification is needed\n const shouldVerifyDpop =\n mode !== 'disabled' && (mode === 'required' || scheme === 'dpop' || hasProof || !!cnfJkt);\n\n // Enforce DPoP binding when `cnf.jkt`\n if (mode !== 'disabled' && scheme === 'dpop' && !cnfJkt) {\n const err = new VerifyAccessTokenError('JWT Access Token has no jkt confirmation claim');\n err.cause = { code: 'dpop_binding_mismatch' };\n throw this.#addChallenges(err, mode, scheme, { dpopSpecific: true });\n }\n\n // Enforce scheme when token is DPoP-bound\n if (scheme === 'bearer' && cnfJkt && mode !== 'disabled') {\n throw this.#addChallenges(\n new VerifyAccessTokenError('DPoP-bound token requires the DPoP authentication scheme, not Bearer'),\n mode,\n scheme\n );\n }\n\n // If DPoP verification is not needed, return the payload early.\n if (!shouldVerifyDpop) {\n return payload;\n }\n\n // Validate DPoP proof presence and related params\n if (!dpopProof) {\n throw this.#addChallenges(new InvalidRequestError(''), mode, scheme, {\n dpopSpecific: true,\n includeError: false,\n });\n }\n\n // Validate HTTP method and URL presence\n if (typeof httpMethod !== 'string' || !httpMethod) {\n throw this.#addChallenges(\n new InvalidRequestError('HTTP method is required for DPoP validation'),\n mode,\n scheme,\n { dpopSpecific: true }\n );\n }\n\n // Validate HTTP URL presence\n if (typeof httpUrl !== 'string' || !httpUrl) {\n throw this.#addChallenges(new InvalidRequestError('HTTP URL is required for DPoP validation'), mode, scheme, {\n dpopSpecific: true,\n });\n }\n\n // Perform DPoP proof verification\n try {\n await verifyDpopProof({\n proof: dpopProof,\n accessToken: options.accessToken,\n method: httpMethod,\n url: httpUrl,\n cnfJkt,\n iatOffset,\n iatLeeway,\n algorithms: ALLOWED_DPOP_ALGORITHMS,\n });\n } catch (err) {\n if (\n err instanceof VerifyAccessTokenError ||\n err instanceof InvalidDpopProofError ||\n err instanceof InvalidRequestError\n ) {\n // Handle DPoP-specific errors with appropriate challenges\n throw this.#addChallenges(err as Error, mode, scheme, { dpopSpecific: true });\n }\n throw err;\n }\n\n return payload;\n } catch (e) {\n if (e instanceof AuthError) {\n throw e;\n }\n const message = e instanceof Error ? e.message : String(e);\n const err = new VerifyAccessTokenError(message);\n throw this.#addChallenges(err, mode, scheme);\n }\n }\n\n #addChallenges<T extends Error & { code?: string; headers?: Record<string, string | string[]> }>(\n err: T,\n mode: NonNullable<DPoPOptions['mode']>,\n scheme: string,\n params?: { dpopSpecific?: boolean; includeError?: boolean; target?: 'bearer' | 'dpop' }\n ) {\n const authErr = err;\n if (!authErr.headers) {\n const includeError = params?.includeError ?? true;\n const target = params?.target ?? (params?.dpopSpecific === true ? 'dpop' : scheme === 'dpop' ? 'dpop' : 'bearer');\n let challengeCode = authErr.code;\n if (authErr instanceof VerifyAccessTokenError) {\n challengeCode = 'invalid_token';\n } else if (authErr instanceof InvalidRequestError) {\n challengeCode = 'invalid_request';\n } else if (authErr instanceof InvalidDpopProofError) {\n challengeCode = 'invalid_dpop_proof';\n }\n const challengeParams =\n includeError && target === 'dpop'\n ? { dpopError: challengeCode, dpopErrorDescription: authErr.message }\n : includeError && target === 'bearer'\n ? { error: challengeCode, errorDescription: authErr.message }\n : {};\n authErr.headers = buildChallenges(mode, ALLOWED_DPOP_ALGORITHMS, challengeParams);\n }\n return authErr;\n }\n\n /**\n * Retrieves an access token for a connection.\n *\n * @param options - Options for retrieving an access token for a connection.\n *\n * @throws {TokenForConnectionError} If there was an issue requesting the access token.\n *\n * @returns The Connection Token Set, containing the access token for the connection, as well as additional information.\n */\n public async getAccessTokenForConnection(options: AccessTokenForConnectionOptions): Promise<ConnectionTokenSet> {\n if (!this.#authClient) {\n throw new TokenForConnectionError('Client credentials are required to use getAccessTokenForConnection');\n }\n\n const tokenEndpointResponse = await this.#authClient.getTokenForConnection({\n connection: options.connection,\n loginHint: options.loginHint,\n accessToken: options.accessToken,\n });\n\n return {\n accessToken: tokenEndpointResponse.accessToken,\n scope: tokenEndpointResponse.scope,\n expiresAt: tokenEndpointResponse.expiresAt,\n connection: options.connection,\n loginHint: options.loginHint,\n };\n }\n\n /**\n * Exchanges a token via a Custom Token Exchange Profile for a different API audience while preserving user identity (RFC 8693).\n *\n * This method supports **Custom Token Exchange** for custom token types via a configured Token Exchange Profile.\n *\n * For **Access Token Exchange with Token Vault** (external provider's access tokens), use {@link getAccessTokenForConnection} instead.\n *\n * **Note**: This method requires a confidential client (client credentials must be configured).\n * While Custom Token Exchange Early Access technically permits public clients, this implementation\n * currently requires client authentication. Public client support may be added in a future release.\n *\n * @param subjectToken - The raw token to be exchanged (without \"Bearer \" prefix)\n * @param options - Configuration for the token exchange\n *\n * @returns A promise that resolves with the {@link TokenExchangeProfileResult}\n *\n * @throws {TokenExchangeError} When client credentials are not configured or exchange fails\n *\n * @see {@link https://auth0.com/docs/authenticate/custom-token-exchange Custom Token Exchange Documentation}\n *\n * @example\n * ```typescript\n * // Exchange custom token (organization is optional)\n * const result = await apiClient.getTokenByExchangeProfile(\n * userToken,\n * {\n * subjectTokenType: 'urn:example:custom-token',\n * audience: 'https://api.backend.com',\n * organization: 'org_abc123', // Optional - Organization ID or name\n * scope: 'read:data write:data',\n * }\n * );\n * // When organization is provided, the access token will include the organization ID in its payload\n * ```\n */\n public async getTokenByExchangeProfile(\n subjectToken: string,\n options: ExchangeProfileOptions\n ): Promise<TokenExchangeProfileResult> {\n if (!this.#authClient) {\n throw new MissingClientAuthError();\n }\n\n const response = await this.#authClient.exchangeToken({\n subjectTokenType: options.subjectTokenType,\n subjectToken,\n audience: options.audience,\n scope: options.scope,\n requestedTokenType: options.requestedTokenType,\n organization: options.organization,\n });\n\n return {\n accessToken: response.accessToken,\n expiresAt: response.expiresAt,\n ...(response.scope && { scope: response.scope }),\n ...(response.idToken && { idToken: response.idToken }),\n ...(response.refreshToken && { refreshToken: response.refreshToken }),\n ...(response.tokenType && { tokenType: response.tokenType }),\n ...(response.issuedTokenType && { issuedTokenType: response.issuedTokenType }),\n };\n }\n}\n","/**\n * Error thrown when a required argument is missing.\n */\nexport class MissingRequiredArgumentError extends Error {\n public code: string = 'missing_required_argument_error';\n\n constructor(argument: string) {\n super(`The argument '${argument}' is required but was not provided.`);\n this.name = 'MissingRequiredArgumentError';\n }\n}\n\n/**\n * Error thrown when the SDK is misconfigured at instantiation time.\n */\nexport class InvalidConfigurationError extends Error {\n public code: string = 'invalid_configuration_error';\n constructor(message: string) {\n super(message);\n this.name = 'InvalidConfigurationError';\n }\n}\n\n/**\n * Base authentication error shape used across the SDK.\n */\nexport class AuthError extends Error {\n public code: string;\n public statusCode?: number;\n public headers?: Record<string, string | string[]>;\n public declare cause?: AuthErrorCause;\n\n constructor(message: string, code: string, statusCode?: number, headers?: Record<string, string | string[]>) {\n super(message);\n this.name = this.constructor.name;\n this.code = code;\n this.statusCode = statusCode;\n this.headers = headers;\n }\n}\n\nexport type AuthErrorCause = {\n code: string;\n};\n\n/**\n * Error thrown when the transaction is missing.\n */\nexport class MissingTransactionError extends AuthError {\n constructor(message?: string) {\n super(message ?? 'The transaction is missing.', 'missing_transaction_error');\n }\n}\n\n/**\n * Error thrown when verifying the access token.\n */\nexport class VerifyAccessTokenError extends AuthError {\n constructor(message: string, headers?: Record<string, string | string[]>) {\n super(message, 'verify_access_token_error', 401, headers);\n }\n}\n\n/**\n * Error thrown when the DPoP proof fails validation.\n */\nexport class InvalidDpopProofError extends AuthError {\n constructor(message = '', headers?: Record<string, string>) {\n super(message, 'invalid_dpop_proof', 400, headers);\n }\n}\n\n/**\n * Error thrown when request is missing a valid token or\n * multiple auth methods used\n */\nexport class InvalidRequestError extends AuthError {\n constructor(message: string, headers?: Record<string, string>) {\n super(message, 'invalid_request', 400, headers);\n }\n}\n","import { createHash } from 'crypto';\nimport {\n EmbeddedJWK,\n base64url,\n calculateJwkThumbprint,\n jwtVerify,\n type JWK,\n type JWTHeaderParameters,\n type JWTPayload,\n} from 'jose';\nimport { InvalidDpopProofError, InvalidRequestError, VerifyAccessTokenError } from './errors.js';\n\nexport type ChallengeParams = {\n error?: string;\n errorDescription?: string;\n dpopError?: string;\n dpopErrorDescription?: string;\n};\n\nexport type DPoPVerificationOptions = {\n proof: string;\n accessToken: string;\n method: string;\n url: string;\n cnfJkt?: string;\n iatOffset: number;\n iatLeeway: number;\n algorithms: readonly string[];\n};\n\nexport const DPOP_ERROR_MESSAGES = {\n PROOF_VERIFICATION_FAILED: 'Failed to verify DPoP proof',\n MISSING_PROOF: 'Missing DPoP proof',\n MULTIPLE_PROOFS: 'Multiple DPoP proofs are not allowed',\n MISSING_CNF_JKT: 'Access token is missing cnf.jkt confirmation claim',\n INVALID_IAT: '\"iat\" claim must be a number',\n INVALID_JTI: '\"jti\" claim must be a string',\n INVALID_HTM: '\"htm\" claim must be a string',\n INVALID_HTU: '\"htu\" claim must be a string',\n INVALID_HTU_URL: '\"htu\" claim URL must be valid URL',\n INVALID_HTU_URL_HOST: 'Invalid \"htu\" claim URL: Host contains illegal characters or format',\n INVALID_HTU_URL_PATH: 'Invalid \"htu\" claim URL: Path must not start with \"//\"',\n INVALID_HTTP_URL: '\"httpUrl\" must be a valid URL',\n INVALID_HTTP_URL_HOST: 'Invalid \"httpUrl\": Host contains illegal characters or format',\n INVALID_HTTP_URL_PATH: 'Invalid \"httpUrl\": Path must not start with \"//\"',\n INVALID_ATH: '\"ath\" claim must be a string',\n IAT_MISMATCH: 'DPoP proof \"iat\" is outside the acceptable range',\n HTM_MISMATCH: 'DPoP proof \"htm\" mismatch',\n HTU_MISMATCH: 'DPoP proof \"htu\" mismatch',\n ATH_MISMATCH: 'DPoP proof \"ath\" mismatch',\n JWT_AT_MISMATCH: 'JWT Access Token confirmation mismatch',\n MISSING_JWK: 'Missing or invalid jwk in DPoP proof header',\n PRIVATE_KEY_MATERIAL: 'DPoP proof header must not contain private key material',\n};\n\n// Currently, only ES256 is supported.\nexport const ALLOWED_DPOP_ALGORITHMS = ['ES256'] as const;\n\nfunction normalizePercentEncodings(s: string): string {\n const UNRESERVED = /[A-Za-z0-9\\-._~]/;\n return s.replace(/%[0-9a-fA-F]{2}/g, (m) => {\n const byte = parseInt(m.slice(1), 16);\n const ch = String.fromCharCode(byte);\n return UNRESERVED.test(ch) ? ch : `%${m.slice(1).toUpperCase()}`;\n });\n}\n\n/**\n * Normalize a URL for DPoP `htu` comparison.\n *\n * Behavior:\n * - Parses with WHATWG `URL`; rejects invalid input.\n * - Host must be a valid hostname with optional `:port`; no schemes, slashes, queries, or fragments allowed.\n * - For `source === 'request'`: path must start with `/` and not look like a protocol.\n * - Removes query and fragment.\n * - Normalizes percent-encodings in the path.\n * - Returns `origin + pathname` for reliable comparison.\n *\n * @param input - The URL to normalize (either the inbound request URL or the `htu` claim).\n * @param source - Indicates whether `input` is from the HTTP request (`'request'`) or the DPoP proof (`'proof'`).\n * @returns The normalized URL string in the form `origin + pathname` (no query or fragment).\n * @throws {InvalidRequestError} When `source === 'request'` and parsing/validation fails.\n * @throws {InvalidDPoPProofError} When `source === 'proof'` and parsing/validation fails.\n */\nexport function normalizeUrl(input: string, source: 'request' | 'proof'): string {\n const HOST_RE = /^(?:[A-Za-z0-9.-]+|\\[[0-9A-Fa-f:.]+\\])(?::\\d{1,5})?$/;\n const PROTOCOL_IN_PATH_RE = /^\\/[a-z][a-z0-9+.-]*:\\/\\//i;\n\n try {\n const url = new URL(input);\n const host = url.host;\n\n if (\n typeof host !== 'string' ||\n host.length === 0 ||\n host.includes('://') ||\n host.includes('/') ||\n host.includes('?') ||\n host.includes('#') ||\n !HOST_RE.test(host)\n ) {\n if (source === 'request') {\n throw new InvalidRequestError(DPOP_ERROR_MESSAGES.INVALID_HTTP_URL_HOST);\n } else {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTU_URL_HOST);\n }\n }\n\n if (source === 'request') {\n const path = url.pathname;\n if (PROTOCOL_IN_PATH_RE.test(path)) {\n throw new InvalidRequestError(DPOP_ERROR_MESSAGES.INVALID_HTTP_URL_PATH);\n }\n }\n\n url.search = '';\n url.hash = '';\n url.pathname = normalizePercentEncodings(url.pathname);\n\n return url.origin + url.pathname;\n } catch (err) {\n if (source === 'request') {\n if (err instanceof InvalidRequestError) throw err;\n throw new InvalidRequestError(DPOP_ERROR_MESSAGES.INVALID_HTTP_URL);\n }\n if (err instanceof InvalidDpopProofError) throw err;\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTU_URL);\n }\n}\n\nasync function verifyProofJwt(\n proof: string,\n algorithms: readonly string[]\n): Promise<{ header: JWTHeaderParameters; claims: JWTPayload }> {\n try {\n const { payload, protectedHeader } = await jwtVerify(proof, EmbeddedJWK, {\n typ: 'dpop+jwt',\n algorithms: [...algorithms],\n });\n\n return { header: protectedHeader, claims: payload };\n } catch (err) {\n let message = DPOP_ERROR_MESSAGES.PROOF_VERIFICATION_FAILED;\n if (err instanceof Error && err.message) {\n message = err.message;\n }\n throw new InvalidDpopProofError(message);\n }\n}\n\nexport async function verifyDpopProof(options: DPoPVerificationOptions): Promise<void> {\n const { proof, accessToken, method, url, cnfJkt, iatOffset, iatLeeway, algorithms } = options;\n\n if (!proof) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.MISSING_PROOF);\n }\n\n if (proof.includes(',')) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.MULTIPLE_PROOFS);\n }\n\n if (!cnfJkt) {\n const err = new VerifyAccessTokenError(DPOP_ERROR_MESSAGES.MISSING_CNF_JKT);\n err.cause = { code: 'dpop_binding_mismatch' };\n throw err;\n }\n\n const normalizedRequestUrl = normalizeUrl(url, 'request');\n const { claims, header } = await verifyProofJwt(proof, algorithms);\n\n const { htm, htu, iat, ath, jti } = claims;\n\n if (typeof jti !== 'string' || !jti) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_JTI);\n }\n\n // Verify `iat` claim is present and is a number. This is redundant with `jose` but we double-check here.\n if (typeof iat !== 'number') {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_IAT);\n }\n\n const now = Math.floor(Date.now() / 1000);\n if (iat < now - iatOffset || iat > now + iatLeeway) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.IAT_MISMATCH);\n }\n\n if (typeof htm !== 'string') {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTM);\n }\n\n if (htm.toUpperCase() !== method.toUpperCase()) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.HTM_MISMATCH);\n }\n\n if (typeof htu !== 'string') {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTU);\n }\n\n const normalizedProofUrl = normalizeUrl(htu, 'proof');\n if (normalizedProofUrl !== normalizedRequestUrl) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.HTU_MISMATCH);\n }\n\n if (typeof ath !== 'string') {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_ATH);\n }\n\n const hash = createHash('sha256').update(accessToken).digest();\n const encodedHash = base64url.encode(hash);\n if (ath !== encodedHash) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.ATH_MISMATCH);\n }\n\n // Verify the JWK is not malformed. This is redundant with `jose` but we double-check here.\n const jwk = header.jwk as JWK | undefined;\n if (!jwk || typeof jwk !== 'object') {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.MISSING_JWK);\n }\n\n // Ensure the JWK does not contain private key material. This is redundant with `jose` but we double-check here.\n if ('d' in jwk) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.PRIVATE_KEY_MATERIAL);\n }\n\n const thumbprint = await calculateJwkThumbprint(jwk);\n if (thumbprint !== cnfJkt) {\n const err = new VerifyAccessTokenError(DPOP_ERROR_MESSAGES.JWT_AT_MISMATCH);\n err.cause = { code: 'dpop_binding_mismatch' };\n throw err;\n }\n}\n\nexport function buildChallenges(\n dpopMode: 'allowed' | 'required' | 'disabled',\n algorithms: readonly string[] = ALLOWED_DPOP_ALGORITHMS,\n params: ChallengeParams = {}\n): Record<string, string | string[]> {\n const bearerParams = [\n 'realm=\"api\"',\n params.error ? `error=\"${params.error}\"` : undefined,\n params.errorDescription ? `error_description=\"${params.errorDescription}\"` : undefined,\n ]\n .filter(Boolean)\n .join(', ');\n\n const dpopParams = [\n params.dpopError ? `error=\"${params.dpopError}\"` : undefined,\n params.dpopErrorDescription ? `error_description=\"${params.dpopErrorDescription}\"` : undefined,\n `algs=\"${algorithms.join(' ')}\"`,\n ]\n .filter(Boolean)\n .join(', ');\n\n const bearerValue = `Bearer ${bearerParams}`;\n const dpopValue = `DPoP ${dpopParams}`;\n\n const challenges: string[] = [];\n\n if (dpopMode === 'allowed') {\n challenges.push(bearerValue, dpopValue);\n } else if (dpopMode === 'required') {\n challenges.push(dpopValue);\n } else {\n challenges.push(bearerValue);\n }\n\n return {\n 'www-authenticate': challenges,\n };\n}\n","/**\n * RFC 9728 - OAuth 2.0 Protected Resource Metadata\n * https://datatracker.ietf.org/doc/html/rfc9728\n */\n\nimport { MissingRequiredArgumentError } from \"./errors.js\";\n\n/**\n * Supported methods of sending an OAuth 2.0 bearer token\n */\nexport enum BearerMethod {\n HEADER = \"header\",\n BODY = \"body\",\n QUERY = \"query\",\n}\n\n/**\n * Supported signing algorithms\n */\nexport enum SigningAlgorithm {\n RS256 = \"RS256\",\n RS384 = \"RS384\",\n RS512 = \"RS512\",\n ES256 = \"ES256\",\n ES384 = \"ES384\",\n ES512 = \"ES512\",\n PS256 = \"PS256\",\n PS384 = \"PS384\",\n PS512 = \"PS512\",\n HS256 = \"HS256\",\n HS384 = \"HS384\",\n HS512 = \"HS512\",\n}\n\n/**\n * Grant types supported\n */\nexport enum GrantType {\n AUTHORIZATION_CODE = \"authorization_code\",\n IMPLICIT = \"implicit\",\n PASSWORD = \"password\",\n CLIENT_CREDENTIALS = \"client_credentials\",\n REFRESH_TOKEN = \"refresh_token\",\n JWT_BEARER = \"urn:ietf:params:oauth:grant-type:jwt-bearer\",\n SAML2_BEARER = \"urn:ietf:params:oauth:grant-type:saml2-bearer\",\n DEVICE_CODE = \"urn:ietf:params:oauth:grant-type:device_code\",\n}\n\n/**\n * Interface for Protected Resource Metadata\n */\nexport interface IProtectedResourceMetadata {\n resource: string;\n authorization_servers: string[];\n jwks_uri?: string;\n scopes_supported?: string[];\n bearer_methods_supported?: BearerMethod[];\n resource_signing_alg_values_supported?: SigningAlgorithm[];\n resource_name?: string;\n resource_documentation?: string;\n resource_policy_uri?: string;\n resource_tos_uri?: string;\n tls_client_certificate_bound_access_tokens?: boolean;\n authorization_details_types_supported?: string[];\n dpop_signing_alg_values_supported?: string[];\n dpop_bound_access_tokens_required?: boolean;\n}\n\n/**\n * Builder for creating a ProtectedResourceMetadata instance\n *\n * @example\n * ```typescript\n * const metadata = new ProtectedResourceMetadataBuilder('https://api.example.com', ['https://auth.example.com'])\n * .withJwksUri('https://api.example.com/.well-known/jwks.json')\n * .withScopesSupported(['read', 'write'])\n * .build();\n * // serialize to json\n * const json = metadata.toJSON();\n * ```\n */\nexport class ProtectedResourceMetadataBuilder {\n private readonly props: Partial<IProtectedResourceMetadata> &\n Pick<IProtectedResourceMetadata, \"resource\" | \"authorization_servers\">;\n\n /**\n * Constructor for the builder\n * @param resource - The protected resource identifier (REQUIRED)\n * @param authorization_servers - Array of authorization server URLs (REQUIRED)\n */\n constructor(resource: string, authorization_servers: string[]) {\n if (!resource?.trim()) {\n throw new MissingRequiredArgumentError(\"resource\");\n }\n if (\n !Array.isArray(authorization_servers) ||\n authorization_servers.length === 0\n ) {\n throw new MissingRequiredArgumentError(\"authorization_servers\");\n }\n this.props = { resource, authorization_servers };\n }\n\n get properties(): IProtectedResourceMetadata {\n return this.props;\n }\n\n /**\n * Builds the ProtectedResourceMetadata\n */\n public build() {\n return new ProtectedResourceMetadata(this);\n }\n\n /**\n * Builder method to add JWKS URI\n */\n withJwksUri(jwks_uri: string): this {\n this.props.jwks_uri = jwks_uri;\n return this;\n }\n\n /**\n * Builder method to add supported scopes\n */\n withScopesSupported(scopes_supported: string[]): this {\n this.props.scopes_supported = [...scopes_supported];\n return this;\n }\n\n /**\n * Builder method to add supported bearer methods\n */\n withBearerMethodsSupported(\n bearer_methods_supported: BearerMethod[]\n ): this {\n this.props.bearer_methods_supported = [...bearer_methods_supported];\n return this;\n }\n\n /**\n * Builder method to add supported resource signing algorithms\n */\n withResourceSigningAlgValuesSupported(\n resource_signing_alg_values_supported: SigningAlgorithm[]\n ): this {\n this.props.resource_signing_alg_values_supported = [...resource_signing_alg_values_supported];\n return this;\n }\n\n /**\n * Builder method to add resource_name\n */\n withResourceName(resource_name: string): this {\n this.props.resource_name = resource_name;\n return this;\n }\n\n /**\n * Builder method to add resource documentation URL\n */\n withResourceDocumentation(resource_documentation: string): this {\n this.props.resource_documentation = resource_documentation;\n return this;\n }\n\n /**\n * Builder method to add resource policy URI\n */\n withResourcePolicyUri(resource_policy_uri: string): this {\n this.props.resource_policy_uri = resource_policy_uri;\n return this;\n }\n\n /**\n * Builder method to add resource terms of service URI\n */\n withResourceTosUri(resource_tos_uri: string): this {\n this.props.resource_tos_uri = resource_tos_uri;\n return this;\n }\n\n /**\n * Builder method to enable TLS client certificate bound access tokens\n */\n withTlsClientCertificateBoundAccessTokens(tls_client_certificate_bound_access_tokens: boolean): this {\n this.props.tls_client_certificate_bound_access_tokens = tls_client_certificate_bound_access_tokens;\n return this;\n }\n\n /**\n * Builder method to add supported authorization details types\n */\n withAuthorizationDetailsTypesSupported(authorization_details_types_supported: string[]): this {\n this.props.authorization_details_types_supported = [...authorization_details_types_supported];\n return this;\n }\n\n /**\n * Builder method to add supported DPoP signing algorithms\n */\n withDpopSigningAlgValuesSupported(dpop_signing_alg_values_supported: string[]): this {\n this.props.dpop_signing_alg_values_supported = [...dpop_signing_alg_values_supported];\n return this;\n }\n\n /**\n * Builder method to require DPoP bound access tokens\n */\n withDpopBoundAccessTokensRequired(dpop_bound_access_tokens_required: boolean): this {\n this.props.dpop_bound_access_tokens_required = dpop_bound_access_tokens_required;\n return this;\n }\n\n\n}\n\nexport class ProtectedResourceMetadata {\n readonly #resource: string;\n readonly #authorization_servers: string[];\n readonly #jwks_uri?: string;\n readonly #scopes_supported?: string[];\n readonly #bearer_methods_supported?: BearerMethod[];\n readonly #resource_signing_alg_values_supported?: SigningAlgorithm[];\n readonly #resource_documentation?: string;\n readonly #resource_policy_uri?: string;\n readonly #resource_tos_uri?: string;\n readonly #resource_name?: string;\n readonly #tls_client_certificate_bound_access_tokens?: boolean;\n readonly #authorization_details_types_supported?: string[];\n readonly #dpop_signing_alg_values_supported?: string[];\n readonly #dpop_bound_access_tokens_required?: boolean;\n\n constructor(builder: ProtectedResourceMetadataBuilder) {\n const props = builder.properties;\n this.#resource = props.resource;\n this.#authorization_servers = [...props.authorization_servers];\n this.#jwks_uri = props.jwks_uri;\n this.#scopes_supported = props.scopes_supported\n ? [...props.scopes_supported]\n : undefined;\n this.#bearer_methods_supported = props.bearer_methods_supported\n ? [...props.bearer_methods_supported]\n : undefined;\n this.#resource_signing_alg_values_supported = props.resource_signing_alg_values_supported\n ? [...props.resource_signing_alg_values_supported]\n : undefined;\n this.#resource_documentation = props.resource_documentation;\n this.#resource_policy_uri = props.resource_policy_uri;\n this.#resource_tos_uri = props.resource_tos_uri;\n this.#resource_name = props.resource_name;\n this.#tls_client_certificate_bound_access_tokens = props.tls_client_certificate_bound_access_tokens;\n this.#authorization_details_types_supported = props.authorization_details_types_supported\n ? [...props.authorization_details_types_supported]\n : undefined;\n this.#dpop_signing_alg_values_supported = props.dpop_signing_alg_values_supported\n ? [...props.dpop_signing_alg_values_supported]\n : undefined;\n this.#dpop_bound_access_tokens_required = props.dpop_bound_access_tokens_required;\n }\n\n /**\n * Convert to JSON representation\n */\n public toJSON(): IProtectedResourceMetadata {\n return {\n resource: this.#resource,\n authorization_servers: [...this.#authorization_servers],\n\n ...(this.#jwks_uri !== undefined && { jwks_uri: this.#jwks_uri }),\n ...(this.#scopes_supported !== undefined && {\n scopes_supported: [...this.#scopes_supported],\n }),\n ...(this.#bearer_methods_supported !== undefined && {\n bearer_methods_supported: [...this.#bearer_methods_supported],\n }),\n ...(this.#resource_signing_alg_values_supported !== undefined && {\n resource_signing_alg_values_supported: [...this.#resource_signing_alg_values_supported],\n }),\n ...(this.#resource_documentation !== undefined && {\n resource_documentation: this.#resource_documentation,\n }),\n ...(this.#resource_policy_uri !== undefined && {\n resource_policy_uri: this.#resource_policy_uri,\n }),\n ...(this.#resource_tos_uri !== undefined && {\n resource_tos_uri: this.#resource_tos_uri,\n }),\n ...(this.#resource_name !== undefined && {\n resource_name: this.#resource_name,\n }),\n ...(this.#tls_client_certificate_bound_access_tokens !== undefined && {\n tls_client_certificate_bound_access_tokens: this.#tls_client_certificate_bound_access_tokens,\n }),\n ...(this.#authorization_details_types_supported !== undefined && {\n authorization_details_types_supported: [...this.#authorization_details_types_supported],\n }),\n ...(this.#dpop_signing_alg_values_supported !== undefined && {\n dpop_signing_alg_values_supported: [...this.#dpop_signing_alg_values_supported],\n }),\n ...(this.#dpop_bound_access_tokens_required !== undefined && {\n dpop_bound_access_tokens_required: this.#dpop_bound_access_tokens_required,\n }),\n };\n }\n}\n","import { InvalidRequestError } from './errors.js';\n/**\n * Header-like object that can represent headers from different HTTP frameworks\n */\nexport type HeadersLike = Record<string, unknown> & {\n authorization?: string;\n 'content-type'?: string;\n};\n\n/**\n * Query-like object for URL query parameters\n */\nexport type QueryLike = Record<string, unknown> & { access_token?: string };\n\n/**\n * Body-like object for form-encoded request body\n */\nexport type BodyLike = QueryLike;\n\n/**\n * Regular expression to match Bearer token in Authorization header\n */\nconst TOKEN_RE = /^Bearer (.+)$/i;\n\n/**\n * Extracts a Bearer token from HTTP request according to RFC 6750.\n * Supports all three methods defined in the RFC:\n * - Authorization header (Section 2.1)\n * - Form-encoded body parameter (Section 2.2)\n * - URI query parameter (Section 2.3)\n *\n * @param headers - HTTP headers object\n * @param query - Query parameters object (optional)\n * @param body - Request body object (optional)\n * @returns The extracted token string\n * @throws {InvalidRequestError} When no token is found or multiple methods are used\n *\n * @example\n * ```typescript\n * // Authorization header method (recommended)\n * const token1 = getToken({ authorization: 'Bearer mF_9.B5f-4.1JqM' });\n *\n * // Query parameter method\n * const token2 = getToken({}, { access_token: 'mF_9.B5f-4.1JqM' });\n *\n * // Form body method\n * const token3 = getToken(\n * { 'content-type': 'application/x-www-form-urlencoded' },\n * {},\n * { access_token: 'mF_9.B5f-4.1JqM' }\n * );\n *\n * // Express.js usage\n * const token4 = getToken(req.headers, req.query, req.body);\n * ```\n *\n * @see https://datatracker.ietf.org/doc/html/rfc6750#section-2 - RFC 6750 Section 2\n */\nexport function getToken(\n headers: HeadersLike,\n query?: QueryLike,\n body?: BodyLike\n): string {\n const fromHeader = getTokenFromHeader(headers);\n const fromQuery = getTokenFromQuery(query);\n const fromBody = getTokenFromBody(headers, body);\n\n if (!fromQuery && !fromHeader && !fromBody) {\n throw new InvalidRequestError('No Bearer token found in request');\n }\n\n // If multiple methods are used, throw an error\n if (+!!fromQuery + +!!fromBody + +!!fromHeader > 1) {\n throw new InvalidRequestError(\n 'More than one method used for authentication'\n );\n }\n\n return (fromQuery || fromBody || fromHeader) as string;\n}\n\n/**\n * Extract token from Authorization header\n */\nfunction getTokenFromHeader(headers: HeadersLike) {\n const authHeader = headers.authorization;\n if (typeof authHeader !== 'string') {\n return undefined;\n }\n\n const match = authHeader.match(TOKEN_RE);\n return match?.[1];\n}\n\n/**\n * Extract token from query parameters\n */\nfunction getTokenFromQuery(query?: QueryLike): string | undefined {\n const accessToken = query?.access_token;\n if (typeof accessToken === 'string') {\n return accessToken;\n }\n}\n\n/**\n * Extract token from form-encoded body\n */\nfunction getTokenFromBody(\n headers: HeadersLike,\n body?: BodyLike\n): string | undefined {\n if (!body || typeof body.access_token !== 'string') {\n return undefined;\n }\n\n const contentType = headers['content-type'];\n if (!contentType) {\n return undefined;\n }\n\n // Handle content-type with charset, e.g., \"application/x-www-form-urlencoded; charset=utf-8\"\n const isFormEncoded = contentType\n .toLowerCase()\n .includes('application/x-www-form-urlencoded');\n if (!isFormEncoded) {\n return undefined;\n }\n\n return body.access_token;\n}\n"],"mappings":"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","names":["import_jose","BearerMethod","SigningAlgorithm","GrantType","import_auth0_auth_js"]} |
+136
-21
@@ -38,2 +38,8 @@ import * as jose from 'jose'; | ||
| customFetch?: typeof fetch; | ||
| /** | ||
| * Demonstration of Proof-of-Possession (DPoP) configuration. | ||
| * | ||
| * @defaultValue `{ mode: 'allowed', iatOffset: 300, iatLeeway: 30 }` | ||
| */ | ||
| dpop?: DPoPOptions; | ||
| } | ||
@@ -178,3 +184,7 @@ interface AccessTokenForConnectionOptions { | ||
| } | ||
| interface VerifyAccessTokenOptions { | ||
| /** | ||
| * Options for validating a bearer (non-DPoP) access token. | ||
| * DPoP-related fields must be omitted. | ||
| */ | ||
| type BearerVerifyAccessTokenOptions = { | ||
| /** | ||
@@ -186,6 +196,70 @@ * The access token to verify. | ||
| * Additional claims that are required to be present in the access token. | ||
| * If the access token does not contain these claims, the verification will fail. | ||
| * Apart from the claims defined in this array, the SDK will also enforce: `iss`, `aud`, `exp` and `iat`. | ||
| */ | ||
| requiredClaims?: string[]; | ||
| /** | ||
| * DPoP proof must be omitted for bearer validation. | ||
| */ | ||
| dpopProof?: undefined; | ||
| /** | ||
| * HTTP method is not used for bearer validation. | ||
| */ | ||
| httpMethod?: undefined; | ||
| /** | ||
| * HTTP URL is not used for bearer validation. | ||
| */ | ||
| httpUrl?: undefined; | ||
| /** | ||
| * Optional scheme (e.g., 'bearer'); DPoP params must be absent. | ||
| */ | ||
| scheme?: string; | ||
| }; | ||
| /** | ||
| * Options for validating a DPoP-bound access token. | ||
| * All DPoP-related fields are required. | ||
| */ | ||
| type DPoPVerifyAccessTokenOptions = { | ||
| /** | ||
| * The access token to verify (must contain cnf.jkt). | ||
| */ | ||
| accessToken: string; | ||
| /** | ||
| * Additional claims that are required to be present in the access token. | ||
| */ | ||
| requiredClaims?: string[]; | ||
| /** | ||
| * The DPoP proof JWT from the `DPoP` header. | ||
| */ | ||
| dpopProof: string; | ||
| /** | ||
| * HTTP method of the authorized request (for `htm` validation). | ||
| */ | ||
| httpMethod: string; | ||
| /** | ||
| * Full HTTP URL of the authorized request (for `htu` validation). | ||
| */ | ||
| httpUrl: string; | ||
| /** | ||
| * Authorization scheme used when presenting the token (e.g., 'dpop'). | ||
| */ | ||
| scheme: string; | ||
| }; | ||
| type VerifyAccessTokenOptions = BearerVerifyAccessTokenOptions | DPoPVerifyAccessTokenOptions; | ||
| interface DPoPOptions { | ||
| /** | ||
| * Controls DPoP behavior. | ||
| * - `allowed` (default): accept Bearer or DPoP; validate proof/binding when DPoP is indicated. | ||
| * - `required`: only DPoP is accepted. | ||
| * - `disabled`: DPoP is ignored; Bearer-only behavior. | ||
| */ | ||
| mode?: 'allowed' | 'required' | 'disabled'; | ||
| /** | ||
| * Maximum accepted age (in seconds) for a DPoP proof `iat` claim. | ||
| * @default 300 | ||
| */ | ||
| iatOffset?: number; | ||
| /** | ||
| * Allowed future skew (in seconds) for a DPoP proof `iat` claim. | ||
| * @default 30 | ||
| */ | ||
| iatLeeway?: number; | ||
| } | ||
@@ -203,3 +277,9 @@ | ||
| * | ||
| * DPoP support: | ||
| * - `dpop.mode` controls behavior: `allowed` (default) accepts Bearer or DPoP; `required` enforces DPoP; `disabled` ignores DPoP. | ||
| * - When validating a DPoP-bound token, you must provide `scheme: 'dpop'`, the `dpopProof` header value, and the actual `httpMethod`/`httpUrl` used for the request. | ||
| * - Bearer tokens omit DPoP params; DPoP params are validated together and proof binding is enforced. | ||
| * | ||
| * @param options Options containing the access token and optional required claims. | ||
| * @see README.md and EXAMPLES.md for usage in allowed/required/disabled modes. | ||
| * @returns Promise resolving to the verified token payload containing all JWT claims. | ||
@@ -211,12 +291,24 @@ * @throws {VerifyAccessTokenError} When verification fails due to invalid signature, | ||
| * ```typescript | ||
| * @example Bearer token validation | ||
| * const apiClient = new ApiClient({ | ||
| * domain: 'example.auth0.com', | ||
| * audience: 'https://api.example.com', // This audience is used for verification | ||
| * clientId: 'client123', | ||
| * clientSecret: 'secret' | ||
| * }); | ||
| * | ||
| * const payload = await apiClient.verifyAccessToken({ | ||
| * accessToken: 'eyJhbGc...' | ||
| * accessToken: 'eyJhbGc...', | ||
| * }); | ||
| * | ||
| * @example DPoP-bound token validation (allowed/required mode) | ||
| * const apiClient = new ApiClient({ | ||
| * domain: 'example.auth0.com', | ||
| * audience: 'https://api.example.com', | ||
| * dpop: { mode: 'required' }, // default is 'allowed' | ||
| * }); | ||
| * const dpopPayload = await apiClient.verifyAccessToken({ | ||
| * accessToken: 'eyJhbGc...', // JWT with cnf.jkt claim | ||
| * scheme: 'dpop', | ||
| * dpopProof: 'eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3A...', // value from DPoP header | ||
| * httpMethod: 'GET', // actual request method | ||
| * httpUrl: 'https://api.example.com/resource', // actual request URL | ||
| * }); | ||
| * ``` | ||
@@ -419,12 +511,12 @@ */ | ||
| /** | ||
| * Error thrown when the transaction is missing. | ||
| * Error thrown when a required argument is missing. | ||
| */ | ||
| declare class MissingTransactionError extends Error { | ||
| declare class MissingRequiredArgumentError extends Error { | ||
| code: string; | ||
| constructor(message?: string); | ||
| constructor(argument: string); | ||
| } | ||
| /** | ||
| * Error thrown when verifying the access token. | ||
| * Error thrown when the SDK is misconfigured at instantiation time. | ||
| */ | ||
| declare class VerifyAccessTokenError extends Error { | ||
| declare class InvalidConfigurationError extends Error { | ||
| code: string; | ||
@@ -434,16 +526,39 @@ constructor(message: string); | ||
| /** | ||
| * Error thrown when request is missing a valid token or | ||
| * multiple auth methods used | ||
| * Base authentication error shape used across the SDK. | ||
| */ | ||
| declare class InvalidRequestError extends Error { | ||
| declare class AuthError extends Error { | ||
| code: string; | ||
| constructor(message: string); | ||
| statusCode?: number; | ||
| headers?: Record<string, string | string[]>; | ||
| cause?: AuthErrorCause; | ||
| constructor(message: string, code: string, statusCode?: number, headers?: Record<string, string | string[]>); | ||
| } | ||
| type AuthErrorCause = { | ||
| code: string; | ||
| }; | ||
| /** | ||
| * Error thrown when a required argument is missing. | ||
| * Error thrown when the transaction is missing. | ||
| */ | ||
| declare class MissingRequiredArgumentError extends Error { | ||
| code: string; | ||
| constructor(argument: string); | ||
| declare class MissingTransactionError extends AuthError { | ||
| constructor(message?: string); | ||
| } | ||
| /** | ||
| * Error thrown when verifying the access token. | ||
| */ | ||
| declare class VerifyAccessTokenError extends AuthError { | ||
| constructor(message: string, headers?: Record<string, string | string[]>); | ||
| } | ||
| /** | ||
| * Error thrown when the DPoP proof fails validation. | ||
| */ | ||
| declare class InvalidDpopProofError extends AuthError { | ||
| constructor(message?: string, headers?: Record<string, string>); | ||
| } | ||
| /** | ||
| * Error thrown when request is missing a valid token or | ||
| * multiple auth methods used | ||
| */ | ||
| declare class InvalidRequestError extends AuthError { | ||
| constructor(message: string, headers?: Record<string, string>); | ||
| } | ||
@@ -503,2 +618,2 @@ /** | ||
| export { type AccessTokenForConnectionOptions, ApiClient, type ApiClientOptions, BearerMethod, type ConnectionTokenSet, type ExchangeProfileOptions, GrantType, type IProtectedResourceMetadata, InvalidRequestError, MissingRequiredArgumentError, MissingTransactionError, ProtectedResourceMetadataBuilder, SigningAlgorithm, type TokenExchangeProfileResult, VerifyAccessTokenError, type VerifyAccessTokenOptions, getToken }; | ||
| export { type AccessTokenForConnectionOptions, ApiClient, type ApiClientOptions, AuthError, type AuthErrorCause, BearerMethod, type BearerVerifyAccessTokenOptions, type BodyLike, type ConnectionTokenSet, type DPoPOptions, type DPoPVerifyAccessTokenOptions, type ExchangeProfileOptions, GrantType, type HeadersLike, type IProtectedResourceMetadata, InvalidConfigurationError, InvalidDpopProofError, InvalidRequestError, MissingRequiredArgumentError, MissingTransactionError, ProtectedResourceMetadata, ProtectedResourceMetadataBuilder, type QueryLike, SigningAlgorithm, type TokenExchangeProfileResult, VerifyAccessTokenError, type VerifyAccessTokenOptions, getToken }; |
+136
-21
@@ -38,2 +38,8 @@ import * as jose from 'jose'; | ||
| customFetch?: typeof fetch; | ||
| /** | ||
| * Demonstration of Proof-of-Possession (DPoP) configuration. | ||
| * | ||
| * @defaultValue `{ mode: 'allowed', iatOffset: 300, iatLeeway: 30 }` | ||
| */ | ||
| dpop?: DPoPOptions; | ||
| } | ||
@@ -178,3 +184,7 @@ interface AccessTokenForConnectionOptions { | ||
| } | ||
| interface VerifyAccessTokenOptions { | ||
| /** | ||
| * Options for validating a bearer (non-DPoP) access token. | ||
| * DPoP-related fields must be omitted. | ||
| */ | ||
| type BearerVerifyAccessTokenOptions = { | ||
| /** | ||
@@ -186,6 +196,70 @@ * The access token to verify. | ||
| * Additional claims that are required to be present in the access token. | ||
| * If the access token does not contain these claims, the verification will fail. | ||
| * Apart from the claims defined in this array, the SDK will also enforce: `iss`, `aud`, `exp` and `iat`. | ||
| */ | ||
| requiredClaims?: string[]; | ||
| /** | ||
| * DPoP proof must be omitted for bearer validation. | ||
| */ | ||
| dpopProof?: undefined; | ||
| /** | ||
| * HTTP method is not used for bearer validation. | ||
| */ | ||
| httpMethod?: undefined; | ||
| /** | ||
| * HTTP URL is not used for bearer validation. | ||
| */ | ||
| httpUrl?: undefined; | ||
| /** | ||
| * Optional scheme (e.g., 'bearer'); DPoP params must be absent. | ||
| */ | ||
| scheme?: string; | ||
| }; | ||
| /** | ||
| * Options for validating a DPoP-bound access token. | ||
| * All DPoP-related fields are required. | ||
| */ | ||
| type DPoPVerifyAccessTokenOptions = { | ||
| /** | ||
| * The access token to verify (must contain cnf.jkt). | ||
| */ | ||
| accessToken: string; | ||
| /** | ||
| * Additional claims that are required to be present in the access token. | ||
| */ | ||
| requiredClaims?: string[]; | ||
| /** | ||
| * The DPoP proof JWT from the `DPoP` header. | ||
| */ | ||
| dpopProof: string; | ||
| /** | ||
| * HTTP method of the authorized request (for `htm` validation). | ||
| */ | ||
| httpMethod: string; | ||
| /** | ||
| * Full HTTP URL of the authorized request (for `htu` validation). | ||
| */ | ||
| httpUrl: string; | ||
| /** | ||
| * Authorization scheme used when presenting the token (e.g., 'dpop'). | ||
| */ | ||
| scheme: string; | ||
| }; | ||
| type VerifyAccessTokenOptions = BearerVerifyAccessTokenOptions | DPoPVerifyAccessTokenOptions; | ||
| interface DPoPOptions { | ||
| /** | ||
| * Controls DPoP behavior. | ||
| * - `allowed` (default): accept Bearer or DPoP; validate proof/binding when DPoP is indicated. | ||
| * - `required`: only DPoP is accepted. | ||
| * - `disabled`: DPoP is ignored; Bearer-only behavior. | ||
| */ | ||
| mode?: 'allowed' | 'required' | 'disabled'; | ||
| /** | ||
| * Maximum accepted age (in seconds) for a DPoP proof `iat` claim. | ||
| * @default 300 | ||
| */ | ||
| iatOffset?: number; | ||
| /** | ||
| * Allowed future skew (in seconds) for a DPoP proof `iat` claim. | ||
| * @default 30 | ||
| */ | ||
| iatLeeway?: number; | ||
| } | ||
@@ -203,3 +277,9 @@ | ||
| * | ||
| * DPoP support: | ||
| * - `dpop.mode` controls behavior: `allowed` (default) accepts Bearer or DPoP; `required` enforces DPoP; `disabled` ignores DPoP. | ||
| * - When validating a DPoP-bound token, you must provide `scheme: 'dpop'`, the `dpopProof` header value, and the actual `httpMethod`/`httpUrl` used for the request. | ||
| * - Bearer tokens omit DPoP params; DPoP params are validated together and proof binding is enforced. | ||
| * | ||
| * @param options Options containing the access token and optional required claims. | ||
| * @see README.md and EXAMPLES.md for usage in allowed/required/disabled modes. | ||
| * @returns Promise resolving to the verified token payload containing all JWT claims. | ||
@@ -211,12 +291,24 @@ * @throws {VerifyAccessTokenError} When verification fails due to invalid signature, | ||
| * ```typescript | ||
| * @example Bearer token validation | ||
| * const apiClient = new ApiClient({ | ||
| * domain: 'example.auth0.com', | ||
| * audience: 'https://api.example.com', // This audience is used for verification | ||
| * clientId: 'client123', | ||
| * clientSecret: 'secret' | ||
| * }); | ||
| * | ||
| * const payload = await apiClient.verifyAccessToken({ | ||
| * accessToken: 'eyJhbGc...' | ||
| * accessToken: 'eyJhbGc...', | ||
| * }); | ||
| * | ||
| * @example DPoP-bound token validation (allowed/required mode) | ||
| * const apiClient = new ApiClient({ | ||
| * domain: 'example.auth0.com', | ||
| * audience: 'https://api.example.com', | ||
| * dpop: { mode: 'required' }, // default is 'allowed' | ||
| * }); | ||
| * const dpopPayload = await apiClient.verifyAccessToken({ | ||
| * accessToken: 'eyJhbGc...', // JWT with cnf.jkt claim | ||
| * scheme: 'dpop', | ||
| * dpopProof: 'eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3A...', // value from DPoP header | ||
| * httpMethod: 'GET', // actual request method | ||
| * httpUrl: 'https://api.example.com/resource', // actual request URL | ||
| * }); | ||
| * ``` | ||
@@ -419,12 +511,12 @@ */ | ||
| /** | ||
| * Error thrown when the transaction is missing. | ||
| * Error thrown when a required argument is missing. | ||
| */ | ||
| declare class MissingTransactionError extends Error { | ||
| declare class MissingRequiredArgumentError extends Error { | ||
| code: string; | ||
| constructor(message?: string); | ||
| constructor(argument: string); | ||
| } | ||
| /** | ||
| * Error thrown when verifying the access token. | ||
| * Error thrown when the SDK is misconfigured at instantiation time. | ||
| */ | ||
| declare class VerifyAccessTokenError extends Error { | ||
| declare class InvalidConfigurationError extends Error { | ||
| code: string; | ||
@@ -434,16 +526,39 @@ constructor(message: string); | ||
| /** | ||
| * Error thrown when request is missing a valid token or | ||
| * multiple auth methods used | ||
| * Base authentication error shape used across the SDK. | ||
| */ | ||
| declare class InvalidRequestError extends Error { | ||
| declare class AuthError extends Error { | ||
| code: string; | ||
| constructor(message: string); | ||
| statusCode?: number; | ||
| headers?: Record<string, string | string[]>; | ||
| cause?: AuthErrorCause; | ||
| constructor(message: string, code: string, statusCode?: number, headers?: Record<string, string | string[]>); | ||
| } | ||
| type AuthErrorCause = { | ||
| code: string; | ||
| }; | ||
| /** | ||
| * Error thrown when a required argument is missing. | ||
| * Error thrown when the transaction is missing. | ||
| */ | ||
| declare class MissingRequiredArgumentError extends Error { | ||
| code: string; | ||
| constructor(argument: string); | ||
| declare class MissingTransactionError extends AuthError { | ||
| constructor(message?: string); | ||
| } | ||
| /** | ||
| * Error thrown when verifying the access token. | ||
| */ | ||
| declare class VerifyAccessTokenError extends AuthError { | ||
| constructor(message: string, headers?: Record<string, string | string[]>); | ||
| } | ||
| /** | ||
| * Error thrown when the DPoP proof fails validation. | ||
| */ | ||
| declare class InvalidDpopProofError extends AuthError { | ||
| constructor(message?: string, headers?: Record<string, string>); | ||
| } | ||
| /** | ||
| * Error thrown when request is missing a valid token or | ||
| * multiple auth methods used | ||
| */ | ||
| declare class InvalidRequestError extends AuthError { | ||
| constructor(message: string, headers?: Record<string, string>); | ||
| } | ||
@@ -503,2 +618,2 @@ /** | ||
| export { type AccessTokenForConnectionOptions, ApiClient, type ApiClientOptions, BearerMethod, type ConnectionTokenSet, type ExchangeProfileOptions, GrantType, type IProtectedResourceMetadata, InvalidRequestError, MissingRequiredArgumentError, MissingTransactionError, ProtectedResourceMetadataBuilder, SigningAlgorithm, type TokenExchangeProfileResult, VerifyAccessTokenError, type VerifyAccessTokenOptions, getToken }; | ||
| export { type AccessTokenForConnectionOptions, ApiClient, type ApiClientOptions, AuthError, type AuthErrorCause, BearerMethod, type BearerVerifyAccessTokenOptions, type BodyLike, type ConnectionTokenSet, type DPoPOptions, type DPoPVerifyAccessTokenOptions, type ExchangeProfileOptions, GrantType, type HeadersLike, type IProtectedResourceMetadata, InvalidConfigurationError, InvalidDpopProofError, InvalidRequestError, MissingRequiredArgumentError, MissingTransactionError, ProtectedResourceMetadata, ProtectedResourceMetadataBuilder, type QueryLike, SigningAlgorithm, type TokenExchangeProfileResult, VerifyAccessTokenError, type VerifyAccessTokenOptions, getToken }; |
+396
-31
| // src/api-client.ts | ||
| import * as oauth from "oauth4webapi"; | ||
| import { createRemoteJWKSet, jwtVerify, customFetch as customFetch2 } from "jose"; | ||
| import { createRemoteJWKSet, jwtVerify as jwtVerify2, customFetch as customFetch2 } from "jose"; | ||
| import { AuthClient, TokenForConnectionError, MissingClientAuthError } from "@auth0/auth0-auth-js"; | ||
| // src/errors.ts | ||
| var MissingTransactionError = class extends Error { | ||
| code = "missing_transaction_error"; | ||
| constructor(message) { | ||
| super(message ?? "The transaction is missing."); | ||
| this.name = "MissingTransactionError"; | ||
| var MissingRequiredArgumentError = class extends Error { | ||
| code = "missing_required_argument_error"; | ||
| constructor(argument) { | ||
| super(`The argument '${argument}' is required but was not provided.`); | ||
| this.name = "MissingRequiredArgumentError"; | ||
| } | ||
| }; | ||
| var VerifyAccessTokenError = class extends Error { | ||
| code = "verify_access_token_error"; | ||
| var InvalidConfigurationError = class extends Error { | ||
| code = "invalid_configuration_error"; | ||
| constructor(message) { | ||
| super(message); | ||
| this.name = "VerifyAccessTokenError"; | ||
| this.name = "InvalidConfigurationError"; | ||
| } | ||
| }; | ||
| var InvalidRequestError = class extends Error { | ||
| code = "invalid_request"; | ||
| constructor(message) { | ||
| var AuthError = class extends Error { | ||
| code; | ||
| statusCode; | ||
| headers; | ||
| constructor(message, code, statusCode, headers) { | ||
| super(message); | ||
| this.name = "InvalidRequestError"; | ||
| this.name = this.constructor.name; | ||
| this.code = code; | ||
| this.statusCode = statusCode; | ||
| this.headers = headers; | ||
| } | ||
| }; | ||
| var MissingRequiredArgumentError = class extends Error { | ||
| code = "missing_required_argument_error"; | ||
| constructor(argument) { | ||
| super(`The argument '${argument}' is required but was not provided.`); | ||
| this.name = "MissingRequiredArgumentError"; | ||
| var MissingTransactionError = class extends AuthError { | ||
| constructor(message) { | ||
| super(message ?? "The transaction is missing.", "missing_transaction_error"); | ||
| } | ||
| }; | ||
| var VerifyAccessTokenError = class extends AuthError { | ||
| constructor(message, headers) { | ||
| super(message, "verify_access_token_error", 401, headers); | ||
| } | ||
| }; | ||
| var InvalidDpopProofError = class extends AuthError { | ||
| constructor(message = "", headers) { | ||
| super(message, "invalid_dpop_proof", 400, headers); | ||
| } | ||
| }; | ||
| var InvalidRequestError = class extends AuthError { | ||
| constructor(message, headers) { | ||
| super(message, "invalid_request", 400, headers); | ||
| } | ||
| }; | ||
| // src/dpop-api.ts | ||
| import { createHash } from "crypto"; | ||
| import { | ||
| EmbeddedJWK, | ||
| base64url, | ||
| calculateJwkThumbprint, | ||
| jwtVerify | ||
| } from "jose"; | ||
| var DPOP_ERROR_MESSAGES = { | ||
| PROOF_VERIFICATION_FAILED: "Failed to verify DPoP proof", | ||
| MISSING_PROOF: "Missing DPoP proof", | ||
| MULTIPLE_PROOFS: "Multiple DPoP proofs are not allowed", | ||
| MISSING_CNF_JKT: "Access token is missing cnf.jkt confirmation claim", | ||
| INVALID_IAT: '"iat" claim must be a number', | ||
| INVALID_JTI: '"jti" claim must be a string', | ||
| INVALID_HTM: '"htm" claim must be a string', | ||
| INVALID_HTU: '"htu" claim must be a string', | ||
| INVALID_HTU_URL: '"htu" claim URL must be valid URL', | ||
| INVALID_HTU_URL_HOST: 'Invalid "htu" claim URL: Host contains illegal characters or format', | ||
| INVALID_HTU_URL_PATH: 'Invalid "htu" claim URL: Path must not start with "//"', | ||
| INVALID_HTTP_URL: '"httpUrl" must be a valid URL', | ||
| INVALID_HTTP_URL_HOST: 'Invalid "httpUrl": Host contains illegal characters or format', | ||
| INVALID_HTTP_URL_PATH: 'Invalid "httpUrl": Path must not start with "//"', | ||
| INVALID_ATH: '"ath" claim must be a string', | ||
| IAT_MISMATCH: 'DPoP proof "iat" is outside the acceptable range', | ||
| HTM_MISMATCH: 'DPoP proof "htm" mismatch', | ||
| HTU_MISMATCH: 'DPoP proof "htu" mismatch', | ||
| ATH_MISMATCH: 'DPoP proof "ath" mismatch', | ||
| JWT_AT_MISMATCH: "JWT Access Token confirmation mismatch", | ||
| MISSING_JWK: "Missing or invalid jwk in DPoP proof header", | ||
| PRIVATE_KEY_MATERIAL: "DPoP proof header must not contain private key material" | ||
| }; | ||
| var ALLOWED_DPOP_ALGORITHMS = ["ES256"]; | ||
| function normalizePercentEncodings(s) { | ||
| const UNRESERVED = /[A-Za-z0-9\-._~]/; | ||
| return s.replace(/%[0-9a-fA-F]{2}/g, (m) => { | ||
| const byte = parseInt(m.slice(1), 16); | ||
| const ch = String.fromCharCode(byte); | ||
| return UNRESERVED.test(ch) ? ch : `%${m.slice(1).toUpperCase()}`; | ||
| }); | ||
| } | ||
| function normalizeUrl(input, source) { | ||
| const HOST_RE = /^(?:[A-Za-z0-9.-]+|\[[0-9A-Fa-f:.]+\])(?::\d{1,5})?$/; | ||
| const PROTOCOL_IN_PATH_RE = /^\/[a-z][a-z0-9+.-]*:\/\//i; | ||
| try { | ||
| const url = new URL(input); | ||
| const host = url.host; | ||
| if (typeof host !== "string" || host.length === 0 || host.includes("://") || host.includes("/") || host.includes("?") || host.includes("#") || !HOST_RE.test(host)) { | ||
| if (source === "request") { | ||
| throw new InvalidRequestError(DPOP_ERROR_MESSAGES.INVALID_HTTP_URL_HOST); | ||
| } else { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTU_URL_HOST); | ||
| } | ||
| } | ||
| if (source === "request") { | ||
| const path = url.pathname; | ||
| if (PROTOCOL_IN_PATH_RE.test(path)) { | ||
| throw new InvalidRequestError(DPOP_ERROR_MESSAGES.INVALID_HTTP_URL_PATH); | ||
| } | ||
| } | ||
| url.search = ""; | ||
| url.hash = ""; | ||
| url.pathname = normalizePercentEncodings(url.pathname); | ||
| return url.origin + url.pathname; | ||
| } catch (err) { | ||
| if (source === "request") { | ||
| if (err instanceof InvalidRequestError) throw err; | ||
| throw new InvalidRequestError(DPOP_ERROR_MESSAGES.INVALID_HTTP_URL); | ||
| } | ||
| if (err instanceof InvalidDpopProofError) throw err; | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTU_URL); | ||
| } | ||
| } | ||
| async function verifyProofJwt(proof, algorithms) { | ||
| try { | ||
| const { payload, protectedHeader } = await jwtVerify(proof, EmbeddedJWK, { | ||
| typ: "dpop+jwt", | ||
| algorithms: [...algorithms] | ||
| }); | ||
| return { header: protectedHeader, claims: payload }; | ||
| } catch (err) { | ||
| let message = DPOP_ERROR_MESSAGES.PROOF_VERIFICATION_FAILED; | ||
| if (err instanceof Error && err.message) { | ||
| message = err.message; | ||
| } | ||
| throw new InvalidDpopProofError(message); | ||
| } | ||
| } | ||
| async function verifyDpopProof(options) { | ||
| const { proof, accessToken, method, url, cnfJkt, iatOffset, iatLeeway, algorithms } = options; | ||
| if (!proof) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.MISSING_PROOF); | ||
| } | ||
| if (proof.includes(",")) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.MULTIPLE_PROOFS); | ||
| } | ||
| if (!cnfJkt) { | ||
| const err = new VerifyAccessTokenError(DPOP_ERROR_MESSAGES.MISSING_CNF_JKT); | ||
| err.cause = { code: "dpop_binding_mismatch" }; | ||
| throw err; | ||
| } | ||
| const normalizedRequestUrl = normalizeUrl(url, "request"); | ||
| const { claims, header } = await verifyProofJwt(proof, algorithms); | ||
| const { htm, htu, iat, ath, jti } = claims; | ||
| if (typeof jti !== "string" || !jti) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_JTI); | ||
| } | ||
| if (typeof iat !== "number") { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_IAT); | ||
| } | ||
| const now = Math.floor(Date.now() / 1e3); | ||
| if (iat < now - iatOffset || iat > now + iatLeeway) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.IAT_MISMATCH); | ||
| } | ||
| if (typeof htm !== "string") { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTM); | ||
| } | ||
| if (htm.toUpperCase() !== method.toUpperCase()) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.HTM_MISMATCH); | ||
| } | ||
| if (typeof htu !== "string") { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTU); | ||
| } | ||
| const normalizedProofUrl = normalizeUrl(htu, "proof"); | ||
| if (normalizedProofUrl !== normalizedRequestUrl) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.HTU_MISMATCH); | ||
| } | ||
| if (typeof ath !== "string") { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_ATH); | ||
| } | ||
| const hash = createHash("sha256").update(accessToken).digest(); | ||
| const encodedHash = base64url.encode(hash); | ||
| if (ath !== encodedHash) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.ATH_MISMATCH); | ||
| } | ||
| const jwk = header.jwk; | ||
| if (!jwk || typeof jwk !== "object") { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.MISSING_JWK); | ||
| } | ||
| if ("d" in jwk) { | ||
| throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.PRIVATE_KEY_MATERIAL); | ||
| } | ||
| const thumbprint = await calculateJwkThumbprint(jwk); | ||
| if (thumbprint !== cnfJkt) { | ||
| const err = new VerifyAccessTokenError(DPOP_ERROR_MESSAGES.JWT_AT_MISMATCH); | ||
| err.cause = { code: "dpop_binding_mismatch" }; | ||
| throw err; | ||
| } | ||
| } | ||
| function buildChallenges(dpopMode, algorithms = ALLOWED_DPOP_ALGORITHMS, params = {}) { | ||
| const bearerParams = [ | ||
| 'realm="api"', | ||
| params.error ? `error="${params.error}"` : void 0, | ||
| params.errorDescription ? `error_description="${params.errorDescription}"` : void 0 | ||
| ].filter(Boolean).join(", "); | ||
| const dpopParams = [ | ||
| params.dpopError ? `error="${params.dpopError}"` : void 0, | ||
| params.dpopErrorDescription ? `error_description="${params.dpopErrorDescription}"` : void 0, | ||
| `algs="${algorithms.join(" ")}"` | ||
| ].filter(Boolean).join(", "); | ||
| const bearerValue = `Bearer ${bearerParams}`; | ||
| const dpopValue = `DPoP ${dpopParams}`; | ||
| const challenges = []; | ||
| if (dpopMode === "allowed") { | ||
| challenges.push(bearerValue, dpopValue); | ||
| } else if (dpopMode === "required") { | ||
| challenges.push(dpopValue); | ||
| } else { | ||
| challenges.push(bearerValue); | ||
| } | ||
| return { | ||
| "www-authenticate": challenges | ||
| }; | ||
| } | ||
| // src/api-client.ts | ||
@@ -43,2 +236,29 @@ var ApiClient = class { | ||
| constructor(options) { | ||
| if (options.dpop !== void 0 && (typeof options.dpop !== "object" || options.dpop === null)) { | ||
| throw new InvalidConfigurationError('Invalid DPoP configuration: "dpop" must be an object'); | ||
| } | ||
| if (options.dpop) { | ||
| const { mode, iatOffset, iatLeeway } = options.dpop; | ||
| if (mode !== void 0 && !["allowed", "required", "disabled"].includes(mode)) { | ||
| throw new InvalidConfigurationError( | ||
| 'Invalid DPoP configuration: "mode" must be allowed, required, or disabled' | ||
| ); | ||
| } | ||
| if (iatOffset !== void 0) { | ||
| if (!Number.isFinite(iatOffset)) { | ||
| throw new InvalidConfigurationError('Invalid DPoP configuration: "iatOffset" must be a number'); | ||
| } | ||
| if (iatOffset < 0) { | ||
| throw new InvalidConfigurationError('Invalid DPoP configuration: "iatOffset" must be a non-negative number'); | ||
| } | ||
| } | ||
| if (iatLeeway !== void 0) { | ||
| if (!Number.isFinite(iatLeeway)) { | ||
| throw new InvalidConfigurationError('Invalid DPoP configuration: "iatLeeway" must be a number'); | ||
| } | ||
| if (iatLeeway < 0) { | ||
| throw new InvalidConfigurationError('Invalid DPoP configuration: "iatLeeway" must be a non-negative number'); | ||
| } | ||
| } | ||
| } | ||
| this.#options = options; | ||
@@ -72,6 +292,3 @@ if (options.clientId) { | ||
| }); | ||
| this.#serverMetadata = await oauth.processDiscoveryResponse( | ||
| issuer, | ||
| response | ||
| ); | ||
| this.#serverMetadata = await oauth.processDiscoveryResponse(issuer, response); | ||
| return { | ||
@@ -88,3 +305,9 @@ serverMetadata: this.#serverMetadata | ||
| * | ||
| * DPoP support: | ||
| * - `dpop.mode` controls behavior: `allowed` (default) accepts Bearer or DPoP; `required` enforces DPoP; `disabled` ignores DPoP. | ||
| * - When validating a DPoP-bound token, you must provide `scheme: 'dpop'`, the `dpopProof` header value, and the actual `httpMethod`/`httpUrl` used for the request. | ||
| * - Bearer tokens omit DPoP params; DPoP params are validated together and proof binding is enforced. | ||
| * | ||
| * @param options Options containing the access token and optional required claims. | ||
| * @see README.md and EXAMPLES.md for usage in allowed/required/disabled modes. | ||
| * @returns Promise resolving to the verified token payload containing all JWT claims. | ||
@@ -96,15 +319,64 @@ * @throws {VerifyAccessTokenError} When verification fails due to invalid signature, | ||
| * ```typescript | ||
| * @example Bearer token validation | ||
| * const apiClient = new ApiClient({ | ||
| * domain: 'example.auth0.com', | ||
| * audience: 'https://api.example.com', // This audience is used for verification | ||
| * clientId: 'client123', | ||
| * clientSecret: 'secret' | ||
| * }); | ||
| * | ||
| * const payload = await apiClient.verifyAccessToken({ | ||
| * accessToken: 'eyJhbGc...' | ||
| * accessToken: 'eyJhbGc...', | ||
| * }); | ||
| * | ||
| * @example DPoP-bound token validation (allowed/required mode) | ||
| * const apiClient = new ApiClient({ | ||
| * domain: 'example.auth0.com', | ||
| * audience: 'https://api.example.com', | ||
| * dpop: { mode: 'required' }, // default is 'allowed' | ||
| * }); | ||
| * const dpopPayload = await apiClient.verifyAccessToken({ | ||
| * accessToken: 'eyJhbGc...', // JWT with cnf.jkt claim | ||
| * scheme: 'dpop', | ||
| * dpopProof: 'eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3A...', // value from DPoP header | ||
| * httpMethod: 'GET', // actual request method | ||
| * httpUrl: 'https://api.example.com/resource', // actual request URL | ||
| * }); | ||
| * ``` | ||
| */ | ||
| async verifyAccessToken(options) { | ||
| const mode = this.#options.dpop?.mode ?? "allowed"; | ||
| const iatOffset = this.#options.dpop?.iatOffset ?? 300; | ||
| const iatLeeway = this.#options.dpop?.iatLeeway ?? 30; | ||
| const scheme = (options.scheme ?? "bearer").toLowerCase(); | ||
| const dpopProof = options.dpopProof; | ||
| const httpMethod = options.httpMethod; | ||
| const httpUrl = options.httpUrl; | ||
| const hasDpopParams = dpopProof !== void 0 || httpMethod !== void 0 || httpUrl !== void 0; | ||
| if (mode !== "disabled" && scheme && !["bearer", "dpop"].includes(scheme)) { | ||
| const err = new InvalidRequestError(""); | ||
| err.cause = { code: "invalid_auth_scheme" }; | ||
| throw this.#addChallenges(err, mode, scheme, { includeError: false }); | ||
| } | ||
| if (mode === "required" && scheme !== "dpop") { | ||
| const err = new InvalidRequestError(""); | ||
| err.cause = { code: "invalid_auth_scheme" }; | ||
| throw this.#addChallenges(err, mode, scheme, { | ||
| includeError: false, | ||
| dpopSpecific: true | ||
| }); | ||
| } | ||
| if (mode === "disabled" && scheme && scheme !== "bearer") { | ||
| const err = new InvalidRequestError(""); | ||
| err.cause = { code: "invalid_auth_scheme" }; | ||
| throw this.#addChallenges(err, mode, scheme, { includeError: false }); | ||
| } | ||
| if (mode !== "disabled" && hasDpopParams && options.scheme === void 0) { | ||
| const err = new InvalidRequestError(""); | ||
| err.cause = { code: "invalid_auth_scheme" }; | ||
| throw this.#addChallenges(err, mode, scheme, { | ||
| includeError: false, | ||
| dpopSpecific: true | ||
| }); | ||
| } | ||
| if (typeof options.accessToken !== "string" || !options.accessToken) { | ||
| throw this.#addChallenges(new VerifyAccessTokenError(""), mode, scheme, { includeError: false }); | ||
| } | ||
| const { serverMetadata } = await this.#discover(); | ||
@@ -115,3 +387,3 @@ this.#jwks ||= createRemoteJWKSet(new URL(serverMetadata.jwks_uri), { | ||
| try { | ||
| const { payload } = await jwtVerify(options.accessToken, this.#jwks, { | ||
| const { payload } = await jwtVerify2(options.accessToken, this.#jwks, { | ||
| issuer: this.#serverMetadata.issuer, | ||
@@ -122,7 +394,98 @@ audience: this.#options.audience, | ||
| }); | ||
| let cnfJkt; | ||
| const cnf = payload.cnf; | ||
| if (cnf && typeof cnf === "object") { | ||
| const maybeJkt = cnf.jkt; | ||
| if (typeof maybeJkt === "string") { | ||
| cnfJkt = maybeJkt; | ||
| } | ||
| } | ||
| const hasProof = typeof dpopProof === "string"; | ||
| if (mode !== "disabled" && scheme === "bearer" && hasProof && !cnfJkt) { | ||
| throw this.#addChallenges( | ||
| new InvalidRequestError("DPoP proof requires the DPoP authentication scheme, not Bearer"), | ||
| mode, | ||
| scheme | ||
| ); | ||
| } | ||
| const shouldVerifyDpop = mode !== "disabled" && (mode === "required" || scheme === "dpop" || hasProof || !!cnfJkt); | ||
| if (mode !== "disabled" && scheme === "dpop" && !cnfJkt) { | ||
| const err = new VerifyAccessTokenError("JWT Access Token has no jkt confirmation claim"); | ||
| err.cause = { code: "dpop_binding_mismatch" }; | ||
| throw this.#addChallenges(err, mode, scheme, { dpopSpecific: true }); | ||
| } | ||
| if (scheme === "bearer" && cnfJkt && mode !== "disabled") { | ||
| throw this.#addChallenges( | ||
| new VerifyAccessTokenError("DPoP-bound token requires the DPoP authentication scheme, not Bearer"), | ||
| mode, | ||
| scheme | ||
| ); | ||
| } | ||
| if (!shouldVerifyDpop) { | ||
| return payload; | ||
| } | ||
| if (!dpopProof) { | ||
| throw this.#addChallenges(new InvalidRequestError(""), mode, scheme, { | ||
| dpopSpecific: true, | ||
| includeError: false | ||
| }); | ||
| } | ||
| if (typeof httpMethod !== "string" || !httpMethod) { | ||
| throw this.#addChallenges( | ||
| new InvalidRequestError("HTTP method is required for DPoP validation"), | ||
| mode, | ||
| scheme, | ||
| { dpopSpecific: true } | ||
| ); | ||
| } | ||
| if (typeof httpUrl !== "string" || !httpUrl) { | ||
| throw this.#addChallenges(new InvalidRequestError("HTTP URL is required for DPoP validation"), mode, scheme, { | ||
| dpopSpecific: true | ||
| }); | ||
| } | ||
| try { | ||
| await verifyDpopProof({ | ||
| proof: dpopProof, | ||
| accessToken: options.accessToken, | ||
| method: httpMethod, | ||
| url: httpUrl, | ||
| cnfJkt, | ||
| iatOffset, | ||
| iatLeeway, | ||
| algorithms: ALLOWED_DPOP_ALGORITHMS | ||
| }); | ||
| } catch (err) { | ||
| if (err instanceof VerifyAccessTokenError || err instanceof InvalidDpopProofError || err instanceof InvalidRequestError) { | ||
| throw this.#addChallenges(err, mode, scheme, { dpopSpecific: true }); | ||
| } | ||
| throw err; | ||
| } | ||
| return payload; | ||
| } catch (e) { | ||
| throw new VerifyAccessTokenError(e.message); | ||
| if (e instanceof AuthError) { | ||
| throw e; | ||
| } | ||
| const message = e instanceof Error ? e.message : String(e); | ||
| const err = new VerifyAccessTokenError(message); | ||
| throw this.#addChallenges(err, mode, scheme); | ||
| } | ||
| } | ||
| #addChallenges(err, mode, scheme, params) { | ||
| const authErr = err; | ||
| if (!authErr.headers) { | ||
| const includeError = params?.includeError ?? true; | ||
| const target = params?.target ?? (params?.dpopSpecific === true ? "dpop" : scheme === "dpop" ? "dpop" : "bearer"); | ||
| let challengeCode = authErr.code; | ||
| if (authErr instanceof VerifyAccessTokenError) { | ||
| challengeCode = "invalid_token"; | ||
| } else if (authErr instanceof InvalidRequestError) { | ||
| challengeCode = "invalid_request"; | ||
| } else if (authErr instanceof InvalidDpopProofError) { | ||
| challengeCode = "invalid_dpop_proof"; | ||
| } | ||
| const challengeParams = includeError && target === "dpop" ? { dpopError: challengeCode, dpopErrorDescription: authErr.message } : includeError && target === "bearer" ? { error: challengeCode, errorDescription: authErr.message } : {}; | ||
| authErr.headers = buildChallenges(mode, ALLOWED_DPOP_ALGORITHMS, challengeParams); | ||
| } | ||
| return authErr; | ||
| } | ||
| /** | ||
@@ -139,5 +502,3 @@ * Retrieves an access token for a connection. | ||
| if (!this.#authClient) { | ||
| throw new TokenForConnectionError( | ||
| "Client credentials are required to use getAccessTokenForConnection" | ||
| ); | ||
| throw new TokenForConnectionError("Client credentials are required to use getAccessTokenForConnection"); | ||
| } | ||
@@ -488,4 +849,7 @@ const tokenEndpointResponse = await this.#authClient.getTokenForConnection({ | ||
| ApiClient, | ||
| AuthError, | ||
| BearerMethod, | ||
| GrantType, | ||
| InvalidConfigurationError, | ||
| InvalidDpopProofError, | ||
| InvalidRequestError, | ||
@@ -495,2 +859,3 @@ MissingClientAuthError2 as MissingClientAuthError, | ||
| MissingTransactionError, | ||
| ProtectedResourceMetadata, | ||
| ProtectedResourceMetadataBuilder, | ||
@@ -497,0 +862,0 @@ SigningAlgorithm, |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/api-client.ts","../src/errors.ts","../src/protected-resource-metadata.ts","../src/token.ts","../src/index.ts"],"sourcesContent":["import * as oauth from 'oauth4webapi';\nimport { createRemoteJWKSet, jwtVerify, customFetch } from 'jose';\nimport { AuthClient, TokenForConnectionError, MissingClientAuthError } from '@auth0/auth0-auth-js';\nimport { AccessTokenForConnectionOptions, ApiClientOptions, ConnectionTokenSet, ExchangeProfileOptions, TokenExchangeProfileResult, VerifyAccessTokenOptions } from './types.js';\nimport {\n MissingRequiredArgumentError,\n VerifyAccessTokenError,\n} from './errors.js';\n\nexport class ApiClient {\n #serverMetadata: oauth.AuthorizationServer | undefined;\n readonly #options: ApiClientOptions;\n #jwks?: ReturnType<typeof createRemoteJWKSet>;\n readonly #authClient: AuthClient | undefined;\n\n constructor(options: ApiClientOptions) {\n this.#options = options;\n\n if (options.clientId) {\n this.#authClient = new AuthClient({\n domain: options.domain,\n clientId: options.clientId,\n clientSecret: options.clientSecret,\n clientAssertionSigningKey: options.clientAssertionSigningKey,\n clientAssertionSigningAlg: options.clientAssertionSigningAlg,\n customFetch: options.customFetch,\n });\n }\n\n if (!this.#options.audience) {\n throw new MissingRequiredArgumentError('audience');\n }\n }\n\n /**\n * Initialized the SDK by performing Metadata Discovery.\n */\n async #discover() {\n if (this.#serverMetadata) {\n return {\n serverMetadata: this.#serverMetadata,\n };\n }\n\n const issuer = new URL(`https://${this.#options.domain}`);\n const response = await oauth.discoveryRequest(issuer, {\n [oauth.customFetch]: this.#options.customFetch,\n });\n\n this.#serverMetadata = await oauth.processDiscoveryResponse(\n issuer,\n response\n );\n\n return {\n serverMetadata: this.#serverMetadata,\n };\n }\n\n /**\n * Verifies the provided access token against the ApiClient's configured audience.\n *\n * This method validates the JWT signature using the Auth0 tenant's JWKS and verifies\n * standard claims including issuer, expiration, and issued-at time. The audience claim\n * is verified against the audience configured when constructing the ApiClient.\n *\n * @param options Options containing the access token and optional required claims.\n * @returns Promise resolving to the verified token payload containing all JWT claims.\n * @throws {VerifyAccessTokenError} When verification fails due to invalid signature,\n * expired token, mismatched audience, or missing required claims.\n *\n * @example\n * ```typescript\n * const apiClient = new ApiClient({\n * domain: 'example.auth0.com',\n * audience: 'https://api.example.com', // This audience is used for verification\n * clientId: 'client123',\n * clientSecret: 'secret'\n * });\n *\n * const payload = await apiClient.verifyAccessToken({\n * accessToken: 'eyJhbGc...'\n * });\n * ```\n */\n async verifyAccessToken(options: VerifyAccessTokenOptions) {\n const { serverMetadata } = await this.#discover();\n\n this.#jwks ||= createRemoteJWKSet(new URL(serverMetadata!.jwks_uri!), {\n [customFetch]: this.#options.customFetch,\n });\n\n try {\n const { payload } = await jwtVerify(options.accessToken, this.#jwks, {\n issuer: this.#serverMetadata!.issuer,\n audience: this.#options.audience,\n algorithms: ['RS256'],\n requiredClaims: ['iat', 'exp', ...(options.requiredClaims || [])],\n });\n return payload;\n } catch (e) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n throw new VerifyAccessTokenError((e as any).message);\n }\n }\n\n /**\n * Retrieves an access token for a connection.\n *\n * @param options - Options for retrieving an access token for a connection.\n *\n * @throws {TokenForConnectionError} If there was an issue requesting the access token.\n *\n * @returns The Connection Token Set, containing the access token for the connection, as well as additional information.\n */\n public async getAccessTokenForConnection(options: AccessTokenForConnectionOptions): Promise<ConnectionTokenSet> {\n if (!this.#authClient) {\n throw new TokenForConnectionError(\n 'Client credentials are required to use getAccessTokenForConnection'\n );\n }\n\n const tokenEndpointResponse = await this.#authClient.getTokenForConnection({\n connection: options.connection,\n loginHint: options.loginHint,\n accessToken: options.accessToken,\n });\n\n return {\n accessToken: tokenEndpointResponse.accessToken,\n scope: tokenEndpointResponse.scope,\n expiresAt: tokenEndpointResponse.expiresAt,\n connection: options.connection,\n loginHint: options.loginHint,\n };\n }\n\n /**\n * Exchanges a token via a Custom Token Exchange Profile for a different API audience while preserving user identity (RFC 8693).\n *\n * This method supports **Custom Token Exchange** for custom token types via a configured Token Exchange Profile.\n *\n * For **Access Token Exchange with Token Vault** (external provider's access tokens), use {@link getAccessTokenForConnection} instead.\n *\n * **Note**: This method requires a confidential client (client credentials must be configured).\n * While Custom Token Exchange Early Access technically permits public clients, this implementation\n * currently requires client authentication. Public client support may be added in a future release.\n *\n * @param subjectToken - The raw token to be exchanged (without \"Bearer \" prefix)\n * @param options - Configuration for the token exchange\n *\n * @returns A promise that resolves with the {@link TokenExchangeProfileResult}\n *\n * @throws {TokenExchangeError} When client credentials are not configured or exchange fails\n *\n * @see {@link https://auth0.com/docs/authenticate/custom-token-exchange Custom Token Exchange Documentation}\n *\n * @example\n * ```typescript\n * // Exchange custom token (organization is optional)\n * const result = await apiClient.getTokenByExchangeProfile(\n * userToken,\n * {\n * subjectTokenType: 'urn:example:custom-token',\n * audience: 'https://api.backend.com',\n * organization: 'org_abc123', // Optional - Organization ID or name\n * scope: 'read:data write:data',\n * }\n * );\n * // When organization is provided, the access token will include the organization ID in its payload\n * ```\n */\n public async getTokenByExchangeProfile(\n subjectToken: string,\n options: ExchangeProfileOptions\n ): Promise<TokenExchangeProfileResult> {\n if (!this.#authClient) {\n throw new MissingClientAuthError();\n }\n\n const response = await this.#authClient.exchangeToken({\n subjectTokenType: options.subjectTokenType,\n subjectToken,\n audience: options.audience,\n scope: options.scope,\n requestedTokenType: options.requestedTokenType,\n organization: options.organization,\n });\n\n return {\n accessToken: response.accessToken,\n expiresAt: response.expiresAt,\n ...(response.scope && { scope: response.scope }),\n ...(response.idToken && { idToken: response.idToken }),\n ...(response.refreshToken && { refreshToken: response.refreshToken }),\n ...(response.tokenType && { tokenType: response.tokenType }),\n ...(response.issuedTokenType && { issuedTokenType: response.issuedTokenType }),\n };\n }\n}\n","/**\n * Error thrown when the transaction is missing.\n */\nexport class MissingTransactionError extends Error {\n public code: string = 'missing_transaction_error';\n\n constructor(message?: string) {\n super(message ?? 'The transaction is missing.');\n this.name = 'MissingTransactionError';\n }\n}\n\n/**\n * Error thrown when verifying the access token.\n */\nexport class VerifyAccessTokenError extends Error {\n public code: string = 'verify_access_token_error';\n\n constructor(message: string) {\n super(message);\n this.name = 'VerifyAccessTokenError';\n }\n}\n\n/**\n * Error thrown when request is missing a valid token or\n * multiple auth methods used\n */\nexport class InvalidRequestError extends Error {\n public code: string = 'invalid_request';\n\n constructor(message: string) {\n super(message);\n this.name = 'InvalidRequestError';\n }\n}\n\n/**\n * Error thrown when a required argument is missing.\n */\nexport class MissingRequiredArgumentError extends Error {\n public code: string = 'missing_required_argument_error';\n\n constructor(argument: string) {\n super(`The argument '${argument}' is required but was not provided.`);\n this.name = 'MissingRequiredArgumentError';\n }\n}\n","/**\n * RFC 9728 - OAuth 2.0 Protected Resource Metadata\n * https://datatracker.ietf.org/doc/html/rfc9728\n */\n\nimport { MissingRequiredArgumentError } from \"./errors.js\";\n\n/**\n * Supported methods of sending an OAuth 2.0 bearer token\n */\nexport enum BearerMethod {\n HEADER = \"header\",\n BODY = \"body\",\n QUERY = \"query\",\n}\n\n/**\n * Supported signing algorithms\n */\nexport enum SigningAlgorithm {\n RS256 = \"RS256\",\n RS384 = \"RS384\",\n RS512 = \"RS512\",\n ES256 = \"ES256\",\n ES384 = \"ES384\",\n ES512 = \"ES512\",\n PS256 = \"PS256\",\n PS384 = \"PS384\",\n PS512 = \"PS512\",\n HS256 = \"HS256\",\n HS384 = \"HS384\",\n HS512 = \"HS512\",\n}\n\n/**\n * Grant types supported\n */\nexport enum GrantType {\n AUTHORIZATION_CODE = \"authorization_code\",\n IMPLICIT = \"implicit\",\n PASSWORD = \"password\",\n CLIENT_CREDENTIALS = \"client_credentials\",\n REFRESH_TOKEN = \"refresh_token\",\n JWT_BEARER = \"urn:ietf:params:oauth:grant-type:jwt-bearer\",\n SAML2_BEARER = \"urn:ietf:params:oauth:grant-type:saml2-bearer\",\n DEVICE_CODE = \"urn:ietf:params:oauth:grant-type:device_code\",\n}\n\n/**\n * Interface for Protected Resource Metadata\n */\nexport interface IProtectedResourceMetadata {\n resource: string;\n authorization_servers: string[];\n jwks_uri?: string;\n scopes_supported?: string[];\n bearer_methods_supported?: BearerMethod[];\n resource_signing_alg_values_supported?: SigningAlgorithm[];\n resource_name?: string;\n resource_documentation?: string;\n resource_policy_uri?: string;\n resource_tos_uri?: string;\n tls_client_certificate_bound_access_tokens?: boolean;\n authorization_details_types_supported?: string[];\n dpop_signing_alg_values_supported?: string[];\n dpop_bound_access_tokens_required?: boolean;\n}\n\n/**\n * Builder for creating a ProtectedResourceMetadata instance\n *\n * @example\n * ```typescript\n * const metadata = new ProtectedResourceMetadataBuilder('https://api.example.com', ['https://auth.example.com'])\n * .withJwksUri('https://api.example.com/.well-known/jwks.json')\n * .withScopesSupported(['read', 'write'])\n * .build();\n * // serialize to json\n * const json = metadata.toJSON();\n * ```\n */\nexport class ProtectedResourceMetadataBuilder {\n private readonly props: Partial<IProtectedResourceMetadata> &\n Pick<IProtectedResourceMetadata, \"resource\" | \"authorization_servers\">;\n\n /**\n * Constructor for the builder\n * @param resource - The protected resource identifier (REQUIRED)\n * @param authorization_servers - Array of authorization server URLs (REQUIRED)\n */\n constructor(resource: string, authorization_servers: string[]) {\n if (!resource?.trim()) {\n throw new MissingRequiredArgumentError(\"resource\");\n }\n if (\n !Array.isArray(authorization_servers) ||\n authorization_servers.length === 0\n ) {\n throw new MissingRequiredArgumentError(\"authorization_servers\");\n }\n this.props = { resource, authorization_servers };\n }\n\n get properties(): IProtectedResourceMetadata {\n return this.props;\n }\n\n /**\n * Builds the ProtectedResourceMetadata\n */\n public build() {\n return new ProtectedResourceMetadata(this);\n }\n\n /**\n * Builder method to add JWKS URI\n */\n withJwksUri(jwks_uri: string): this {\n this.props.jwks_uri = jwks_uri;\n return this;\n }\n\n /**\n * Builder method to add supported scopes\n */\n withScopesSupported(scopes_supported: string[]): this {\n this.props.scopes_supported = [...scopes_supported];\n return this;\n }\n\n /**\n * Builder method to add supported bearer methods\n */\n withBearerMethodsSupported(\n bearer_methods_supported: BearerMethod[]\n ): this {\n this.props.bearer_methods_supported = [...bearer_methods_supported];\n return this;\n }\n\n /**\n * Builder method to add supported resource signing algorithms\n */\n withResourceSigningAlgValuesSupported(\n resource_signing_alg_values_supported: SigningAlgorithm[]\n ): this {\n this.props.resource_signing_alg_values_supported = [...resource_signing_alg_values_supported];\n return this;\n }\n\n /**\n * Builder method to add resource_name\n */\n withResourceName(resource_name: string): this {\n this.props.resource_name = resource_name;\n return this;\n }\n\n /**\n * Builder method to add resource documentation URL\n */\n withResourceDocumentation(resource_documentation: string): this {\n this.props.resource_documentation = resource_documentation;\n return this;\n }\n\n /**\n * Builder method to add resource policy URI\n */\n withResourcePolicyUri(resource_policy_uri: string): this {\n this.props.resource_policy_uri = resource_policy_uri;\n return this;\n }\n\n /**\n * Builder method to add resource terms of service URI\n */\n withResourceTosUri(resource_tos_uri: string): this {\n this.props.resource_tos_uri = resource_tos_uri;\n return this;\n }\n\n /**\n * Builder method to enable TLS client certificate bound access tokens\n */\n withTlsClientCertificateBoundAccessTokens(tls_client_certificate_bound_access_tokens: boolean): this {\n this.props.tls_client_certificate_bound_access_tokens = tls_client_certificate_bound_access_tokens;\n return this;\n }\n\n /**\n * Builder method to add supported authorization details types\n */\n withAuthorizationDetailsTypesSupported(authorization_details_types_supported: string[]): this {\n this.props.authorization_details_types_supported = [...authorization_details_types_supported];\n return this;\n }\n\n /**\n * Builder method to add supported DPoP signing algorithms\n */\n withDpopSigningAlgValuesSupported(dpop_signing_alg_values_supported: string[]): this {\n this.props.dpop_signing_alg_values_supported = [...dpop_signing_alg_values_supported];\n return this;\n }\n\n /**\n * Builder method to require DPoP bound access tokens\n */\n withDpopBoundAccessTokensRequired(dpop_bound_access_tokens_required: boolean): this {\n this.props.dpop_bound_access_tokens_required = dpop_bound_access_tokens_required;\n return this;\n }\n\n\n}\n\nclass ProtectedResourceMetadata {\n readonly #resource: string;\n readonly #authorization_servers: string[];\n readonly #jwks_uri?: string;\n readonly #scopes_supported?: string[];\n readonly #bearer_methods_supported?: BearerMethod[];\n readonly #resource_signing_alg_values_supported?: SigningAlgorithm[];\n readonly #resource_documentation?: string;\n readonly #resource_policy_uri?: string;\n readonly #resource_tos_uri?: string;\n readonly #resource_name?: string;\n readonly #tls_client_certificate_bound_access_tokens?: boolean;\n readonly #authorization_details_types_supported?: string[];\n readonly #dpop_signing_alg_values_supported?: string[];\n readonly #dpop_bound_access_tokens_required?: boolean;\n\n constructor(builder: ProtectedResourceMetadataBuilder) {\n const props = builder.properties;\n this.#resource = props.resource;\n this.#authorization_servers = [...props.authorization_servers];\n this.#jwks_uri = props.jwks_uri;\n this.#scopes_supported = props.scopes_supported\n ? [...props.scopes_supported]\n : undefined;\n this.#bearer_methods_supported = props.bearer_methods_supported\n ? [...props.bearer_methods_supported]\n : undefined;\n this.#resource_signing_alg_values_supported = props.resource_signing_alg_values_supported\n ? [...props.resource_signing_alg_values_supported]\n : undefined;\n this.#resource_documentation = props.resource_documentation;\n this.#resource_policy_uri = props.resource_policy_uri;\n this.#resource_tos_uri = props.resource_tos_uri;\n this.#resource_name = props.resource_name;\n this.#tls_client_certificate_bound_access_tokens = props.tls_client_certificate_bound_access_tokens;\n this.#authorization_details_types_supported = props.authorization_details_types_supported\n ? [...props.authorization_details_types_supported]\n : undefined;\n this.#dpop_signing_alg_values_supported = props.dpop_signing_alg_values_supported\n ? [...props.dpop_signing_alg_values_supported]\n : undefined;\n this.#dpop_bound_access_tokens_required = props.dpop_bound_access_tokens_required;\n }\n\n /**\n * Convert to JSON representation\n */\n public toJSON(): IProtectedResourceMetadata {\n return {\n resource: this.#resource,\n authorization_servers: [...this.#authorization_servers],\n\n ...(this.#jwks_uri !== undefined && { jwks_uri: this.#jwks_uri }),\n ...(this.#scopes_supported !== undefined && {\n scopes_supported: [...this.#scopes_supported],\n }),\n ...(this.#bearer_methods_supported !== undefined && {\n bearer_methods_supported: [...this.#bearer_methods_supported],\n }),\n ...(this.#resource_signing_alg_values_supported !== undefined && {\n resource_signing_alg_values_supported: [...this.#resource_signing_alg_values_supported],\n }),\n ...(this.#resource_documentation !== undefined && {\n resource_documentation: this.#resource_documentation,\n }),\n ...(this.#resource_policy_uri !== undefined && {\n resource_policy_uri: this.#resource_policy_uri,\n }),\n ...(this.#resource_tos_uri !== undefined && {\n resource_tos_uri: this.#resource_tos_uri,\n }),\n ...(this.#resource_name !== undefined && {\n resource_name: this.#resource_name,\n }),\n ...(this.#tls_client_certificate_bound_access_tokens !== undefined && {\n tls_client_certificate_bound_access_tokens: this.#tls_client_certificate_bound_access_tokens,\n }),\n ...(this.#authorization_details_types_supported !== undefined && {\n authorization_details_types_supported: [...this.#authorization_details_types_supported],\n }),\n ...(this.#dpop_signing_alg_values_supported !== undefined && {\n dpop_signing_alg_values_supported: [...this.#dpop_signing_alg_values_supported],\n }),\n ...(this.#dpop_bound_access_tokens_required !== undefined && {\n dpop_bound_access_tokens_required: this.#dpop_bound_access_tokens_required,\n }),\n };\n }\n}\n","import { InvalidRequestError } from './errors.js';\n/**\n * Header-like object that can represent headers from different HTTP frameworks\n */\ntype HeadersLike = Record<string, unknown> & {\n authorization?: string;\n 'content-type'?: string;\n};\n\n/**\n * Query-like object for URL query parameters\n */\ntype QueryLike = Record<string, unknown> & { access_token?: string };\n\n/**\n * Body-like object for form-encoded request body\n */\ntype BodyLike = QueryLike;\n\n/**\n * Regular expression to match Bearer token in Authorization header\n */\nconst TOKEN_RE = /^Bearer (.+)$/i;\n\n/**\n * Extracts a Bearer token from HTTP request according to RFC 6750.\n * Supports all three methods defined in the RFC:\n * - Authorization header (Section 2.1)\n * - Form-encoded body parameter (Section 2.2)\n * - URI query parameter (Section 2.3)\n *\n * @param headers - HTTP headers object\n * @param query - Query parameters object (optional)\n * @param body - Request body object (optional)\n * @returns The extracted token string\n * @throws {InvalidRequestError} When no token is found or multiple methods are used\n *\n * @example\n * ```typescript\n * // Authorization header method (recommended)\n * const token1 = getToken({ authorization: 'Bearer mF_9.B5f-4.1JqM' });\n *\n * // Query parameter method\n * const token2 = getToken({}, { access_token: 'mF_9.B5f-4.1JqM' });\n *\n * // Form body method\n * const token3 = getToken(\n * { 'content-type': 'application/x-www-form-urlencoded' },\n * {},\n * { access_token: 'mF_9.B5f-4.1JqM' }\n * );\n *\n * // Express.js usage\n * const token4 = getToken(req.headers, req.query, req.body);\n * ```\n *\n * @see https://datatracker.ietf.org/doc/html/rfc6750#section-2 - RFC 6750 Section 2\n */\nexport function getToken(\n headers: HeadersLike,\n query?: QueryLike,\n body?: BodyLike\n): string {\n const fromHeader = getTokenFromHeader(headers);\n const fromQuery = getTokenFromQuery(query);\n const fromBody = getTokenFromBody(headers, body);\n\n if (!fromQuery && !fromHeader && !fromBody) {\n throw new InvalidRequestError('No Bearer token found in request');\n }\n\n // If multiple methods are used, throw an error\n if (+!!fromQuery + +!!fromBody + +!!fromHeader > 1) {\n throw new InvalidRequestError(\n 'More than one method used for authentication'\n );\n }\n\n return (fromQuery || fromBody || fromHeader) as string;\n}\n\n/**\n * Extract token from Authorization header\n */\nfunction getTokenFromHeader(headers: HeadersLike) {\n const authHeader = headers.authorization;\n if (typeof authHeader !== 'string') {\n return undefined;\n }\n\n const match = authHeader.match(TOKEN_RE);\n return match?.[1];\n}\n\n/**\n * Extract token from query parameters\n */\nfunction getTokenFromQuery(query?: QueryLike): string | undefined {\n const accessToken = query?.access_token;\n if (typeof accessToken === 'string') {\n return accessToken;\n }\n}\n\n/**\n * Extract token from form-encoded body\n */\nfunction getTokenFromBody(\n headers: HeadersLike,\n body?: BodyLike\n): string | undefined {\n if (!body || typeof body.access_token !== 'string') {\n return undefined;\n }\n\n const contentType = headers['content-type'];\n if (!contentType) {\n return undefined;\n }\n\n // Handle content-type with charset, e.g., \"application/x-www-form-urlencoded; charset=utf-8\"\n const isFormEncoded = contentType\n .toLowerCase()\n .includes('application/x-www-form-urlencoded');\n if (!isFormEncoded) {\n return undefined;\n }\n\n return body.access_token;\n}\n","export { ApiClient } from './api-client.js';\nexport * from './protected-resource-metadata.js';\nexport * from './errors.js';\nexport * from './types.js';\nexport { getToken } from './token.js';\n\n// Re-export shared errors from auth0-auth-js for convenience\nexport {\n MissingClientAuthError,\n TokenExchangeError,\n} from '@auth0/auth0-auth-js';\n"],"mappings":";AAAA,YAAY,WAAW;AACvB,SAAS,oBAAoB,WAAW,eAAAA,oBAAmB;AAC3D,SAAS,YAAY,yBAAyB,8BAA8B;;;ACCrE,IAAM,0BAAN,cAAsC,MAAM;AAAA,EAC1C,OAAe;AAAA,EAEtB,YAAY,SAAkB;AAC5B,UAAM,WAAW,6BAA6B;AAC9C,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,yBAAN,cAAqC,MAAM;AAAA,EACzC,OAAe;AAAA,EAEtB,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAMO,IAAM,sBAAN,cAAkC,MAAM;AAAA,EACtC,OAAe;AAAA,EAEtB,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,+BAAN,cAA2C,MAAM;AAAA,EAC/C,OAAe;AAAA,EAEtB,YAAY,UAAkB;AAC5B,UAAM,iBAAiB,QAAQ,qCAAqC;AACpE,SAAK,OAAO;AAAA,EACd;AACF;;;ADtCO,IAAM,YAAN,MAAgB;AAAA,EACrB;AAAA,EACS;AAAA,EACT;AAAA,EACS;AAAA,EAET,YAAY,SAA2B;AACrC,SAAK,WAAW;AAEhB,QAAI,QAAQ,UAAU;AACpB,WAAK,cAAc,IAAI,WAAW;AAAA,QAChC,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ;AAAA,QAClB,cAAc,QAAQ;AAAA,QACtB,2BAA2B,QAAQ;AAAA,QACnC,2BAA2B,QAAQ;AAAA,QACnC,aAAa,QAAQ;AAAA,MACvB,CAAC;AAAA,IACH;AAEA,QAAI,CAAC,KAAK,SAAS,UAAU;AAC3B,YAAM,IAAI,6BAA6B,UAAU;AAAA,IACnD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY;AAChB,QAAI,KAAK,iBAAiB;AACxB,aAAO;AAAA,QACL,gBAAgB,KAAK;AAAA,MACvB;AAAA,IACF;AAEA,UAAM,SAAS,IAAI,IAAI,WAAW,KAAK,SAAS,MAAM,EAAE;AACxD,UAAM,WAAW,MAAY,uBAAiB,QAAQ;AAAA,MACpD,CAAO,iBAAW,GAAG,KAAK,SAAS;AAAA,IACrC,CAAC;AAED,SAAK,kBAAkB,MAAY;AAAA,MACjC;AAAA,MACA;AAAA,IACF;AAEA,WAAO;AAAA,MACL,gBAAgB,KAAK;AAAA,IACvB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4BA,MAAM,kBAAkB,SAAmC;AACzD,UAAM,EAAE,eAAe,IAAI,MAAM,KAAK,UAAU;AAEhD,SAAK,UAAU,mBAAmB,IAAI,IAAI,eAAgB,QAAS,GAAG;AAAA,MACpE,CAACC,YAAW,GAAG,KAAK,SAAS;AAAA,IAC/B,CAAC;AAED,QAAI;AACF,YAAM,EAAE,QAAQ,IAAI,MAAM,UAAU,QAAQ,aAAa,KAAK,OAAO;AAAA,QACnE,QAAQ,KAAK,gBAAiB;AAAA,QAC9B,UAAU,KAAK,SAAS;AAAA,QACxB,YAAY,CAAC,OAAO;AAAA,QACpB,gBAAgB,CAAC,OAAO,OAAO,GAAI,QAAQ,kBAAkB,CAAC,CAAE;AAAA,MAClE,CAAC;AACD,aAAO;AAAA,IACT,SAAS,GAAG;AAEV,YAAM,IAAI,uBAAwB,EAAU,OAAO;AAAA,IACrD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAa,4BAA4B,SAAuE;AAC9G,QAAI,CAAC,KAAK,aAAa;AACrB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,wBAAwB,MAAM,KAAK,YAAY,sBAAsB;AAAA,MACzE,YAAY,QAAQ;AAAA,MACpB,WAAW,QAAQ;AAAA,MACnB,aAAa,QAAQ;AAAA,IACvB,CAAC;AAED,WAAO;AAAA,MACL,aAAa,sBAAsB;AAAA,MACnC,OAAO,sBAAsB;AAAA,MAC7B,WAAW,sBAAsB;AAAA,MACjC,YAAY,QAAQ;AAAA,MACpB,WAAW,QAAQ;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqCA,MAAa,0BACX,cACA,SACqC;AACrC,QAAI,CAAC,KAAK,aAAa;AACrB,YAAM,IAAI,uBAAuB;AAAA,IACnC;AAEA,UAAM,WAAW,MAAM,KAAK,YAAY,cAAc;AAAA,MACpD,kBAAkB,QAAQ;AAAA,MAC1B;AAAA,MACA,UAAU,QAAQ;AAAA,MAClB,OAAO,QAAQ;AAAA,MACf,oBAAoB,QAAQ;AAAA,MAC5B,cAAc,QAAQ;AAAA,IACxB,CAAC;AAED,WAAO;AAAA,MACL,aAAa,SAAS;AAAA,MACtB,WAAW,SAAS;AAAA,MACpB,GAAI,SAAS,SAAS,EAAE,OAAO,SAAS,MAAM;AAAA,MAC9C,GAAI,SAAS,WAAW,EAAE,SAAS,SAAS,QAAQ;AAAA,MACpD,GAAI,SAAS,gBAAgB,EAAE,cAAc,SAAS,aAAa;AAAA,MACnE,GAAI,SAAS,aAAa,EAAE,WAAW,SAAS,UAAU;AAAA,MAC1D,GAAI,SAAS,mBAAmB,EAAE,iBAAiB,SAAS,gBAAgB;AAAA,IAC9E;AAAA,EACF;AACF;;;AE7LO,IAAK,eAAL,kBAAKC,kBAAL;AACL,EAAAA,cAAA,YAAS;AACT,EAAAA,cAAA,UAAO;AACP,EAAAA,cAAA,WAAQ;AAHE,SAAAA;AAAA,GAAA;AASL,IAAK,mBAAL,kBAAKC,sBAAL;AACL,EAAAA,kBAAA,WAAQ;AACR,EAAAA,kBAAA,WAAQ;AACR,EAAAA,kBAAA,WAAQ;AACR,EAAAA,kBAAA,WAAQ;AACR,EAAAA,kBAAA,WAAQ;AACR,EAAAA,kBAAA,WAAQ;AACR,EAAAA,kBAAA,WAAQ;AACR,EAAAA,kBAAA,WAAQ;AACR,EAAAA,kBAAA,WAAQ;AACR,EAAAA,kBAAA,WAAQ;AACR,EAAAA,kBAAA,WAAQ;AACR,EAAAA,kBAAA,WAAQ;AAZE,SAAAA;AAAA,GAAA;AAkBL,IAAK,YAAL,kBAAKC,eAAL;AACL,EAAAA,WAAA,wBAAqB;AACrB,EAAAA,WAAA,cAAW;AACX,EAAAA,WAAA,cAAW;AACX,EAAAA,WAAA,wBAAqB;AACrB,EAAAA,WAAA,mBAAgB;AAChB,EAAAA,WAAA,gBAAa;AACb,EAAAA,WAAA,kBAAe;AACf,EAAAA,WAAA,iBAAc;AARJ,SAAAA;AAAA,GAAA;AA4CL,IAAM,mCAAN,MAAuC;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjB,YAAY,UAAkB,uBAAiC;AAC7D,QAAI,CAAC,UAAU,KAAK,GAAG;AACrB,YAAM,IAAI,6BAA6B,UAAU;AAAA,IACnD;AACA,QACE,CAAC,MAAM,QAAQ,qBAAqB,KACpC,sBAAsB,WAAW,GACjC;AACA,YAAM,IAAI,6BAA6B,uBAAuB;AAAA,IAChE;AACA,SAAK,QAAQ,EAAE,UAAU,sBAAsB;AAAA,EACjD;AAAA,EAEA,IAAI,aAAyC;AAC3C,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,QAAQ;AACb,WAAO,IAAI,0BAA0B,IAAI;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,UAAwB;AAClC,SAAK,MAAM,WAAW;AACtB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoB,kBAAkC;AACpD,SAAK,MAAM,mBAAmB,CAAC,GAAG,gBAAgB;AAClD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,2BACE,0BACM;AACN,SAAK,MAAM,2BAA2B,CAAC,GAAG,wBAAwB;AAClE,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,sCACE,uCACM;AACN,SAAK,MAAM,wCAAwC,CAAC,GAAG,qCAAqC;AAC5F,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,eAA6B;AAC5C,SAAK,MAAM,gBAAgB;AAC3B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,0BAA0B,wBAAsC;AAC9D,SAAK,MAAM,yBAAyB;AACpC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,qBAAmC;AACvD,SAAK,MAAM,sBAAsB;AACjC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB,kBAAgC;AACjD,SAAK,MAAM,mBAAmB;AAC9B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,0CAA0C,4CAA2D;AACnG,SAAK,MAAM,6CAA6C;AACxD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,uCAAuC,uCAAuD;AAC5F,SAAK,MAAM,wCAAwC,CAAC,GAAG,qCAAqC;AAC5F,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,kCAAkC,mCAAmD;AACnF,SAAK,MAAM,oCAAoC,CAAC,GAAG,iCAAiC;AACpF,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,kCAAkC,mCAAkD;AAClF,SAAK,MAAM,oCAAoC;AAC/C,WAAO;AAAA,EACT;AAGF;AAEA,IAAM,4BAAN,MAAgC;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,SAA2C;AACrD,UAAM,QAAQ,QAAQ;AACtB,SAAK,YAAY,MAAM;AACvB,SAAK,yBAAyB,CAAC,GAAG,MAAM,qBAAqB;AAC7D,SAAK,YAAY,MAAM;AACvB,SAAK,oBAAoB,MAAM,mBAC3B,CAAC,GAAG,MAAM,gBAAgB,IAC1B;AACJ,SAAK,4BAA4B,MAAM,2BACnC,CAAC,GAAG,MAAM,wBAAwB,IAClC;AACJ,SAAK,yCAAyC,MAAM,wCAChD,CAAC,GAAG,MAAM,qCAAqC,IAC/C;AACJ,SAAK,0BAA0B,MAAM;AACrC,SAAK,uBAAuB,MAAM;AAClC,SAAK,oBAAoB,MAAM;AAC/B,SAAK,iBAAiB,MAAM;AAC5B,SAAK,8CAA8C,MAAM;AACzD,SAAK,yCAAyC,MAAM,wCAChD,CAAC,GAAG,MAAM,qCAAqC,IAC/C;AACJ,SAAK,qCAAqC,MAAM,oCAC5C,CAAC,GAAG,MAAM,iCAAiC,IAC3C;AACJ,SAAK,qCAAqC,MAAM;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKO,SAAqC;AAC1C,WAAO;AAAA,MACL,UAAU,KAAK;AAAA,MACf,uBAAuB,CAAC,GAAG,KAAK,sBAAsB;AAAA,MAEtD,GAAI,KAAK,cAAc,UAAa,EAAE,UAAU,KAAK,UAAU;AAAA,MAC/D,GAAI,KAAK,sBAAsB,UAAa;AAAA,QAC1C,kBAAkB,CAAC,GAAG,KAAK,iBAAiB;AAAA,MAC9C;AAAA,MACA,GAAI,KAAK,8BAA8B,UAAa;AAAA,QAClD,0BAA0B,CAAC,GAAG,KAAK,yBAAyB;AAAA,MAC9D;AAAA,MACA,GAAI,KAAK,2CAA2C,UAAa;AAAA,QAC/D,uCAAuC,CAAC,GAAG,KAAK,sCAAsC;AAAA,MACxF;AAAA,MACA,GAAI,KAAK,4BAA4B,UAAa;AAAA,QAChD,wBAAwB,KAAK;AAAA,MAC/B;AAAA,MACA,GAAI,KAAK,yBAAyB,UAAa;AAAA,QAC7C,qBAAqB,KAAK;AAAA,MAC5B;AAAA,MACA,GAAI,KAAK,sBAAsB,UAAa;AAAA,QAC1C,kBAAkB,KAAK;AAAA,MACzB;AAAA,MACA,GAAI,KAAK,mBAAmB,UAAa;AAAA,QACvC,eAAe,KAAK;AAAA,MACtB;AAAA,MACA,GAAI,KAAK,gDAAgD,UAAa;AAAA,QACpE,4CAA4C,KAAK;AAAA,MACnD;AAAA,MACA,GAAI,KAAK,2CAA2C,UAAa;AAAA,QAC/D,uCAAuC,CAAC,GAAG,KAAK,sCAAsC;AAAA,MACxF;AAAA,MACA,GAAI,KAAK,uCAAuC,UAAa;AAAA,QAC3D,mCAAmC,CAAC,GAAG,KAAK,kCAAkC;AAAA,MAChF;AAAA,MACA,GAAI,KAAK,uCAAuC,UAAa;AAAA,QAC3D,mCAAmC,KAAK;AAAA,MAC1C;AAAA,IACF;AAAA,EACF;AACF;;;AC3RA,IAAM,WAAW;AAoCV,SAAS,SACd,SACA,OACA,MACQ;AACR,QAAM,aAAa,mBAAmB,OAAO;AAC7C,QAAM,YAAY,kBAAkB,KAAK;AACzC,QAAM,WAAW,iBAAiB,SAAS,IAAI;AAE/C,MAAI,CAAC,aAAa,CAAC,cAAc,CAAC,UAAU;AAC1C,UAAM,IAAI,oBAAoB,kCAAkC;AAAA,EAClE;AAGA,MAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,GAAG;AAClD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAQ,aAAa,YAAY;AACnC;AAKA,SAAS,mBAAmB,SAAsB;AAChD,QAAM,aAAa,QAAQ;AAC3B,MAAI,OAAO,eAAe,UAAU;AAClC,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,WAAW,MAAM,QAAQ;AACvC,SAAO,QAAQ,CAAC;AAClB;AAKA,SAAS,kBAAkB,OAAuC;AAChE,QAAM,cAAc,OAAO;AAC3B,MAAI,OAAO,gBAAgB,UAAU;AACnC,WAAO;AAAA,EACT;AACF;AAKA,SAAS,iBACP,SACA,MACoB;AACpB,MAAI,CAAC,QAAQ,OAAO,KAAK,iBAAiB,UAAU;AAClD,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,QAAQ,cAAc;AAC1C,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAGA,QAAM,gBAAgB,YACnB,YAAY,EACZ,SAAS,mCAAmC;AAC/C,MAAI,CAAC,eAAe;AAClB,WAAO;AAAA,EACT;AAEA,SAAO,KAAK;AACd;;;AC1HA;AAAA,EACE,0BAAAC;AAAA,EACA;AAAA,OACK;","names":["customFetch","customFetch","BearerMethod","SigningAlgorithm","GrantType","MissingClientAuthError"]} | ||
| {"version":3,"sources":["../src/api-client.ts","../src/errors.ts","../src/dpop-api.ts","../src/protected-resource-metadata.ts","../src/token.ts","../src/index.ts"],"sourcesContent":["import * as oauth from 'oauth4webapi';\nimport { createRemoteJWKSet, jwtVerify, customFetch } from 'jose';\nimport { AuthClient, TokenForConnectionError, MissingClientAuthError } from '@auth0/auth0-auth-js';\nimport {\n AccessTokenForConnectionOptions,\n ApiClientOptions,\n ConnectionTokenSet,\n DPoPOptions,\n ExchangeProfileOptions,\n TokenExchangeProfileResult,\n VerifyAccessTokenOptions,\n} from './types.js';\nimport {\n AuthError,\n InvalidConfigurationError,\n InvalidDpopProofError,\n InvalidRequestError,\n MissingRequiredArgumentError,\n VerifyAccessTokenError,\n} from './errors.js';\nimport { ALLOWED_DPOP_ALGORITHMS, buildChallenges, verifyDpopProof } from './dpop-api.js';\n\nexport class ApiClient {\n #serverMetadata: oauth.AuthorizationServer | undefined;\n readonly #options: ApiClientOptions;\n #jwks?: ReturnType<typeof createRemoteJWKSet>;\n readonly #authClient: AuthClient | undefined;\n\n constructor(options: ApiClientOptions) {\n if (options.dpop !== undefined && (typeof options.dpop !== 'object' || options.dpop === null)) {\n throw new InvalidConfigurationError('Invalid DPoP configuration: \"dpop\" must be an object');\n }\n\n if (options.dpop) {\n const { mode, iatOffset, iatLeeway } = options.dpop;\n if (mode !== undefined && !['allowed', 'required', 'disabled'].includes(mode)) {\n throw new InvalidConfigurationError(\n 'Invalid DPoP configuration: \"mode\" must be allowed, required, or disabled'\n );\n }\n if (iatOffset !== undefined) {\n if (!Number.isFinite(iatOffset)) {\n throw new InvalidConfigurationError('Invalid DPoP configuration: \"iatOffset\" must be a number');\n }\n if (iatOffset < 0) {\n throw new InvalidConfigurationError('Invalid DPoP configuration: \"iatOffset\" must be a non-negative number');\n }\n }\n if (iatLeeway !== undefined) {\n if (!Number.isFinite(iatLeeway)) {\n throw new InvalidConfigurationError('Invalid DPoP configuration: \"iatLeeway\" must be a number');\n }\n if (iatLeeway < 0) {\n throw new InvalidConfigurationError('Invalid DPoP configuration: \"iatLeeway\" must be a non-negative number');\n }\n }\n }\n\n this.#options = options;\n\n if (options.clientId) {\n this.#authClient = new AuthClient({\n domain: options.domain,\n clientId: options.clientId,\n clientSecret: options.clientSecret,\n clientAssertionSigningKey: options.clientAssertionSigningKey,\n clientAssertionSigningAlg: options.clientAssertionSigningAlg,\n customFetch: options.customFetch,\n });\n }\n\n if (!this.#options.audience) {\n throw new MissingRequiredArgumentError('audience');\n }\n }\n\n /**\n * Initialized the SDK by performing Metadata Discovery.\n */\n async #discover() {\n if (this.#serverMetadata) {\n return {\n serverMetadata: this.#serverMetadata,\n };\n }\n\n const issuer = new URL(`https://${this.#options.domain}`);\n const response = await oauth.discoveryRequest(issuer, {\n [oauth.customFetch]: this.#options.customFetch,\n });\n\n this.#serverMetadata = await oauth.processDiscoveryResponse(issuer, response);\n\n return {\n serverMetadata: this.#serverMetadata,\n };\n }\n\n /**\n * Verifies the provided access token against the ApiClient's configured audience.\n *\n * This method validates the JWT signature using the Auth0 tenant's JWKS and verifies\n * standard claims including issuer, expiration, and issued-at time. The audience claim\n * is verified against the audience configured when constructing the ApiClient.\n *\n * DPoP support:\n * - `dpop.mode` controls behavior: `allowed` (default) accepts Bearer or DPoP; `required` enforces DPoP; `disabled` ignores DPoP.\n * - When validating a DPoP-bound token, you must provide `scheme: 'dpop'`, the `dpopProof` header value, and the actual `httpMethod`/`httpUrl` used for the request.\n * - Bearer tokens omit DPoP params; DPoP params are validated together and proof binding is enforced.\n *\n * @param options Options containing the access token and optional required claims.\n * @see README.md and EXAMPLES.md for usage in allowed/required/disabled modes.\n * @returns Promise resolving to the verified token payload containing all JWT claims.\n * @throws {VerifyAccessTokenError} When verification fails due to invalid signature,\n * expired token, mismatched audience, or missing required claims.\n *\n * @example\n * ```typescript\n * @example Bearer token validation\n * const apiClient = new ApiClient({\n * domain: 'example.auth0.com',\n * audience: 'https://api.example.com', // This audience is used for verification\n * });\n * const payload = await apiClient.verifyAccessToken({\n * accessToken: 'eyJhbGc...',\n * });\n *\n * @example DPoP-bound token validation (allowed/required mode)\n * const apiClient = new ApiClient({\n * domain: 'example.auth0.com',\n * audience: 'https://api.example.com',\n * dpop: { mode: 'required' }, // default is 'allowed'\n * });\n * const dpopPayload = await apiClient.verifyAccessToken({\n * accessToken: 'eyJhbGc...', // JWT with cnf.jkt claim\n * scheme: 'dpop',\n * dpopProof: 'eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3A...', // value from DPoP header\n * httpMethod: 'GET', // actual request method\n * httpUrl: 'https://api.example.com/resource', // actual request URL\n * });\n * ```\n */\n async verifyAccessToken(options: VerifyAccessTokenOptions) {\n const mode: NonNullable<DPoPOptions['mode']> = this.#options.dpop?.mode ?? 'allowed';\n // Default timing options\n const iatOffset = this.#options.dpop?.iatOffset ?? 300;\n const iatLeeway = this.#options.dpop?.iatLeeway ?? 30;\n\n // Normalize scheme to lowercase; default to 'bearer' if not provided.\n const scheme = (options.scheme ?? 'bearer').toLowerCase();\n const dpopProof = options.dpopProof;\n const httpMethod = options.httpMethod;\n const httpUrl = options.httpUrl;\n const hasDpopParams = dpopProof !== undefined || httpMethod !== undefined || httpUrl !== undefined;\n\n // When DPoP is enabled, only 'bearer' and 'dpop' schemes are allowed.\n if (mode !== 'disabled' && scheme && !['bearer', 'dpop'].includes(scheme)) {\n const err = new InvalidRequestError('');\n err.cause = { code: 'invalid_auth_scheme' };\n throw this.#addChallenges(err, mode, scheme, { includeError: false });\n }\n\n // When DPoP is required, only 'dpop' scheme is allowed.\n if (mode === 'required' && scheme !== 'dpop') {\n const err = new InvalidRequestError('');\n err.cause = { code: 'invalid_auth_scheme' };\n throw this.#addChallenges(err, mode, scheme, {\n includeError: false,\n dpopSpecific: true,\n });\n }\n\n // When DPoP is disabled, only 'bearer' scheme is allowed.\n if (mode === 'disabled' && scheme && scheme !== 'bearer') {\n const err = new InvalidRequestError('');\n err.cause = { code: 'invalid_auth_scheme' };\n throw this.#addChallenges(err, mode, scheme, { includeError: false });\n }\n\n // When `scheme` is not provided, but `dpopProof`, `httpMethod`, or `httpUrl` are present.\n if (mode !== 'disabled' && hasDpopParams && options.scheme === undefined) {\n const err = new InvalidRequestError('');\n err.cause = { code: 'invalid_auth_scheme' };\n throw this.#addChallenges(err, mode, scheme, {\n includeError: false,\n dpopSpecific: true,\n });\n }\n\n // Access token must always be present.\n if (typeof options.accessToken !== 'string' || !options.accessToken) {\n throw this.#addChallenges(new VerifyAccessTokenError(''), mode, scheme, { includeError: false });\n }\n\n const { serverMetadata } = await this.#discover();\n\n this.#jwks ||= createRemoteJWKSet(new URL(serverMetadata!.jwks_uri!), {\n [customFetch]: this.#options.customFetch,\n });\n\n try {\n const { payload } = await jwtVerify(options.accessToken, this.#jwks, {\n issuer: this.#serverMetadata!.issuer,\n audience: this.#options.audience,\n algorithms: ['RS256'],\n requiredClaims: ['iat', 'exp', ...(options.requiredClaims || [])],\n });\n\n let cnfJkt: string | undefined;\n const cnf = (payload as Record<string, unknown> & { cnf?: unknown }).cnf;\n\n // Extract `jkt` from `cnf` claim if present\n if (cnf && typeof cnf === 'object') {\n const maybeJkt = (cnf as Record<string, unknown>).jkt;\n if (typeof maybeJkt === 'string') {\n cnfJkt = maybeJkt;\n }\n }\n\n const hasProof = typeof dpopProof === 'string';\n\n // DPoP validation logic\n if (mode !== 'disabled' && scheme === 'bearer' && hasProof && !cnfJkt) {\n throw this.#addChallenges(\n new InvalidRequestError('DPoP proof requires the DPoP authentication scheme, not Bearer'),\n mode,\n scheme\n );\n }\n\n // Determine if DPoP verification is needed\n const shouldVerifyDpop =\n mode !== 'disabled' && (mode === 'required' || scheme === 'dpop' || hasProof || !!cnfJkt);\n\n // Enforce DPoP binding when `cnf.jkt`\n if (mode !== 'disabled' && scheme === 'dpop' && !cnfJkt) {\n const err = new VerifyAccessTokenError('JWT Access Token has no jkt confirmation claim');\n err.cause = { code: 'dpop_binding_mismatch' };\n throw this.#addChallenges(err, mode, scheme, { dpopSpecific: true });\n }\n\n // Enforce scheme when token is DPoP-bound\n if (scheme === 'bearer' && cnfJkt && mode !== 'disabled') {\n throw this.#addChallenges(\n new VerifyAccessTokenError('DPoP-bound token requires the DPoP authentication scheme, not Bearer'),\n mode,\n scheme\n );\n }\n\n // If DPoP verification is not needed, return the payload early.\n if (!shouldVerifyDpop) {\n return payload;\n }\n\n // Validate DPoP proof presence and related params\n if (!dpopProof) {\n throw this.#addChallenges(new InvalidRequestError(''), mode, scheme, {\n dpopSpecific: true,\n includeError: false,\n });\n }\n\n // Validate HTTP method and URL presence\n if (typeof httpMethod !== 'string' || !httpMethod) {\n throw this.#addChallenges(\n new InvalidRequestError('HTTP method is required for DPoP validation'),\n mode,\n scheme,\n { dpopSpecific: true }\n );\n }\n\n // Validate HTTP URL presence\n if (typeof httpUrl !== 'string' || !httpUrl) {\n throw this.#addChallenges(new InvalidRequestError('HTTP URL is required for DPoP validation'), mode, scheme, {\n dpopSpecific: true,\n });\n }\n\n // Perform DPoP proof verification\n try {\n await verifyDpopProof({\n proof: dpopProof,\n accessToken: options.accessToken,\n method: httpMethod,\n url: httpUrl,\n cnfJkt,\n iatOffset,\n iatLeeway,\n algorithms: ALLOWED_DPOP_ALGORITHMS,\n });\n } catch (err) {\n if (\n err instanceof VerifyAccessTokenError ||\n err instanceof InvalidDpopProofError ||\n err instanceof InvalidRequestError\n ) {\n // Handle DPoP-specific errors with appropriate challenges\n throw this.#addChallenges(err as Error, mode, scheme, { dpopSpecific: true });\n }\n throw err;\n }\n\n return payload;\n } catch (e) {\n if (e instanceof AuthError) {\n throw e;\n }\n const message = e instanceof Error ? e.message : String(e);\n const err = new VerifyAccessTokenError(message);\n throw this.#addChallenges(err, mode, scheme);\n }\n }\n\n #addChallenges<T extends Error & { code?: string; headers?: Record<string, string | string[]> }>(\n err: T,\n mode: NonNullable<DPoPOptions['mode']>,\n scheme: string,\n params?: { dpopSpecific?: boolean; includeError?: boolean; target?: 'bearer' | 'dpop' }\n ) {\n const authErr = err;\n if (!authErr.headers) {\n const includeError = params?.includeError ?? true;\n const target = params?.target ?? (params?.dpopSpecific === true ? 'dpop' : scheme === 'dpop' ? 'dpop' : 'bearer');\n let challengeCode = authErr.code;\n if (authErr instanceof VerifyAccessTokenError) {\n challengeCode = 'invalid_token';\n } else if (authErr instanceof InvalidRequestError) {\n challengeCode = 'invalid_request';\n } else if (authErr instanceof InvalidDpopProofError) {\n challengeCode = 'invalid_dpop_proof';\n }\n const challengeParams =\n includeError && target === 'dpop'\n ? { dpopError: challengeCode, dpopErrorDescription: authErr.message }\n : includeError && target === 'bearer'\n ? { error: challengeCode, errorDescription: authErr.message }\n : {};\n authErr.headers = buildChallenges(mode, ALLOWED_DPOP_ALGORITHMS, challengeParams);\n }\n return authErr;\n }\n\n /**\n * Retrieves an access token for a connection.\n *\n * @param options - Options for retrieving an access token for a connection.\n *\n * @throws {TokenForConnectionError} If there was an issue requesting the access token.\n *\n * @returns The Connection Token Set, containing the access token for the connection, as well as additional information.\n */\n public async getAccessTokenForConnection(options: AccessTokenForConnectionOptions): Promise<ConnectionTokenSet> {\n if (!this.#authClient) {\n throw new TokenForConnectionError('Client credentials are required to use getAccessTokenForConnection');\n }\n\n const tokenEndpointResponse = await this.#authClient.getTokenForConnection({\n connection: options.connection,\n loginHint: options.loginHint,\n accessToken: options.accessToken,\n });\n\n return {\n accessToken: tokenEndpointResponse.accessToken,\n scope: tokenEndpointResponse.scope,\n expiresAt: tokenEndpointResponse.expiresAt,\n connection: options.connection,\n loginHint: options.loginHint,\n };\n }\n\n /**\n * Exchanges a token via a Custom Token Exchange Profile for a different API audience while preserving user identity (RFC 8693).\n *\n * This method supports **Custom Token Exchange** for custom token types via a configured Token Exchange Profile.\n *\n * For **Access Token Exchange with Token Vault** (external provider's access tokens), use {@link getAccessTokenForConnection} instead.\n *\n * **Note**: This method requires a confidential client (client credentials must be configured).\n * While Custom Token Exchange Early Access technically permits public clients, this implementation\n * currently requires client authentication. Public client support may be added in a future release.\n *\n * @param subjectToken - The raw token to be exchanged (without \"Bearer \" prefix)\n * @param options - Configuration for the token exchange\n *\n * @returns A promise that resolves with the {@link TokenExchangeProfileResult}\n *\n * @throws {TokenExchangeError} When client credentials are not configured or exchange fails\n *\n * @see {@link https://auth0.com/docs/authenticate/custom-token-exchange Custom Token Exchange Documentation}\n *\n * @example\n * ```typescript\n * // Exchange custom token (organization is optional)\n * const result = await apiClient.getTokenByExchangeProfile(\n * userToken,\n * {\n * subjectTokenType: 'urn:example:custom-token',\n * audience: 'https://api.backend.com',\n * organization: 'org_abc123', // Optional - Organization ID or name\n * scope: 'read:data write:data',\n * }\n * );\n * // When organization is provided, the access token will include the organization ID in its payload\n * ```\n */\n public async getTokenByExchangeProfile(\n subjectToken: string,\n options: ExchangeProfileOptions\n ): Promise<TokenExchangeProfileResult> {\n if (!this.#authClient) {\n throw new MissingClientAuthError();\n }\n\n const response = await this.#authClient.exchangeToken({\n subjectTokenType: options.subjectTokenType,\n subjectToken,\n audience: options.audience,\n scope: options.scope,\n requestedTokenType: options.requestedTokenType,\n organization: options.organization,\n });\n\n return {\n accessToken: response.accessToken,\n expiresAt: response.expiresAt,\n ...(response.scope && { scope: response.scope }),\n ...(response.idToken && { idToken: response.idToken }),\n ...(response.refreshToken && { refreshToken: response.refreshToken }),\n ...(response.tokenType && { tokenType: response.tokenType }),\n ...(response.issuedTokenType && { issuedTokenType: response.issuedTokenType }),\n };\n }\n}\n","/**\n * Error thrown when a required argument is missing.\n */\nexport class MissingRequiredArgumentError extends Error {\n public code: string = 'missing_required_argument_error';\n\n constructor(argument: string) {\n super(`The argument '${argument}' is required but was not provided.`);\n this.name = 'MissingRequiredArgumentError';\n }\n}\n\n/**\n * Error thrown when the SDK is misconfigured at instantiation time.\n */\nexport class InvalidConfigurationError extends Error {\n public code: string = 'invalid_configuration_error';\n constructor(message: string) {\n super(message);\n this.name = 'InvalidConfigurationError';\n }\n}\n\n/**\n * Base authentication error shape used across the SDK.\n */\nexport class AuthError extends Error {\n public code: string;\n public statusCode?: number;\n public headers?: Record<string, string | string[]>;\n public declare cause?: AuthErrorCause;\n\n constructor(message: string, code: string, statusCode?: number, headers?: Record<string, string | string[]>) {\n super(message);\n this.name = this.constructor.name;\n this.code = code;\n this.statusCode = statusCode;\n this.headers = headers;\n }\n}\n\nexport type AuthErrorCause = {\n code: string;\n};\n\n/**\n * Error thrown when the transaction is missing.\n */\nexport class MissingTransactionError extends AuthError {\n constructor(message?: string) {\n super(message ?? 'The transaction is missing.', 'missing_transaction_error');\n }\n}\n\n/**\n * Error thrown when verifying the access token.\n */\nexport class VerifyAccessTokenError extends AuthError {\n constructor(message: string, headers?: Record<string, string | string[]>) {\n super(message, 'verify_access_token_error', 401, headers);\n }\n}\n\n/**\n * Error thrown when the DPoP proof fails validation.\n */\nexport class InvalidDpopProofError extends AuthError {\n constructor(message = '', headers?: Record<string, string>) {\n super(message, 'invalid_dpop_proof', 400, headers);\n }\n}\n\n/**\n * Error thrown when request is missing a valid token or\n * multiple auth methods used\n */\nexport class InvalidRequestError extends AuthError {\n constructor(message: string, headers?: Record<string, string>) {\n super(message, 'invalid_request', 400, headers);\n }\n}\n","import { createHash } from 'crypto';\nimport {\n EmbeddedJWK,\n base64url,\n calculateJwkThumbprint,\n jwtVerify,\n type JWK,\n type JWTHeaderParameters,\n type JWTPayload,\n} from 'jose';\nimport { InvalidDpopProofError, InvalidRequestError, VerifyAccessTokenError } from './errors.js';\n\nexport type ChallengeParams = {\n error?: string;\n errorDescription?: string;\n dpopError?: string;\n dpopErrorDescription?: string;\n};\n\nexport type DPoPVerificationOptions = {\n proof: string;\n accessToken: string;\n method: string;\n url: string;\n cnfJkt?: string;\n iatOffset: number;\n iatLeeway: number;\n algorithms: readonly string[];\n};\n\nexport const DPOP_ERROR_MESSAGES = {\n PROOF_VERIFICATION_FAILED: 'Failed to verify DPoP proof',\n MISSING_PROOF: 'Missing DPoP proof',\n MULTIPLE_PROOFS: 'Multiple DPoP proofs are not allowed',\n MISSING_CNF_JKT: 'Access token is missing cnf.jkt confirmation claim',\n INVALID_IAT: '\"iat\" claim must be a number',\n INVALID_JTI: '\"jti\" claim must be a string',\n INVALID_HTM: '\"htm\" claim must be a string',\n INVALID_HTU: '\"htu\" claim must be a string',\n INVALID_HTU_URL: '\"htu\" claim URL must be valid URL',\n INVALID_HTU_URL_HOST: 'Invalid \"htu\" claim URL: Host contains illegal characters or format',\n INVALID_HTU_URL_PATH: 'Invalid \"htu\" claim URL: Path must not start with \"//\"',\n INVALID_HTTP_URL: '\"httpUrl\" must be a valid URL',\n INVALID_HTTP_URL_HOST: 'Invalid \"httpUrl\": Host contains illegal characters or format',\n INVALID_HTTP_URL_PATH: 'Invalid \"httpUrl\": Path must not start with \"//\"',\n INVALID_ATH: '\"ath\" claim must be a string',\n IAT_MISMATCH: 'DPoP proof \"iat\" is outside the acceptable range',\n HTM_MISMATCH: 'DPoP proof \"htm\" mismatch',\n HTU_MISMATCH: 'DPoP proof \"htu\" mismatch',\n ATH_MISMATCH: 'DPoP proof \"ath\" mismatch',\n JWT_AT_MISMATCH: 'JWT Access Token confirmation mismatch',\n MISSING_JWK: 'Missing or invalid jwk in DPoP proof header',\n PRIVATE_KEY_MATERIAL: 'DPoP proof header must not contain private key material',\n};\n\n// Currently, only ES256 is supported.\nexport const ALLOWED_DPOP_ALGORITHMS = ['ES256'] as const;\n\nfunction normalizePercentEncodings(s: string): string {\n const UNRESERVED = /[A-Za-z0-9\\-._~]/;\n return s.replace(/%[0-9a-fA-F]{2}/g, (m) => {\n const byte = parseInt(m.slice(1), 16);\n const ch = String.fromCharCode(byte);\n return UNRESERVED.test(ch) ? ch : `%${m.slice(1).toUpperCase()}`;\n });\n}\n\n/**\n * Normalize a URL for DPoP `htu` comparison.\n *\n * Behavior:\n * - Parses with WHATWG `URL`; rejects invalid input.\n * - Host must be a valid hostname with optional `:port`; no schemes, slashes, queries, or fragments allowed.\n * - For `source === 'request'`: path must start with `/` and not look like a protocol.\n * - Removes query and fragment.\n * - Normalizes percent-encodings in the path.\n * - Returns `origin + pathname` for reliable comparison.\n *\n * @param input - The URL to normalize (either the inbound request URL or the `htu` claim).\n * @param source - Indicates whether `input` is from the HTTP request (`'request'`) or the DPoP proof (`'proof'`).\n * @returns The normalized URL string in the form `origin + pathname` (no query or fragment).\n * @throws {InvalidRequestError} When `source === 'request'` and parsing/validation fails.\n * @throws {InvalidDPoPProofError} When `source === 'proof'` and parsing/validation fails.\n */\nexport function normalizeUrl(input: string, source: 'request' | 'proof'): string {\n const HOST_RE = /^(?:[A-Za-z0-9.-]+|\\[[0-9A-Fa-f:.]+\\])(?::\\d{1,5})?$/;\n const PROTOCOL_IN_PATH_RE = /^\\/[a-z][a-z0-9+.-]*:\\/\\//i;\n\n try {\n const url = new URL(input);\n const host = url.host;\n\n if (\n typeof host !== 'string' ||\n host.length === 0 ||\n host.includes('://') ||\n host.includes('/') ||\n host.includes('?') ||\n host.includes('#') ||\n !HOST_RE.test(host)\n ) {\n if (source === 'request') {\n throw new InvalidRequestError(DPOP_ERROR_MESSAGES.INVALID_HTTP_URL_HOST);\n } else {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTU_URL_HOST);\n }\n }\n\n if (source === 'request') {\n const path = url.pathname;\n if (PROTOCOL_IN_PATH_RE.test(path)) {\n throw new InvalidRequestError(DPOP_ERROR_MESSAGES.INVALID_HTTP_URL_PATH);\n }\n }\n\n url.search = '';\n url.hash = '';\n url.pathname = normalizePercentEncodings(url.pathname);\n\n return url.origin + url.pathname;\n } catch (err) {\n if (source === 'request') {\n if (err instanceof InvalidRequestError) throw err;\n throw new InvalidRequestError(DPOP_ERROR_MESSAGES.INVALID_HTTP_URL);\n }\n if (err instanceof InvalidDpopProofError) throw err;\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTU_URL);\n }\n}\n\nasync function verifyProofJwt(\n proof: string,\n algorithms: readonly string[]\n): Promise<{ header: JWTHeaderParameters; claims: JWTPayload }> {\n try {\n const { payload, protectedHeader } = await jwtVerify(proof, EmbeddedJWK, {\n typ: 'dpop+jwt',\n algorithms: [...algorithms],\n });\n\n return { header: protectedHeader, claims: payload };\n } catch (err) {\n let message = DPOP_ERROR_MESSAGES.PROOF_VERIFICATION_FAILED;\n if (err instanceof Error && err.message) {\n message = err.message;\n }\n throw new InvalidDpopProofError(message);\n }\n}\n\nexport async function verifyDpopProof(options: DPoPVerificationOptions): Promise<void> {\n const { proof, accessToken, method, url, cnfJkt, iatOffset, iatLeeway, algorithms } = options;\n\n if (!proof) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.MISSING_PROOF);\n }\n\n if (proof.includes(',')) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.MULTIPLE_PROOFS);\n }\n\n if (!cnfJkt) {\n const err = new VerifyAccessTokenError(DPOP_ERROR_MESSAGES.MISSING_CNF_JKT);\n err.cause = { code: 'dpop_binding_mismatch' };\n throw err;\n }\n\n const normalizedRequestUrl = normalizeUrl(url, 'request');\n const { claims, header } = await verifyProofJwt(proof, algorithms);\n\n const { htm, htu, iat, ath, jti } = claims;\n\n if (typeof jti !== 'string' || !jti) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_JTI);\n }\n\n // Verify `iat` claim is present and is a number. This is redundant with `jose` but we double-check here.\n if (typeof iat !== 'number') {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_IAT);\n }\n\n const now = Math.floor(Date.now() / 1000);\n if (iat < now - iatOffset || iat > now + iatLeeway) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.IAT_MISMATCH);\n }\n\n if (typeof htm !== 'string') {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTM);\n }\n\n if (htm.toUpperCase() !== method.toUpperCase()) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.HTM_MISMATCH);\n }\n\n if (typeof htu !== 'string') {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_HTU);\n }\n\n const normalizedProofUrl = normalizeUrl(htu, 'proof');\n if (normalizedProofUrl !== normalizedRequestUrl) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.HTU_MISMATCH);\n }\n\n if (typeof ath !== 'string') {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.INVALID_ATH);\n }\n\n const hash = createHash('sha256').update(accessToken).digest();\n const encodedHash = base64url.encode(hash);\n if (ath !== encodedHash) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.ATH_MISMATCH);\n }\n\n // Verify the JWK is not malformed. This is redundant with `jose` but we double-check here.\n const jwk = header.jwk as JWK | undefined;\n if (!jwk || typeof jwk !== 'object') {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.MISSING_JWK);\n }\n\n // Ensure the JWK does not contain private key material. This is redundant with `jose` but we double-check here.\n if ('d' in jwk) {\n throw new InvalidDpopProofError(DPOP_ERROR_MESSAGES.PRIVATE_KEY_MATERIAL);\n }\n\n const thumbprint = await calculateJwkThumbprint(jwk);\n if (thumbprint !== cnfJkt) {\n const err = new VerifyAccessTokenError(DPOP_ERROR_MESSAGES.JWT_AT_MISMATCH);\n err.cause = { code: 'dpop_binding_mismatch' };\n throw err;\n }\n}\n\nexport function buildChallenges(\n dpopMode: 'allowed' | 'required' | 'disabled',\n algorithms: readonly string[] = ALLOWED_DPOP_ALGORITHMS,\n params: ChallengeParams = {}\n): Record<string, string | string[]> {\n const bearerParams = [\n 'realm=\"api\"',\n params.error ? `error=\"${params.error}\"` : undefined,\n params.errorDescription ? `error_description=\"${params.errorDescription}\"` : undefined,\n ]\n .filter(Boolean)\n .join(', ');\n\n const dpopParams = [\n params.dpopError ? `error=\"${params.dpopError}\"` : undefined,\n params.dpopErrorDescription ? `error_description=\"${params.dpopErrorDescription}\"` : undefined,\n `algs=\"${algorithms.join(' ')}\"`,\n ]\n .filter(Boolean)\n .join(', ');\n\n const bearerValue = `Bearer ${bearerParams}`;\n const dpopValue = `DPoP ${dpopParams}`;\n\n const challenges: string[] = [];\n\n if (dpopMode === 'allowed') {\n challenges.push(bearerValue, dpopValue);\n } else if (dpopMode === 'required') {\n challenges.push(dpopValue);\n } else {\n challenges.push(bearerValue);\n }\n\n return {\n 'www-authenticate': challenges,\n };\n}\n","/**\n * RFC 9728 - OAuth 2.0 Protected Resource Metadata\n * https://datatracker.ietf.org/doc/html/rfc9728\n */\n\nimport { MissingRequiredArgumentError } from \"./errors.js\";\n\n/**\n * Supported methods of sending an OAuth 2.0 bearer token\n */\nexport enum BearerMethod {\n HEADER = \"header\",\n BODY = \"body\",\n QUERY = \"query\",\n}\n\n/**\n * Supported signing algorithms\n */\nexport enum SigningAlgorithm {\n RS256 = \"RS256\",\n RS384 = \"RS384\",\n RS512 = \"RS512\",\n ES256 = \"ES256\",\n ES384 = \"ES384\",\n ES512 = \"ES512\",\n PS256 = \"PS256\",\n PS384 = \"PS384\",\n PS512 = \"PS512\",\n HS256 = \"HS256\",\n HS384 = \"HS384\",\n HS512 = \"HS512\",\n}\n\n/**\n * Grant types supported\n */\nexport enum GrantType {\n AUTHORIZATION_CODE = \"authorization_code\",\n IMPLICIT = \"implicit\",\n PASSWORD = \"password\",\n CLIENT_CREDENTIALS = \"client_credentials\",\n REFRESH_TOKEN = \"refresh_token\",\n JWT_BEARER = \"urn:ietf:params:oauth:grant-type:jwt-bearer\",\n SAML2_BEARER = \"urn:ietf:params:oauth:grant-type:saml2-bearer\",\n DEVICE_CODE = \"urn:ietf:params:oauth:grant-type:device_code\",\n}\n\n/**\n * Interface for Protected Resource Metadata\n */\nexport interface IProtectedResourceMetadata {\n resource: string;\n authorization_servers: string[];\n jwks_uri?: string;\n scopes_supported?: string[];\n bearer_methods_supported?: BearerMethod[];\n resource_signing_alg_values_supported?: SigningAlgorithm[];\n resource_name?: string;\n resource_documentation?: string;\n resource_policy_uri?: string;\n resource_tos_uri?: string;\n tls_client_certificate_bound_access_tokens?: boolean;\n authorization_details_types_supported?: string[];\n dpop_signing_alg_values_supported?: string[];\n dpop_bound_access_tokens_required?: boolean;\n}\n\n/**\n * Builder for creating a ProtectedResourceMetadata instance\n *\n * @example\n * ```typescript\n * const metadata = new ProtectedResourceMetadataBuilder('https://api.example.com', ['https://auth.example.com'])\n * .withJwksUri('https://api.example.com/.well-known/jwks.json')\n * .withScopesSupported(['read', 'write'])\n * .build();\n * // serialize to json\n * const json = metadata.toJSON();\n * ```\n */\nexport class ProtectedResourceMetadataBuilder {\n private readonly props: Partial<IProtectedResourceMetadata> &\n Pick<IProtectedResourceMetadata, \"resource\" | \"authorization_servers\">;\n\n /**\n * Constructor for the builder\n * @param resource - The protected resource identifier (REQUIRED)\n * @param authorization_servers - Array of authorization server URLs (REQUIRED)\n */\n constructor(resource: string, authorization_servers: string[]) {\n if (!resource?.trim()) {\n throw new MissingRequiredArgumentError(\"resource\");\n }\n if (\n !Array.isArray(authorization_servers) ||\n authorization_servers.length === 0\n ) {\n throw new MissingRequiredArgumentError(\"authorization_servers\");\n }\n this.props = { resource, authorization_servers };\n }\n\n get properties(): IProtectedResourceMetadata {\n return this.props;\n }\n\n /**\n * Builds the ProtectedResourceMetadata\n */\n public build() {\n return new ProtectedResourceMetadata(this);\n }\n\n /**\n * Builder method to add JWKS URI\n */\n withJwksUri(jwks_uri: string): this {\n this.props.jwks_uri = jwks_uri;\n return this;\n }\n\n /**\n * Builder method to add supported scopes\n */\n withScopesSupported(scopes_supported: string[]): this {\n this.props.scopes_supported = [...scopes_supported];\n return this;\n }\n\n /**\n * Builder method to add supported bearer methods\n */\n withBearerMethodsSupported(\n bearer_methods_supported: BearerMethod[]\n ): this {\n this.props.bearer_methods_supported = [...bearer_methods_supported];\n return this;\n }\n\n /**\n * Builder method to add supported resource signing algorithms\n */\n withResourceSigningAlgValuesSupported(\n resource_signing_alg_values_supported: SigningAlgorithm[]\n ): this {\n this.props.resource_signing_alg_values_supported = [...resource_signing_alg_values_supported];\n return this;\n }\n\n /**\n * Builder method to add resource_name\n */\n withResourceName(resource_name: string): this {\n this.props.resource_name = resource_name;\n return this;\n }\n\n /**\n * Builder method to add resource documentation URL\n */\n withResourceDocumentation(resource_documentation: string): this {\n this.props.resource_documentation = resource_documentation;\n return this;\n }\n\n /**\n * Builder method to add resource policy URI\n */\n withResourcePolicyUri(resource_policy_uri: string): this {\n this.props.resource_policy_uri = resource_policy_uri;\n return this;\n }\n\n /**\n * Builder method to add resource terms of service URI\n */\n withResourceTosUri(resource_tos_uri: string): this {\n this.props.resource_tos_uri = resource_tos_uri;\n return this;\n }\n\n /**\n * Builder method to enable TLS client certificate bound access tokens\n */\n withTlsClientCertificateBoundAccessTokens(tls_client_certificate_bound_access_tokens: boolean): this {\n this.props.tls_client_certificate_bound_access_tokens = tls_client_certificate_bound_access_tokens;\n return this;\n }\n\n /**\n * Builder method to add supported authorization details types\n */\n withAuthorizationDetailsTypesSupported(authorization_details_types_supported: string[]): this {\n this.props.authorization_details_types_supported = [...authorization_details_types_supported];\n return this;\n }\n\n /**\n * Builder method to add supported DPoP signing algorithms\n */\n withDpopSigningAlgValuesSupported(dpop_signing_alg_values_supported: string[]): this {\n this.props.dpop_signing_alg_values_supported = [...dpop_signing_alg_values_supported];\n return this;\n }\n\n /**\n * Builder method to require DPoP bound access tokens\n */\n withDpopBoundAccessTokensRequired(dpop_bound_access_tokens_required: boolean): this {\n this.props.dpop_bound_access_tokens_required = dpop_bound_access_tokens_required;\n return this;\n }\n\n\n}\n\nexport class ProtectedResourceMetadata {\n readonly #resource: string;\n readonly #authorization_servers: string[];\n readonly #jwks_uri?: string;\n readonly #scopes_supported?: string[];\n readonly #bearer_methods_supported?: BearerMethod[];\n readonly #resource_signing_alg_values_supported?: SigningAlgorithm[];\n readonly #resource_documentation?: string;\n readonly #resource_policy_uri?: string;\n readonly #resource_tos_uri?: string;\n readonly #resource_name?: string;\n readonly #tls_client_certificate_bound_access_tokens?: boolean;\n readonly #authorization_details_types_supported?: string[];\n readonly #dpop_signing_alg_values_supported?: string[];\n readonly #dpop_bound_access_tokens_required?: boolean;\n\n constructor(builder: ProtectedResourceMetadataBuilder) {\n const props = builder.properties;\n this.#resource = props.resource;\n this.#authorization_servers = [...props.authorization_servers];\n this.#jwks_uri = props.jwks_uri;\n this.#scopes_supported = props.scopes_supported\n ? [...props.scopes_supported]\n : undefined;\n this.#bearer_methods_supported = props.bearer_methods_supported\n ? [...props.bearer_methods_supported]\n : undefined;\n this.#resource_signing_alg_values_supported = props.resource_signing_alg_values_supported\n ? [...props.resource_signing_alg_values_supported]\n : undefined;\n this.#resource_documentation = props.resource_documentation;\n this.#resource_policy_uri = props.resource_policy_uri;\n this.#resource_tos_uri = props.resource_tos_uri;\n this.#resource_name = props.resource_name;\n this.#tls_client_certificate_bound_access_tokens = props.tls_client_certificate_bound_access_tokens;\n this.#authorization_details_types_supported = props.authorization_details_types_supported\n ? [...props.authorization_details_types_supported]\n : undefined;\n this.#dpop_signing_alg_values_supported = props.dpop_signing_alg_values_supported\n ? [...props.dpop_signing_alg_values_supported]\n : undefined;\n this.#dpop_bound_access_tokens_required = props.dpop_bound_access_tokens_required;\n }\n\n /**\n * Convert to JSON representation\n */\n public toJSON(): IProtectedResourceMetadata {\n return {\n resource: this.#resource,\n authorization_servers: [...this.#authorization_servers],\n\n ...(this.#jwks_uri !== undefined && { jwks_uri: this.#jwks_uri }),\n ...(this.#scopes_supported !== undefined && {\n scopes_supported: [...this.#scopes_supported],\n }),\n ...(this.#bearer_methods_supported !== undefined && {\n bearer_methods_supported: [...this.#bearer_methods_supported],\n }),\n ...(this.#resource_signing_alg_values_supported !== undefined && {\n resource_signing_alg_values_supported: [...this.#resource_signing_alg_values_supported],\n }),\n ...(this.#resource_documentation !== undefined && {\n resource_documentation: this.#resource_documentation,\n }),\n ...(this.#resource_policy_uri !== undefined && {\n resource_policy_uri: this.#resource_policy_uri,\n }),\n ...(this.#resource_tos_uri !== undefined && {\n resource_tos_uri: this.#resource_tos_uri,\n }),\n ...(this.#resource_name !== undefined && {\n resource_name: this.#resource_name,\n }),\n ...(this.#tls_client_certificate_bound_access_tokens !== undefined && {\n tls_client_certificate_bound_access_tokens: this.#tls_client_certificate_bound_access_tokens,\n }),\n ...(this.#authorization_details_types_supported !== undefined && {\n authorization_details_types_supported: [...this.#authorization_details_types_supported],\n }),\n ...(this.#dpop_signing_alg_values_supported !== undefined && {\n dpop_signing_alg_values_supported: [...this.#dpop_signing_alg_values_supported],\n }),\n ...(this.#dpop_bound_access_tokens_required !== undefined && {\n dpop_bound_access_tokens_required: this.#dpop_bound_access_tokens_required,\n }),\n };\n }\n}\n","import { InvalidRequestError } from './errors.js';\n/**\n * Header-like object that can represent headers from different HTTP frameworks\n */\nexport type HeadersLike = Record<string, unknown> & {\n authorization?: string;\n 'content-type'?: string;\n};\n\n/**\n * Query-like object for URL query parameters\n */\nexport type QueryLike = Record<string, unknown> & { access_token?: string };\n\n/**\n * Body-like object for form-encoded request body\n */\nexport type BodyLike = QueryLike;\n\n/**\n * Regular expression to match Bearer token in Authorization header\n */\nconst TOKEN_RE = /^Bearer (.+)$/i;\n\n/**\n * Extracts a Bearer token from HTTP request according to RFC 6750.\n * Supports all three methods defined in the RFC:\n * - Authorization header (Section 2.1)\n * - Form-encoded body parameter (Section 2.2)\n * - URI query parameter (Section 2.3)\n *\n * @param headers - HTTP headers object\n * @param query - Query parameters object (optional)\n * @param body - Request body object (optional)\n * @returns The extracted token string\n * @throws {InvalidRequestError} When no token is found or multiple methods are used\n *\n * @example\n * ```typescript\n * // Authorization header method (recommended)\n * const token1 = getToken({ authorization: 'Bearer mF_9.B5f-4.1JqM' });\n *\n * // Query parameter method\n * const token2 = getToken({}, { access_token: 'mF_9.B5f-4.1JqM' });\n *\n * // Form body method\n * const token3 = getToken(\n * { 'content-type': 'application/x-www-form-urlencoded' },\n * {},\n * { access_token: 'mF_9.B5f-4.1JqM' }\n * );\n *\n * // Express.js usage\n * const token4 = getToken(req.headers, req.query, req.body);\n * ```\n *\n * @see https://datatracker.ietf.org/doc/html/rfc6750#section-2 - RFC 6750 Section 2\n */\nexport function getToken(\n headers: HeadersLike,\n query?: QueryLike,\n body?: BodyLike\n): string {\n const fromHeader = getTokenFromHeader(headers);\n const fromQuery = getTokenFromQuery(query);\n const fromBody = getTokenFromBody(headers, body);\n\n if (!fromQuery && !fromHeader && !fromBody) {\n throw new InvalidRequestError('No Bearer token found in request');\n }\n\n // If multiple methods are used, throw an error\n if (+!!fromQuery + +!!fromBody + +!!fromHeader > 1) {\n throw new InvalidRequestError(\n 'More than one method used for authentication'\n );\n }\n\n return (fromQuery || fromBody || fromHeader) as string;\n}\n\n/**\n * Extract token from Authorization header\n */\nfunction getTokenFromHeader(headers: HeadersLike) {\n const authHeader = headers.authorization;\n if (typeof authHeader !== 'string') {\n return undefined;\n }\n\n const match = authHeader.match(TOKEN_RE);\n return match?.[1];\n}\n\n/**\n * Extract token from query parameters\n */\nfunction getTokenFromQuery(query?: QueryLike): string | undefined {\n const accessToken = query?.access_token;\n if (typeof accessToken === 'string') {\n return accessToken;\n }\n}\n\n/**\n * Extract token from form-encoded body\n */\nfunction getTokenFromBody(\n headers: HeadersLike,\n body?: BodyLike\n): string | undefined {\n if (!body || typeof body.access_token !== 'string') {\n return undefined;\n }\n\n const contentType = headers['content-type'];\n if (!contentType) {\n return undefined;\n }\n\n // Handle content-type with charset, e.g., \"application/x-www-form-urlencoded; charset=utf-8\"\n const isFormEncoded = contentType\n .toLowerCase()\n .includes('application/x-www-form-urlencoded');\n if (!isFormEncoded) {\n return undefined;\n }\n\n return body.access_token;\n}\n","export { ApiClient } from './api-client.js';\nexport * from './protected-resource-metadata.js';\nexport * from './errors.js';\nexport * from './types.js';\nexport { getToken } from './token.js';\nexport type { QueryLike, HeadersLike, BodyLike } from './token.js';\n\n// Re-export shared errors from auth0-auth-js for convenience\nexport {\n MissingClientAuthError,\n TokenExchangeError,\n} from '@auth0/auth0-auth-js';\n"],"mappings":"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","names":["jwtVerify","customFetch","customFetch","jwtVerify","BearerMethod","SigningAlgorithm","GrantType","MissingClientAuthError"]} |
+1
-1
| { | ||
| "name": "@auth0/auth0-api-js", | ||
| "version": "1.3.0", | ||
| "version": "1.4.0", | ||
| "description": "Auth0 Authentication SDK for API's on JavaScript runtimes", | ||
@@ -5,0 +5,0 @@ "author": "Auth0", |
+32
-2
@@ -72,4 +72,34 @@ The `@auth0/auth0-api-js` library allows for securing API's running on a JavaScript runtime. | ||
| ### 4. Protected Resource Metadata (RFC 9728) | ||
| ### 4. Verify DPoP Access Tokens | ||
| The `verifyAccessToken` method also supports validating DPoP-bound access tokens. | ||
| When using `DPoP`, you must also supply `scheme`, `dpopProof`, `httpMethod`, and `httpUrl` from the incoming HTTP request so the SDK can validate the proof and ensure the token is bound to that request. | ||
| ```ts | ||
| const apiClient = new ApiClient({ | ||
| domain: '<AUTH0_DOMAIN>', | ||
| audience: '<AUTH0_AUDIENCE>', | ||
| dpop: { | ||
| mode: 'required', // optional, defaults to 'allowed' | ||
| iatOffset: 400, // optional, defaults to 300 seconds | ||
| iatLeeway: 30, // optional, defaults to 30 seconds | ||
| }, | ||
| }); | ||
| const accessToken = '...'; | ||
| const decodedAndVerifiedToken = await apiClient.verifyAccessToken({ | ||
| accessToken, | ||
| requiredClaims: ['my_custom_claim'], | ||
| // Options required for DPoP bound token verification | ||
| scheme: '<AUTHENTICATION_SCHEME>', | ||
| dpopProof: '<DPOP_PROOF_JWT>', | ||
| httpMethod: '<HTTP_METHOD>', | ||
| httpUrl: '<HTTP_REQUEST_URL>' | ||
| }); | ||
| ``` | ||
| See the [DPoP Authentication](https://github.com/auth0/auth0-auth-js/blob/main/packages/auth0-api-js/EXAMPLES.md#dpop-authentication) in [EXAMPLES.md](https://github.com/auth0/auth0-auth-js/blob/main/packages/auth0-api-js/EXAMPLES.md) for more examples and details. | ||
| ### 5. Protected Resource Metadata (RFC 9728) | ||
| The SDK supports OAuth 2.0 Protected Resource Metadata as defined in [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728): | ||
@@ -102,3 +132,3 @@ | ||
| ### 5. Token Exchange | ||
| ### 6. Token Exchange | ||
@@ -105,0 +135,0 @@ The SDK supports RFC 8693 OAuth 2.0 Token Exchange, allowing you to exchange tokens for different API audiences while preserving user identity. |
243181
67.78%2351
55.9%219
15.87%