@clerk/backend
Version:
Clerk Backend SDK - REST Client for Backend API & JWT verification utilities
1 lines • 494 kB
Source Map (JSON)
{"version":3,"sources":["../../../node_modules/.pnpm/cookie@1.0.2/node_modules/cookie/src/index.ts","../src/constants.ts","../src/createRedirect.ts","../src/util/mergePreDefinedOptions.ts","../src/util/optionsAssertions.ts","../src/tokens/authenticateContext.ts","../src/tokens/tokenTypes.ts","../src/tokens/authObjects.ts","../src/util/path.ts","../src/api/endpoints/AbstractApi.ts","../src/api/endpoints/ActorTokenApi.ts","../src/api/endpoints/AccountlessApplicationsAPI.ts","../src/api/endpoints/AllowlistIdentifierApi.ts","../src/api/endpoints/APIKeysApi.ts","../src/api/endpoints/BetaFeaturesApi.ts","../src/api/endpoints/BlocklistIdentifierApi.ts","../src/api/endpoints/ClientApi.ts","../src/api/endpoints/DomainApi.ts","../src/api/endpoints/EmailAddressApi.ts","../src/api/endpoints/IdPOAuthAccessTokenApi.ts","../src/api/endpoints/InstanceApi.ts","../src/api/endpoints/InvitationApi.ts","../src/api/endpoints/MachineApi.ts","../src/api/endpoints/M2MTokenApi.ts","../src/api/endpoints/JwksApi.ts","../src/api/endpoints/JwtTemplatesApi.ts","../src/api/endpoints/OrganizationApi.ts","../src/api/endpoints/OAuthApplicationsApi.ts","../src/api/endpoints/PhoneNumberApi.ts","../src/api/endpoints/ProxyCheckApi.ts","../src/api/endpoints/RedirectUrlApi.ts","../src/api/endpoints/SamlConnectionApi.ts","../src/api/endpoints/SessionApi.ts","../src/api/endpoints/SignInTokenApi.ts","../src/api/endpoints/SignUpApi.ts","../src/api/endpoints/TestingTokenApi.ts","../src/api/endpoints/UserApi.ts","../src/api/endpoints/WaitlistEntryApi.ts","../src/api/endpoints/WebhookApi.ts","../src/api/endpoints/BillingApi.ts","../src/api/request.ts","../../../node_modules/.pnpm/map-obj@5.0.2/node_modules/map-obj/index.js","../../../node_modules/.pnpm/change-case@5.4.4/node_modules/change-case/src/index.ts","../../../node_modules/.pnpm/snakecase-keys@9.0.2/node_modules/snakecase-keys/index.js","../src/api/resources/AccountlessApplication.ts","../src/api/resources/ActorToken.ts","../src/api/resources/AllowlistIdentifier.ts","../src/api/resources/APIKey.ts","../src/api/resources/BlocklistIdentifier.ts","../src/api/resources/Session.ts","../src/api/resources/Client.ts","../src/api/resources/CnameTarget.ts","../src/api/resources/Cookies.ts","../src/api/resources/DeletedObject.ts","../src/api/resources/Domain.ts","../src/api/resources/Email.ts","../src/api/resources/IdentificationLink.ts","../src/api/resources/Verification.ts","../src/api/resources/EmailAddress.ts","../src/api/resources/ExternalAccount.ts","../src/api/resources/IdPOAuthAccessToken.ts","../src/api/resources/Instance.ts","../src/api/resources/InstanceRestrictions.ts","../src/api/resources/InstanceSettings.ts","../src/api/resources/Invitation.ts","../src/api/resources/JSON.ts","../src/api/resources/Machine.ts","../src/api/resources/MachineScope.ts","../src/api/resources/MachineSecretKey.ts","../src/api/resources/M2MToken.ts","../src/api/resources/JwtTemplate.ts","../src/api/resources/OauthAccessToken.ts","../src/api/resources/OAuthApplication.ts","../src/api/resources/Organization.ts","../src/api/resources/OrganizationInvitation.ts","../src/api/resources/OrganizationMembership.ts","../src/api/resources/OrganizationSettings.ts","../src/api/resources/PhoneNumber.ts","../src/api/resources/ProxyCheck.ts","../src/api/resources/RedirectUrl.ts","../src/api/resources/SamlConnection.ts","../src/api/resources/SamlAccount.ts","../src/api/resources/SignInTokens.ts","../src/api/resources/SignUpAttempt.ts","../src/api/resources/SMSMessage.ts","../src/api/resources/Token.ts","../src/api/resources/Web3Wallet.ts","../src/api/resources/User.ts","../src/api/resources/WaitlistEntry.ts","../src/api/resources/Feature.ts","../src/api/resources/CommercePlan.ts","../src/api/resources/CommerceSubscriptionItem.ts","../src/api/resources/CommerceSubscription.ts","../src/api/resources/Deserializer.ts","../src/api/factory.ts","../src/tokens/machine.ts","../src/tokens/authStatus.ts","../src/tokens/clerkRequest.ts","../src/tokens/clerkUrl.ts","../src/tokens/cookie.ts","../src/tokens/keys.ts","../src/tokens/verify.ts","../src/tokens/handshake.ts","../src/tokens/organizationMatcher.ts","../src/tokens/request.ts","../src/tokens/factory.ts","../src/util/decorateObjectWithResources.ts","../src/internal.ts"],"sourcesContent":["/**\n * RegExp to match cookie-name in RFC 6265 sec 4.1.1\n * This refers out to the obsoleted definition of token in RFC 2616 sec 2.2\n * which has been replaced by the token definition in RFC 7230 appendix B.\n *\n * cookie-name = token\n * token = 1*tchar\n * tchar = \"!\" / \"#\" / \"$\" / \"%\" / \"&\" / \"'\" /\n * \"*\" / \"+\" / \"-\" / \".\" / \"^\" / \"_\" /\n * \"`\" / \"|\" / \"~\" / DIGIT / ALPHA\n *\n * Note: Allowing more characters - https://github.com/jshttp/cookie/issues/191\n * Allow same range as cookie value, except `=`, which delimits end of name.\n */\nconst cookieNameRegExp = /^[\\u0021-\\u003A\\u003C\\u003E-\\u007E]+$/;\n\n/**\n * RegExp to match cookie-value in RFC 6265 sec 4.1.1\n *\n * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )\n * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E\n * ; US-ASCII characters excluding CTLs,\n * ; whitespace DQUOTE, comma, semicolon,\n * ; and backslash\n *\n * Allowing more characters: https://github.com/jshttp/cookie/issues/191\n * Comma, backslash, and DQUOTE are not part of the parsing algorithm.\n */\nconst cookieValueRegExp = /^[\\u0021-\\u003A\\u003C-\\u007E]*$/;\n\n/**\n * RegExp to match domain-value in RFC 6265 sec 4.1.1\n *\n * domain-value = <subdomain>\n * ; defined in [RFC1034], Section 3.5, as\n * ; enhanced by [RFC1123], Section 2.1\n * <subdomain> = <label> | <subdomain> \".\" <label>\n * <label> = <let-dig> [ [ <ldh-str> ] <let-dig> ]\n * Labels must be 63 characters or less.\n * 'let-dig' not 'letter' in the first char, per RFC1123\n * <ldh-str> = <let-dig-hyp> | <let-dig-hyp> <ldh-str>\n * <let-dig-hyp> = <let-dig> | \"-\"\n * <let-dig> = <letter> | <digit>\n * <letter> = any one of the 52 alphabetic characters A through Z in\n * upper case and a through z in lower case\n * <digit> = any one of the ten digits 0 through 9\n *\n * Keep support for leading dot: https://github.com/jshttp/cookie/issues/173\n *\n * > (Note that a leading %x2E (\".\"), if present, is ignored even though that\n * character is not permitted, but a trailing %x2E (\".\"), if present, will\n * cause the user agent to ignore the attribute.)\n */\nconst domainValueRegExp =\n /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;\n\n/**\n * RegExp to match path-value in RFC 6265 sec 4.1.1\n *\n * path-value = <any CHAR except CTLs or \";\">\n * CHAR = %x01-7F\n * ; defined in RFC 5234 appendix B.1\n */\nconst pathValueRegExp = /^[\\u0020-\\u003A\\u003D-\\u007E]*$/;\n\nconst __toString = Object.prototype.toString;\n\nconst NullObject = /* @__PURE__ */ (() => {\n const C = function () {};\n C.prototype = Object.create(null);\n return C;\n})() as unknown as { new (): any };\n\n/**\n * Parse options.\n */\nexport interface ParseOptions {\n /**\n * Specifies a function that will be used to decode a [cookie-value](https://datatracker.ietf.org/doc/html/rfc6265#section-4.1.1).\n * Since the value of a cookie has a limited character set (and must be a simple string), this function can be used to decode\n * a previously-encoded cookie value into a JavaScript string.\n *\n * The default function is the global `decodeURIComponent`, wrapped in a `try..catch`. If an error\n * is thrown it will return the cookie's original value. If you provide your own encode/decode\n * scheme you must ensure errors are appropriately handled.\n *\n * @default decode\n */\n decode?: (str: string) => string | undefined;\n}\n\n/**\n * Parse a cookie header.\n *\n * Parse the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n */\nexport function parse(\n str: string,\n options?: ParseOptions,\n): Record<string, string | undefined> {\n const obj: Record<string, string | undefined> = new NullObject();\n const len = str.length;\n // RFC 6265 sec 4.1.1, RFC 2616 2.2 defines a cookie name consists of one char minimum, plus '='.\n if (len < 2) return obj;\n\n const dec = options?.decode || decode;\n let index = 0;\n\n do {\n const eqIdx = str.indexOf(\"=\", index);\n if (eqIdx === -1) break; // No more cookie pairs.\n\n const colonIdx = str.indexOf(\";\", index);\n const endIdx = colonIdx === -1 ? len : colonIdx;\n\n if (eqIdx > endIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n continue;\n }\n\n const keyStartIdx = startIndex(str, index, eqIdx);\n const keyEndIdx = endIndex(str, eqIdx, keyStartIdx);\n const key = str.slice(keyStartIdx, keyEndIdx);\n\n // only assign once\n if (obj[key] === undefined) {\n let valStartIdx = startIndex(str, eqIdx + 1, endIdx);\n let valEndIdx = endIndex(str, endIdx, valStartIdx);\n\n const value = dec(str.slice(valStartIdx, valEndIdx));\n obj[key] = value;\n }\n\n index = endIdx + 1;\n } while (index < len);\n\n return obj;\n}\n\nfunction startIndex(str: string, index: number, max: number) {\n do {\n const code = str.charCodeAt(index);\n if (code !== 0x20 /* */ && code !== 0x09 /* \\t */) return index;\n } while (++index < max);\n return max;\n}\n\nfunction endIndex(str: string, index: number, min: number) {\n while (index > min) {\n const code = str.charCodeAt(--index);\n if (code !== 0x20 /* */ && code !== 0x09 /* \\t */) return index + 1;\n }\n return min;\n}\n\n/**\n * Serialize options.\n */\nexport interface SerializeOptions {\n /**\n * Specifies a function that will be used to encode a [cookie-value](https://datatracker.ietf.org/doc/html/rfc6265#section-4.1.1).\n * Since value of a cookie has a limited character set (and must be a simple string), this function can be used to encode\n * a value into a string suited for a cookie's value, and should mirror `decode` when parsing.\n *\n * @default encodeURIComponent\n */\n encode?: (str: string) => string;\n /**\n * Specifies the `number` (in seconds) to be the value for the [`Max-Age` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.2).\n *\n * The [cookie storage model specification](https://tools.ietf.org/html/rfc6265#section-5.3) states that if both `expires` and\n * `maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this,\n * so if both are set, they should point to the same date and time.\n */\n maxAge?: number;\n /**\n * Specifies the `Date` object to be the value for the [`Expires` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.1).\n * When no expiration is set clients consider this a \"non-persistent cookie\" and delete it the current session is over.\n *\n * The [cookie storage model specification](https://tools.ietf.org/html/rfc6265#section-5.3) states that if both `expires` and\n * `maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this,\n * so if both are set, they should point to the same date and time.\n */\n expires?: Date;\n /**\n * Specifies the value for the [`Domain` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.3).\n * When no domain is set clients consider the cookie to apply to the current domain only.\n */\n domain?: string;\n /**\n * Specifies the value for the [`Path` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.4).\n * When no path is set, the path is considered the [\"default path\"](https://tools.ietf.org/html/rfc6265#section-5.1.4).\n */\n path?: string;\n /**\n * Enables the [`HttpOnly` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.6).\n * When enabled, clients will not allow client-side JavaScript to see the cookie in `document.cookie`.\n */\n httpOnly?: boolean;\n /**\n * Enables the [`Secure` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.5).\n * When enabled, clients will only send the cookie back if the browser has a HTTPS connection.\n */\n secure?: boolean;\n /**\n * Enables the [`Partitioned` `Set-Cookie` attribute](https://tools.ietf.org/html/draft-cutler-httpbis-partitioned-cookies/).\n * When enabled, clients will only send the cookie back when the current domain _and_ top-level domain matches.\n *\n * This is an attribute that has not yet been fully standardized, and may change in the future.\n * This also means clients may ignore this attribute until they understand it. More information\n * about can be found in [the proposal](https://github.com/privacycg/CHIPS).\n */\n partitioned?: boolean;\n /**\n * Specifies the value for the [`Priority` `Set-Cookie` attribute](https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1).\n *\n * - `'low'` will set the `Priority` attribute to `Low`.\n * - `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set.\n * - `'high'` will set the `Priority` attribute to `High`.\n *\n * More information about priority levels can be found in [the specification](https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1).\n */\n priority?: \"low\" | \"medium\" | \"high\";\n /**\n * Specifies the value for the [`SameSite` `Set-Cookie` attribute](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7).\n *\n * - `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement.\n * - `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement.\n * - `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie.\n * - `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement.\n *\n * More information about enforcement levels can be found in [the specification](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7).\n */\n sameSite?: boolean | \"lax\" | \"strict\" | \"none\";\n}\n\n/**\n * Serialize data into a cookie header.\n *\n * Serialize a name value pair into a cookie string suitable for\n * http headers. An optional options object specifies cookie parameters.\n *\n * serialize('foo', 'bar', { httpOnly: true })\n * => \"foo=bar; httpOnly\"\n */\nexport function serialize(\n name: string,\n val: string,\n options?: SerializeOptions,\n): string {\n const enc = options?.encode || encodeURIComponent;\n\n if (!cookieNameRegExp.test(name)) {\n throw new TypeError(`argument name is invalid: ${name}`);\n }\n\n const value = enc(val);\n\n if (!cookieValueRegExp.test(value)) {\n throw new TypeError(`argument val is invalid: ${val}`);\n }\n\n let str = name + \"=\" + value;\n if (!options) return str;\n\n if (options.maxAge !== undefined) {\n if (!Number.isInteger(options.maxAge)) {\n throw new TypeError(`option maxAge is invalid: ${options.maxAge}`);\n }\n\n str += \"; Max-Age=\" + options.maxAge;\n }\n\n if (options.domain) {\n if (!domainValueRegExp.test(options.domain)) {\n throw new TypeError(`option domain is invalid: ${options.domain}`);\n }\n\n str += \"; Domain=\" + options.domain;\n }\n\n if (options.path) {\n if (!pathValueRegExp.test(options.path)) {\n throw new TypeError(`option path is invalid: ${options.path}`);\n }\n\n str += \"; Path=\" + options.path;\n }\n\n if (options.expires) {\n if (\n !isDate(options.expires) ||\n !Number.isFinite(options.expires.valueOf())\n ) {\n throw new TypeError(`option expires is invalid: ${options.expires}`);\n }\n\n str += \"; Expires=\" + options.expires.toUTCString();\n }\n\n if (options.httpOnly) {\n str += \"; HttpOnly\";\n }\n\n if (options.secure) {\n str += \"; Secure\";\n }\n\n if (options.partitioned) {\n str += \"; Partitioned\";\n }\n\n if (options.priority) {\n const priority =\n typeof options.priority === \"string\"\n ? options.priority.toLowerCase()\n : undefined;\n switch (priority) {\n case \"low\":\n str += \"; Priority=Low\";\n break;\n case \"medium\":\n str += \"; Priority=Medium\";\n break;\n case \"high\":\n str += \"; Priority=High\";\n break;\n default:\n throw new TypeError(`option priority is invalid: ${options.priority}`);\n }\n }\n\n if (options.sameSite) {\n const sameSite =\n typeof options.sameSite === \"string\"\n ? options.sameSite.toLowerCase()\n : options.sameSite;\n switch (sameSite) {\n case true:\n case \"strict\":\n str += \"; SameSite=Strict\";\n break;\n case \"lax\":\n str += \"; SameSite=Lax\";\n break;\n case \"none\":\n str += \"; SameSite=None\";\n break;\n default:\n throw new TypeError(`option sameSite is invalid: ${options.sameSite}`);\n }\n }\n\n return str;\n}\n\n/**\n * URL-decode string value. Optimized to skip native call when no %.\n */\nfunction decode(str: string): string {\n if (str.indexOf(\"%\") === -1) return str;\n\n try {\n return decodeURIComponent(str);\n } catch (e) {\n return str;\n }\n}\n\n/**\n * Determine if value is a Date.\n */\nfunction isDate(val: any): val is Date {\n return __toString.call(val) === \"[object Date]\";\n}\n","export const API_URL = 'https://api.clerk.com';\nexport const API_VERSION = 'v1';\n\nexport const USER_AGENT = `${PACKAGE_NAME}@${PACKAGE_VERSION}`;\nexport const MAX_CACHE_LAST_UPDATED_AT_SECONDS = 5 * 60;\nexport const SUPPORTED_BAPI_VERSION = '2025-11-10';\n\nconst Attributes = {\n AuthToken: '__clerkAuthToken',\n AuthSignature: '__clerkAuthSignature',\n AuthStatus: '__clerkAuthStatus',\n AuthReason: '__clerkAuthReason',\n AuthMessage: '__clerkAuthMessage',\n ClerkUrl: '__clerkUrl',\n} as const;\n\nconst Cookies = {\n Session: '__session',\n Refresh: '__refresh',\n ClientUat: '__client_uat',\n Handshake: '__clerk_handshake',\n DevBrowser: '__clerk_db_jwt',\n RedirectCount: '__clerk_redirect_count',\n HandshakeNonce: '__clerk_handshake_nonce',\n} as const;\n\nconst QueryParameters = {\n ClerkSynced: '__clerk_synced',\n SuffixedCookies: 'suffixed_cookies',\n ClerkRedirectUrl: '__clerk_redirect_url',\n // use the reference to Cookies to indicate that it's the same value\n DevBrowser: Cookies.DevBrowser,\n Handshake: Cookies.Handshake,\n HandshakeHelp: '__clerk_help',\n LegacyDevBrowser: '__dev_session',\n HandshakeReason: '__clerk_hs_reason',\n HandshakeNonce: Cookies.HandshakeNonce,\n HandshakeFormat: 'format',\n Session: '__session',\n} as const;\n\nconst Headers = {\n Accept: 'accept',\n AuthMessage: 'x-clerk-auth-message',\n Authorization: 'authorization',\n AuthReason: 'x-clerk-auth-reason',\n AuthSignature: 'x-clerk-auth-signature',\n AuthStatus: 'x-clerk-auth-status',\n AuthToken: 'x-clerk-auth-token',\n CacheControl: 'cache-control',\n ClerkRedirectTo: 'x-clerk-redirect-to',\n ClerkRequestData: 'x-clerk-request-data',\n ClerkUrl: 'x-clerk-clerk-url',\n CloudFrontForwardedProto: 'cloudfront-forwarded-proto',\n ContentType: 'content-type',\n ContentSecurityPolicy: 'content-security-policy',\n ContentSecurityPolicyReportOnly: 'content-security-policy-report-only',\n EnableDebug: 'x-clerk-debug',\n ForwardedHost: 'x-forwarded-host',\n ForwardedPort: 'x-forwarded-port',\n ForwardedProto: 'x-forwarded-proto',\n Host: 'host',\n Location: 'location',\n Nonce: 'x-nonce',\n Origin: 'origin',\n Referrer: 'referer',\n SecFetchDest: 'sec-fetch-dest',\n SecFetchSite: 'sec-fetch-site',\n UserAgent: 'user-agent',\n ReportingEndpoints: 'reporting-endpoints',\n} as const;\n\nconst ContentTypes = {\n Json: 'application/json',\n} as const;\n\n/**\n * @internal\n */\nexport const constants = {\n Attributes,\n Cookies,\n Headers,\n ContentTypes,\n QueryParameters,\n} as const;\n\nexport type Constants = typeof constants;\n","import { buildAccountsBaseUrl } from '@clerk/shared/buildAccountsBaseUrl';\nimport type { SessionStatusClaim } from '@clerk/types';\n\nimport { constants } from './constants';\nimport { errorThrower, parsePublishableKey } from './util/shared';\n\nconst buildUrl = (\n _baseUrl: string | URL,\n _targetUrl: string | URL,\n _returnBackUrl?: string | URL | null,\n _devBrowserToken?: string | null,\n) => {\n if (_baseUrl === '') {\n return legacyBuildUrl(_targetUrl.toString(), _returnBackUrl?.toString());\n }\n\n const baseUrl = new URL(_baseUrl);\n const returnBackUrl = _returnBackUrl ? new URL(_returnBackUrl, baseUrl) : undefined;\n const res = new URL(_targetUrl, baseUrl);\n const isCrossOriginRedirect = `${baseUrl.hostname}:${baseUrl.port}` !== `${res.hostname}:${res.port}`;\n\n if (returnBackUrl) {\n if (isCrossOriginRedirect) {\n returnBackUrl.searchParams.delete(constants.QueryParameters.ClerkSynced);\n }\n\n res.searchParams.set('redirect_url', returnBackUrl.toString());\n }\n // For cross-origin redirects, we need to pass the dev browser token for URL session syncing\n if (isCrossOriginRedirect && _devBrowserToken) {\n res.searchParams.set(constants.QueryParameters.DevBrowser, _devBrowserToken);\n }\n return res.toString();\n};\n\n/**\n * In v5, we deprecated the top-level redirectToSignIn and redirectToSignUp functions\n * in favor of the new auth().redirectToSignIn helpers\n * In order to allow for a smooth transition, we need to support the legacy redirectToSignIn for now\n * as we will remove it in v6.\n * In order to make sure that the legacy function works as expected, we will use legacyBuildUrl\n * to build the url if baseUrl is not provided (which is the case for legacy redirectToSignIn)\n * This function can be safely removed when we remove the legacy redirectToSignIn function\n */\nconst legacyBuildUrl = (targetUrl: string, redirectUrl?: string) => {\n let url;\n if (!targetUrl.startsWith('http')) {\n if (!redirectUrl || !redirectUrl.startsWith('http')) {\n throw new Error('destination url or return back url should be an absolute path url!');\n }\n\n const baseURL = new URL(redirectUrl);\n url = new URL(targetUrl, baseURL.origin);\n } else {\n url = new URL(targetUrl);\n }\n\n if (redirectUrl) {\n url.searchParams.set('redirect_url', redirectUrl);\n }\n\n return url.toString();\n};\n\ntype RedirectAdapter<RedirectReturn> = (url: string) => RedirectReturn;\ntype RedirectToParams = { returnBackUrl?: string | URL | null };\nexport type RedirectFun<ReturnType> = (params?: RedirectToParams) => ReturnType;\n\n/**\n * @internal\n */\ntype CreateRedirect = <ReturnType>(params: {\n publishableKey: string;\n devBrowserToken?: string;\n redirectAdapter: RedirectAdapter<ReturnType>;\n baseUrl: URL | string;\n signInUrl?: URL | string;\n signUpUrl?: URL | string;\n sessionStatus?: SessionStatusClaim | null;\n}) => {\n redirectToSignIn: RedirectFun<ReturnType>;\n redirectToSignUp: RedirectFun<ReturnType>;\n};\n\nexport const createRedirect: CreateRedirect = params => {\n const { publishableKey, redirectAdapter, signInUrl, signUpUrl, baseUrl, sessionStatus } = params;\n const parsedPublishableKey = parsePublishableKey(publishableKey);\n const frontendApi = parsedPublishableKey?.frontendApi;\n const isDevelopment = parsedPublishableKey?.instanceType === 'development';\n const accountsBaseUrl = buildAccountsBaseUrl(frontendApi);\n const hasPendingStatus = sessionStatus === 'pending';\n\n const redirectToTasks = (url: string | URL, { returnBackUrl }: RedirectToParams) => {\n return redirectAdapter(\n buildUrl(baseUrl, `${url}/tasks`, returnBackUrl, isDevelopment ? params.devBrowserToken : null),\n );\n };\n\n const redirectToSignUp = ({ returnBackUrl }: RedirectToParams = {}) => {\n if (!signUpUrl && !accountsBaseUrl) {\n errorThrower.throwMissingPublishableKeyError();\n }\n\n const accountsSignUpUrl = `${accountsBaseUrl}/sign-up`;\n\n // Allows redirection to SignInOrUp path\n function buildSignUpUrl(signIn: string | URL | undefined) {\n if (!signIn) {\n return;\n }\n const url = new URL(signIn, baseUrl);\n url.pathname = `${url.pathname}/create`;\n return url.toString();\n }\n\n const targetUrl = signUpUrl || buildSignUpUrl(signInUrl) || accountsSignUpUrl;\n\n if (hasPendingStatus) {\n return redirectToTasks(targetUrl, { returnBackUrl });\n }\n\n return redirectAdapter(buildUrl(baseUrl, targetUrl, returnBackUrl, isDevelopment ? params.devBrowserToken : null));\n };\n\n const redirectToSignIn = ({ returnBackUrl }: RedirectToParams = {}) => {\n if (!signInUrl && !accountsBaseUrl) {\n errorThrower.throwMissingPublishableKeyError();\n }\n\n const accountsSignInUrl = `${accountsBaseUrl}/sign-in`;\n const targetUrl = signInUrl || accountsSignInUrl;\n\n if (hasPendingStatus) {\n return redirectToTasks(targetUrl, { returnBackUrl });\n }\n\n return redirectAdapter(buildUrl(baseUrl, targetUrl, returnBackUrl, isDevelopment ? params.devBrowserToken : null));\n };\n\n return { redirectToSignUp, redirectToSignIn };\n};\n","export function mergePreDefinedOptions<T extends Record<string, any>>(preDefinedOptions: T, options: Partial<T>): T {\n return Object.keys(preDefinedOptions).reduce(\n (obj: T, key: string) => {\n return { ...obj, [key]: options[key] || obj[key] };\n },\n { ...preDefinedOptions },\n );\n}\n","import { parsePublishableKey } from './shared';\n\nexport function assertValidSecretKey(val: unknown): asserts val is string {\n if (!val || typeof val !== 'string') {\n throw Error('Missing Clerk Secret Key. Go to https://dashboard.clerk.com and get your key for your instance.');\n }\n\n //TODO: Check if the key is invalid and throw error\n}\n\nexport function assertValidPublishableKey(val: unknown): asserts val is string {\n parsePublishableKey(val as string | undefined, { fatal: true });\n}\n","import { buildAccountsBaseUrl } from '@clerk/shared/buildAccountsBaseUrl';\nimport { isCurrentDevAccountPortalOrigin, isLegacyDevAccountPortalOrigin } from '@clerk/shared/url';\nimport type { Jwt } from '@clerk/types';\n\nimport { constants } from '../constants';\nimport { decodeJwt } from '../jwt/verifyJwt';\nimport { runtime } from '../runtime';\nimport { assertValidPublishableKey } from '../util/optionsAssertions';\nimport { getCookieSuffix, getSuffixedCookieName, parsePublishableKey } from '../util/shared';\nimport type { ClerkRequest } from './clerkRequest';\nimport { TokenType } from './tokenTypes';\nimport type { AuthenticateRequestOptions } from './types';\n\ninterface AuthenticateContext extends AuthenticateRequestOptions {\n // header-based values\n accept: string | undefined;\n forwardedHost: string | undefined;\n forwardedProto: string | undefined;\n host: string | undefined;\n origin: string | undefined;\n referrer: string | undefined;\n secFetchDest: string | undefined;\n tokenInHeader: string | undefined;\n userAgent: string | undefined;\n\n // cookie-based values\n clientUat: number;\n refreshTokenInCookie: string | undefined;\n sessionTokenInCookie: string | undefined;\n\n // handshake-related values\n devBrowserToken: string | undefined;\n handshakeNonce: string | undefined;\n handshakeRedirectLoopCounter: number;\n handshakeToken: string | undefined;\n\n // url derived from headers\n clerkUrl: URL;\n // enforce existence of the following props\n frontendApi: string;\n instanceType: string;\n publishableKey: string;\n}\n\n/**\n * All data required to authenticate a request.\n * This is the data we use to decide whether a request\n * is in a signed in or signed out state or if we need\n * to perform a handshake.\n */\nclass AuthenticateContext implements AuthenticateContext {\n /**\n * The original Clerk frontend API URL, extracted from publishable key before proxy URL override.\n * Used for backend operations like token validation and issuer checking.\n */\n private originalFrontendApi: string = '';\n\n /**\n * Retrieves the session token from either the cookie or the header.\n *\n * @returns {string | undefined} The session token if available, otherwise undefined.\n */\n public get sessionToken(): string | undefined {\n return this.sessionTokenInCookie || this.tokenInHeader;\n }\n\n public constructor(\n private cookieSuffix: string,\n private clerkRequest: ClerkRequest,\n options: AuthenticateRequestOptions,\n ) {\n if (options.acceptsToken === TokenType.M2MToken || options.acceptsToken === TokenType.ApiKey) {\n // For non-session tokens, we only want to set the header values.\n this.initHeaderValues();\n } else {\n // Even though the options are assigned to this later in this function\n // we set the publishableKey here because it is being used in cookies/headers/handshake-values\n // as part of getMultipleAppsCookie.\n this.initPublishableKeyValues(options);\n this.initHeaderValues();\n // initCookieValues should be used before initHandshakeValues because it depends on suffixedCookies\n this.initCookieValues();\n this.initHandshakeValues();\n }\n\n Object.assign(this, options);\n this.clerkUrl = this.clerkRequest.clerkUrl;\n }\n\n public usesSuffixedCookies(): boolean {\n const suffixedClientUat = this.getSuffixedCookie(constants.Cookies.ClientUat);\n const clientUat = this.getCookie(constants.Cookies.ClientUat);\n const suffixedSession = this.getSuffixedCookie(constants.Cookies.Session) || '';\n const session = this.getCookie(constants.Cookies.Session) || '';\n\n // In the case of malformed session cookies (eg missing the iss claim), we should\n // use the un-suffixed cookies to return signed-out state instead of triggering\n // handshake\n if (session && !this.tokenHasIssuer(session)) {\n return false;\n }\n\n // If there's a token in un-suffixed, and it doesn't belong to this\n // instance, then we must trust suffixed\n if (session && !this.tokenBelongsToInstance(session)) {\n return true;\n }\n\n // If there are no suffixed cookies use un-suffixed\n if (!suffixedClientUat && !suffixedSession) {\n return false;\n }\n\n const { data: sessionData } = decodeJwt(session);\n const sessionIat = sessionData?.payload.iat || 0;\n const { data: suffixedSessionData } = decodeJwt(suffixedSession);\n const suffixedSessionIat = suffixedSessionData?.payload.iat || 0;\n\n // Both indicate signed in, but un-suffixed is newer\n // Trust un-suffixed because it's newer\n if (suffixedClientUat !== '0' && clientUat !== '0' && sessionIat > suffixedSessionIat) {\n return false;\n }\n\n // Suffixed indicates signed out, but un-suffixed indicates signed in\n // Trust un-suffixed because it gets set with both new and old clerk.js,\n // so we can assume it's newer\n if (suffixedClientUat === '0' && clientUat !== '0') {\n return false;\n }\n\n // Suffixed indicates signed in, un-suffixed indicates signed out\n // This is the tricky one\n\n // In production, suffixed_uat should be set reliably, since it's\n // set by FAPI and not clerk.js. So in the scenario where a developer\n // downgrades, the state will look like this:\n // - un-suffixed session cookie: empty\n // - un-suffixed uat: 0\n // - suffixed session cookie: (possibly filled, possibly empty)\n // - suffixed uat: 0\n\n // Our SDK honors client_uat over the session cookie, so we don't\n // need a special case for production. We can rely on suffixed,\n // and the fact that the suffixed uat is set properly means and\n // suffixed session cookie will be ignored.\n\n // The important thing to make sure we have a test that confirms\n // the user ends up as signed out in this scenario, and the suffixed\n // session cookie is ignored\n\n // In development, suffixed_uat is not set reliably, since it's done\n // by clerk.js. If the developer downgrades to a pinned version of\n // clerk.js, the suffixed uat will no longer be updated\n\n // The best we can do is look to see if the suffixed token is expired.\n // This means that, if a developer downgrades, and then immediately\n // signs out, all in the span of 1 minute, then they will inadvertently\n // remain signed in for the rest of that minute. This is a known\n // limitation of the strategy but seems highly unlikely.\n if (this.instanceType !== 'production') {\n const isSuffixedSessionExpired = this.sessionExpired(suffixedSessionData);\n if (suffixedClientUat !== '0' && clientUat === '0' && isSuffixedSessionExpired) {\n return false;\n }\n }\n\n // If a suffixed session cookie exists but the corresponding client_uat cookie is missing, fallback to using\n // unsuffixed cookies.\n // This handles the scenario where an app has been deployed using an SDK version that supports suffixed\n // cookies, but FAPI for its Clerk instance has the feature disabled (eg: if we need to temporarily disable the feature).\n if (!suffixedClientUat && suffixedSession) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Determines if the request came from a different origin based on the referrer header.\n * Used for cross-origin detection in multi-domain authentication flows.\n *\n * @returns {boolean} True if referrer exists and is from a different origin, false otherwise.\n */\n public isCrossOriginReferrer(): boolean {\n if (!this.referrer || !this.clerkUrl.origin) {\n return false;\n }\n\n try {\n const referrerOrigin = new URL(this.referrer).origin;\n return referrerOrigin !== this.clerkUrl.origin;\n } catch {\n // Invalid referrer URL format\n return false;\n }\n }\n\n /**\n * Determines if the referrer URL is from a Clerk domain (accounts portal or FAPI).\n * This includes both development and production account portal domains, as well as FAPI domains\n * used for redirect-based authentication flows.\n *\n * @returns {boolean} True if the referrer is from a Clerk accounts portal or FAPI domain, false otherwise\n */\n public isKnownClerkReferrer(): boolean {\n if (!this.referrer) {\n return false;\n }\n\n try {\n const referrerOrigin = new URL(this.referrer);\n const referrerHost = referrerOrigin.hostname;\n\n // Check if referrer is the FAPI domain itself (redirect-based auth flows)\n if (this.frontendApi) {\n const fapiHost = this.frontendApi.startsWith('http') ? new URL(this.frontendApi).hostname : this.frontendApi;\n if (referrerHost === fapiHost) {\n return true;\n }\n }\n\n // Check for development account portal patterns\n if (isLegacyDevAccountPortalOrigin(referrerHost) || isCurrentDevAccountPortalOrigin(referrerHost)) {\n return true;\n }\n\n // Check for production account portal by comparing with expected accounts URL\n const expectedAccountsUrl = buildAccountsBaseUrl(this.frontendApi);\n if (expectedAccountsUrl) {\n const expectedAccountsOrigin = new URL(expectedAccountsUrl).origin;\n if (referrerOrigin.origin === expectedAccountsOrigin) {\n return true;\n }\n }\n\n // Check for generic production accounts patterns (accounts.*)\n if (referrerHost.startsWith('accounts.')) {\n return true;\n }\n\n return false;\n } catch {\n // Invalid URL format\n return false;\n }\n }\n\n private initPublishableKeyValues(options: AuthenticateRequestOptions) {\n assertValidPublishableKey(options.publishableKey);\n this.publishableKey = options.publishableKey;\n\n const originalPk = parsePublishableKey(this.publishableKey, {\n fatal: true,\n domain: options.domain,\n isSatellite: options.isSatellite,\n });\n this.originalFrontendApi = originalPk.frontendApi;\n\n const pk = parsePublishableKey(this.publishableKey, {\n fatal: true,\n proxyUrl: options.proxyUrl,\n domain: options.domain,\n isSatellite: options.isSatellite,\n });\n this.instanceType = pk.instanceType;\n this.frontendApi = pk.frontendApi;\n }\n\n private initHeaderValues() {\n this.tokenInHeader = this.parseAuthorizationHeader(this.getHeader(constants.Headers.Authorization));\n this.origin = this.getHeader(constants.Headers.Origin);\n this.host = this.getHeader(constants.Headers.Host);\n this.forwardedHost = this.getHeader(constants.Headers.ForwardedHost);\n this.forwardedProto =\n this.getHeader(constants.Headers.CloudFrontForwardedProto) || this.getHeader(constants.Headers.ForwardedProto);\n this.referrer = this.getHeader(constants.Headers.Referrer);\n this.userAgent = this.getHeader(constants.Headers.UserAgent);\n this.secFetchDest = this.getHeader(constants.Headers.SecFetchDest);\n this.accept = this.getHeader(constants.Headers.Accept);\n }\n\n private initCookieValues() {\n // suffixedCookies needs to be set first because it's used in getMultipleAppsCookie\n this.sessionTokenInCookie = this.getSuffixedOrUnSuffixedCookie(constants.Cookies.Session);\n this.refreshTokenInCookie = this.getSuffixedCookie(constants.Cookies.Refresh);\n this.clientUat = Number.parseInt(this.getSuffixedOrUnSuffixedCookie(constants.Cookies.ClientUat) || '') || 0;\n }\n\n private initHandshakeValues() {\n this.devBrowserToken =\n this.getQueryParam(constants.QueryParameters.DevBrowser) ||\n this.getSuffixedOrUnSuffixedCookie(constants.Cookies.DevBrowser);\n // Using getCookie since we don't suffix the handshake token cookie\n this.handshakeToken =\n this.getQueryParam(constants.QueryParameters.Handshake) || this.getCookie(constants.Cookies.Handshake);\n this.handshakeRedirectLoopCounter = Number(this.getCookie(constants.Cookies.RedirectCount)) || 0;\n this.handshakeNonce =\n this.getQueryParam(constants.QueryParameters.HandshakeNonce) || this.getCookie(constants.Cookies.HandshakeNonce);\n }\n\n private getQueryParam(name: string) {\n return this.clerkRequest.clerkUrl.searchParams.get(name);\n }\n\n private getHeader(name: string) {\n return this.clerkRequest.headers.get(name) || undefined;\n }\n\n private getCookie(name: string) {\n return this.clerkRequest.cookies.get(name) || undefined;\n }\n\n private getSuffixedCookie(name: string) {\n return this.getCookie(getSuffixedCookieName(name, this.cookieSuffix)) || undefined;\n }\n\n private getSuffixedOrUnSuffixedCookie(cookieName: string) {\n if (this.usesSuffixedCookies()) {\n return this.getSuffixedCookie(cookieName);\n }\n return this.getCookie(cookieName);\n }\n\n private parseAuthorizationHeader(authorizationHeader: string | undefined | null): string | undefined {\n if (!authorizationHeader) {\n return undefined;\n }\n\n const [scheme, token] = authorizationHeader.split(' ', 2);\n\n if (!token) {\n // No scheme specified, treat the entire value as the token\n return scheme;\n }\n\n if (scheme === 'Bearer') {\n return token;\n }\n\n // Skip all other schemes\n return undefined;\n }\n\n private tokenHasIssuer(token: string): boolean {\n const { data, errors } = decodeJwt(token);\n if (errors) {\n return false;\n }\n return !!data.payload.iss;\n }\n\n private tokenBelongsToInstance(token: string): boolean {\n if (!token) {\n return false;\n }\n\n const { data, errors } = decodeJwt(token);\n if (errors) {\n return false;\n }\n const tokenIssuer = data.payload.iss.replace(/https?:\\/\\//gi, '');\n // Use original frontend API for token validation since tokens are issued by the actual Clerk API, not proxy\n return this.originalFrontendApi === tokenIssuer;\n }\n\n private sessionExpired(jwt: Jwt | undefined): boolean {\n return !!jwt && jwt?.payload.exp <= (Date.now() / 1000) >> 0;\n }\n}\n\nexport type { AuthenticateContext };\n\nexport const createAuthenticateContext = async (\n clerkRequest: ClerkRequest,\n options: AuthenticateRequestOptions,\n): Promise<AuthenticateContext> => {\n const cookieSuffix = options.publishableKey\n ? await getCookieSuffix(options.publishableKey, runtime.crypto.subtle)\n : '';\n return new AuthenticateContext(cookieSuffix, clerkRequest, options);\n};\n","export const TokenType = {\n SessionToken: 'session_token',\n ApiKey: 'api_key',\n M2MToken: 'm2m_token',\n OAuthToken: 'oauth_token',\n} as const;\n\n/**\n * @inline\n */\nexport type TokenType = (typeof TokenType)[keyof typeof TokenType];\n\n/**\n * @inline\n */\nexport type SessionTokenType = typeof TokenType.SessionToken;\n/**\n * @inline\n */\nexport type MachineTokenType = Exclude<TokenType, SessionTokenType>;\n","import { createCheckAuthorization } from '@clerk/shared/authorization';\nimport { __experimental_JWTPayloadToAuthObjectProperties } from '@clerk/shared/jwtPayloadParser';\nimport type {\n CheckAuthorizationFromSessionClaims,\n Jwt,\n JwtPayload,\n PendingSessionOptions,\n ServerGetToken,\n ServerGetTokenOptions,\n SessionStatusClaim,\n SharedSignedInAuthObjectProperties,\n} from '@clerk/types';\n\nimport type { APIKey, CreateBackendApiOptions, IdPOAuthAccessToken, M2MToken } from '../api';\nimport { createBackendApiClient } from '../api';\nimport { isTokenTypeAccepted } from '../internal';\nimport type { AuthenticateContext } from './authenticateContext';\nimport { isMachineTokenType } from './machine';\nimport type { MachineTokenType, SessionTokenType } from './tokenTypes';\nimport { TokenType } from './tokenTypes';\nimport type { AuthenticateRequestOptions, MachineAuthType } from './types';\n\n/**\n * @inline\n */\ntype AuthObjectDebugData = Record<string, any>;\n/**\n * @inline\n */\ntype AuthObjectDebug = () => AuthObjectDebugData;\n\ntype Claims = Record<string, any>;\n\n/**\n * @internal\n */\nexport type SignedInAuthObjectOptions = CreateBackendApiOptions & {\n token: string;\n};\n\n/**\n * @internal\n */\nexport type SignedInAuthObject = SharedSignedInAuthObjectProperties & {\n /**\n * The allowed token type.\n */\n tokenType: SessionTokenType;\n /**\n * A function that gets the current user's [session token](https://clerk.com/docs/guides/sessions/session-tokens) or a [custom JWT template](https://clerk.com/docs/guides/sessions/jwt-templates).\n */\n getToken: ServerGetToken;\n /**\n * A function that checks if the user has an Organization Role or Custom Permission.\n */\n has: CheckAuthorizationFromSessionClaims;\n /**\n * Used to help debug issues when using Clerk in development.\n */\n debug: AuthObjectDebug;\n isAuthenticated: true;\n};\n\n/**\n * @internal\n */\nexport type SignedOutAuthObject = {\n sessionClaims: null;\n sessionId: null;\n sessionStatus: SessionStatusClaim | null;\n actor: null;\n tokenType: SessionTokenType;\n userId: null;\n orgId: null;\n orgRole: null;\n orgSlug: null;\n orgPermissions: null;\n factorVerificationAge: null;\n getToken: ServerGetToken;\n has: CheckAuthorizationFromSessionClaims;\n debug: AuthObjectDebug;\n isAuthenticated: false;\n};\n\n/**\n * Extended properties specific to each machine token type.\n * While all machine token types share common properties (id, name, subject, etc),\n * this type defines the additional properties that are unique to each token type.\n *\n * @template TAuthenticated - Whether the machine object is authenticated or not\n */\ntype MachineObjectExtendedProperties<TAuthenticated extends boolean> = {\n api_key: TAuthenticated extends true\n ?\n | { name: string; claims: Claims | null; userId: string; orgId: null }\n | { name: string; claims: Claims | null; userId: null; orgId: string }\n : { name: null; claims: null; userId: null; orgId: null };\n m2m_token: {\n claims: TAuthenticated extends true ? Claims | null : null;\n machineId: TAuthenticated extends true ? string : null;\n };\n oauth_token: {\n userId: TAuthenticated extends true ? string : null;\n clientId: TAuthenticated extends true ? string : null;\n };\n};\n\n/**\n * @internal\n *\n * Uses `T extends any` to create a distributive conditional type.\n * This ensures that union types like `'api_key' | 'oauth_token'` are processed\n * individually, creating proper discriminated unions where each token type\n * gets its own distinct properties (e.g., oauth_token won't have claims).\n */\nexport type AuthenticatedMachineObject<T extends MachineTokenType = MachineTokenType> = T extends any\n ? {\n id: string;\n subject: string;\n scopes: string[];\n getToken: () => Promise<string>;\n has: CheckAuthorizationFromSessionClaims;\n debug: AuthObjectDebug;\n tokenType: T;\n isAuthenticated: true;\n } & MachineObjectExtendedProperties<true>[T]\n : never;\n\n/**\n * @internal\n *\n * Uses `T extends any` to create a distributive conditional type.\n * This ensures that union types like `'api_key' | 'oauth_token'` are processed\n * individually, creating proper discriminated unions where each token type\n * gets its own distinct properties (e.g., oauth_token won't have claims).\n */\nexport type UnauthenticatedMachineObject<T extends MachineTokenType = MachineTokenType> = T extends any\n ? {\n id: null;\n subject: null;\n scopes: null;\n getToken: () => Promise<null>;\n has: CheckAuthorizationFromSessionClaims;\n debug: AuthObjectDebug;\n tokenType: T;\n isAuthenticated: false;\n } & MachineObjectExtendedProperties<false>[T]\n : never;\n\nexport type InvalidTokenAuthObject = {\n isAuthenticated: false;\n tokenType: null;\n getToken: () => Promise<null>;\n has: () => false;\n debug: AuthObjectDebug;\n};\n\n/**\n * @interface\n */\nexport type AuthObject =\n | SignedInAuthObject\n | SignedOutAuthObject\n | AuthenticatedMachineObject\n | UnauthenticatedMachineObject\n | InvalidTokenAuthObject;\n\nconst createDebug = (data: AuthObjectDebugData | undefined) => {\n return () => {\n const res = { ...data };\n res.secretKey = (res.secretKey || '').substring(0, 7);\n res.jwtKey = (res.jwtKey || '').substring(0, 7);\n return { ...res };\n };\n};\n\n/**\n * @internal\n */\nexport function signedInAuthObject(\n authenticateContext: Partial<AuthenticateContext>,\n sessionToken: string,\n sessionClaims: JwtPayload,\n): SignedInAuthObject {\n const { actor, sessionId, sessionStatus, userId, orgId, orgRole, orgSlug, orgPermissions, factorVerificationAge } =\n __experimental_JWTPayloadToAuthObjectProperties(sessionClaims);\n const apiClient = createBackendApiClient(authenticateContext);\n const getToken = createGetToken({\n sessionId,\n sessionToken,\n fetcher: async (sessionId, template, expiresInSeconds) =>\n (await apiClient.sessions.getToken(sessionId, template || '', expiresInSeconds)).jwt,\n });\n return {\n tokenType: TokenType.SessionToken,\n actor,\n sessionClaims,\n sessionId,\n sessionStatus,\n userId,\n orgId,\n orgRole,\n orgSlug,\n orgPermissions,\n factorVerificationAge,\n getToken,\n has: createCheckAuthorization({\n orgId,\n orgRole,\n orgPermissions,\n userId,\n factorVerificationAge,\n features: (sessionClaims.fea as string) || '',\n plans: (sessionClaims.pla as string) || '',\n }),\n debug: createDebug({ ...authenticateContext, sessionToken }),\n isAuthenticated: true,\n };\n}\n\n/**\n * @internal\n */\nexport function signedOutAuthObject(\n debugData?: AuthObjectDebugData,\n initialSessionStatus?: SessionStatusClaim,\n): SignedOutAuthObject {\n return {\n tokenType: TokenType.SessionToken,\n sessionClaims: null,\n sessionId: null,\n sessionStatus: initialSessionStatus ?? null,\n userId: null,\n actor: null,\n orgId: null,\n orgRole: null,\n orgSlug: null,\n orgPermissions: null,\n factorVerificationAge: null,\n getToken: () => Promise.resolve(null),\n has: () => false,\n debug: createDebug(debugData),\n isAuthenticated: false,\n };\n}\n\n/**\n * @internal\n */\nexport function authenticatedMachineObject<T extends MachineTokenType>(\n tokenType: T,\n token: string,\n verificationResult: MachineAuthType,\n debugData?: AuthObjectDebugData,\n): AuthenticatedMachineObject<T> {\n const baseObject = {\n id: verificationResult.id,\n subject: verificationResult.subject,\n getToken: () => Promise.resolve(token),\n has: () => false,\n debug: createDebug(debugData),\n isAuthenticated: true,\n };\n\n // Type assertions are safe here since we know the verification result type matches the tokenType.\n // We need these assertions because TS can't infer the specific type\n // just from the tokenType discriminator.\n\n switch (tokenType) {\n case TokenType.ApiKey: {\n const result = verificationResult as APIKey;\n return {\n ...baseObject,\n tokenType,\n name: result.name,\n claims: result.claims,\n scopes: result.scopes,\n userId: result.subject.startsWith('user_') ? result.subject : null,\n orgId: result.subject.startsWith('org_') ? result.subject : null,