UNPKG

@clerk/backend

Version:

Clerk Backend SDK - REST Client for Backend API & JWT verification utilities

1,492 lines (1,459 loc) • 210 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __typeError = (msg) => { throw TypeError(msg); }; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method); // ../../node_modules/.pnpm/cookie@1.0.2/node_modules/cookie/dist/index.js var require_dist = __commonJS({ "../../node_modules/.pnpm/cookie@1.0.2/node_modules/cookie/dist/index.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.parse = parse3; exports2.serialize = serialize; var cookieNameRegExp = /^[\u0021-\u003A\u003C\u003E-\u007E]+$/; var cookieValueRegExp = /^[\u0021-\u003A\u003C-\u007E]*$/; var domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i; var pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/; var __toString = Object.prototype.toString; var NullObject = /* @__PURE__ */ (() => { const C = function() { }; C.prototype = /* @__PURE__ */ Object.create(null); return C; })(); function parse3(str, options) { const obj = new NullObject(); const len = str.length; if (len < 2) return obj; const dec = options?.decode || decode; let index = 0; do { const eqIdx = str.indexOf("=", index); if (eqIdx === -1) break; const colonIdx = str.indexOf(";", index); const endIdx = colonIdx === -1 ? len : colonIdx; if (eqIdx > endIdx) { index = str.lastIndexOf(";", eqIdx - 1) + 1; continue; } const keyStartIdx = startIndex(str, index, eqIdx); const keyEndIdx = endIndex(str, eqIdx, keyStartIdx); const key = str.slice(keyStartIdx, keyEndIdx); if (obj[key] === void 0) { let valStartIdx = startIndex(str, eqIdx + 1, endIdx); let valEndIdx = endIndex(str, endIdx, valStartIdx); const value = dec(str.slice(valStartIdx, valEndIdx)); obj[key] = value; } index = endIdx + 1; } while (index < len); return obj; } function startIndex(str, index, max) { do { const code = str.charCodeAt(index); if (code !== 32 && code !== 9) return index; } while (++index < max); return max; } function endIndex(str, index, min) { while (index > min) { const code = str.charCodeAt(--index); if (code !== 32 && code !== 9) return index + 1; } return min; } function serialize(name, val, options) { const enc = options?.encode || encodeURIComponent; if (!cookieNameRegExp.test(name)) { throw new TypeError(`argument name is invalid: ${name}`); } const value = enc(val); if (!cookieValueRegExp.test(value)) { throw new TypeError(`argument val is invalid: ${val}`); } let str = name + "=" + value; if (!options) return str; if (options.maxAge !== void 0) { if (!Number.isInteger(options.maxAge)) { throw new TypeError(`option maxAge is invalid: ${options.maxAge}`); } str += "; Max-Age=" + options.maxAge; } if (options.domain) { if (!domainValueRegExp.test(options.domain)) { throw new TypeError(`option domain is invalid: ${options.domain}`); } str += "; Domain=" + options.domain; } if (options.path) { if (!pathValueRegExp.test(options.path)) { throw new TypeError(`option path is invalid: ${options.path}`); } str += "; Path=" + options.path; } if (options.expires) { if (!isDate(options.expires) || !Number.isFinite(options.expires.valueOf())) { throw new TypeError(`option expires is invalid: ${options.expires}`); } str += "; Expires=" + options.expires.toUTCString(); } if (options.httpOnly) { str += "; HttpOnly"; } if (options.secure) { str += "; Secure"; } if (options.partitioned) { str += "; Partitioned"; } if (options.priority) { const priority = typeof options.priority === "string" ? options.priority.toLowerCase() : void 0; switch (priority) { case "low": str += "; Priority=Low"; break; case "medium": str += "; Priority=Medium"; break; case "high": str += "; Priority=High"; break; default: throw new TypeError(`option priority is invalid: ${options.priority}`); } } if (options.sameSite) { const sameSite = typeof options.sameSite === "string" ? options.sameSite.toLowerCase() : options.sameSite; switch (sameSite) { case true: case "strict": str += "; SameSite=Strict"; break; case "lax": str += "; SameSite=Lax"; break; case "none": str += "; SameSite=None"; break; default: throw new TypeError(`option sameSite is invalid: ${options.sameSite}`); } } return str; } function decode(str) { if (str.indexOf("%") === -1) return str; try { return decodeURIComponent(str); } catch (e) { return str; } } function isDate(val) { return __toString.call(val) === "[object Date]"; } } }); // src/internal.ts var internal_exports = {}; __export(internal_exports, { AuthStatus: () => AuthStatus, TokenType: () => TokenType, authenticatedMachineObject: () => authenticatedMachineObject, constants: () => constants, createAuthenticateRequest: () => createAuthenticateRequest, createClerkRequest: () => createClerkRequest, createRedirect: () => createRedirect, debugRequestState: () => debugRequestState, decorateObjectWithResources: () => decorateObjectWithResources, getAuthObjectForAcceptedToken: () => getAuthObjectForAcceptedToken, getAuthObjectFromJwt: () => getAuthObjectFromJwt, getMachineTokenType: () => getMachineTokenType, invalidTokenAuthObject: () => invalidTokenAuthObject, isMachineTokenByPrefix: () => isMachineTokenByPrefix, isMachineTokenType: () => isMachineTokenType, isTokenTypeAccepted: () => isTokenTypeAccepted, makeAuthObjectSerializable: () => makeAuthObjectSerializable, reverificationError: () => import_authorization_errors.reverificationError, reverificationErrorResponse: () => import_authorization_errors.reverificationErrorResponse, signedInAuthObject: () => signedInAuthObject, signedOutAuthObject: () => signedOutAuthObject, stripPrivateDataFromObject: () => stripPrivateDataFromObject, unauthenticatedMachineObject: () => unauthenticatedMachineObject, verifyMachineAuthToken: () => verifyMachineAuthToken }); module.exports = __toCommonJS(internal_exports); // src/constants.ts var API_URL = "https://api.clerk.com"; var API_VERSION = "v1"; var USER_AGENT = `${"@clerk/backend"}@${"2.29.2"}`; var MAX_CACHE_LAST_UPDATED_AT_SECONDS = 5 * 60; var SUPPORTED_BAPI_VERSION = "2025-11-10"; var Attributes = { AuthToken: "__clerkAuthToken", AuthSignature: "__clerkAuthSignature", AuthStatus: "__clerkAuthStatus", AuthReason: "__clerkAuthReason", AuthMessage: "__clerkAuthMessage", ClerkUrl: "__clerkUrl" }; var Cookies = { Session: "__session", Refresh: "__refresh", ClientUat: "__client_uat", Handshake: "__clerk_handshake", DevBrowser: "__clerk_db_jwt", RedirectCount: "__clerk_redirect_count", HandshakeNonce: "__clerk_handshake_nonce" }; var QueryParameters = { ClerkSynced: "__clerk_synced", SuffixedCookies: "suffixed_cookies", ClerkRedirectUrl: "__clerk_redirect_url", // use the reference to Cookies to indicate that it's the same value DevBrowser: Cookies.DevBrowser, Handshake: Cookies.Handshake, HandshakeHelp: "__clerk_help", LegacyDevBrowser: "__dev_session", HandshakeReason: "__clerk_hs_reason", HandshakeNonce: Cookies.HandshakeNonce, HandshakeFormat: "format", Session: "__session" }; var Headers2 = { Accept: "accept", AuthMessage: "x-clerk-auth-message", Authorization: "authorization", AuthReason: "x-clerk-auth-reason", AuthSignature: "x-clerk-auth-signature", AuthStatus: "x-clerk-auth-status", AuthToken: "x-clerk-auth-token", CacheControl: "cache-control", ClerkRedirectTo: "x-clerk-redirect-to", ClerkRequestData: "x-clerk-request-data", ClerkUrl: "x-clerk-clerk-url", CloudFrontForwardedProto: "cloudfront-forwarded-proto", ContentType: "content-type", ContentSecurityPolicy: "content-security-policy", ContentSecurityPolicyReportOnly: "content-security-policy-report-only", EnableDebug: "x-clerk-debug", ForwardedHost: "x-forwarded-host", ForwardedPort: "x-forwarded-port", ForwardedProto: "x-forwarded-proto", Host: "host", Location: "location", Nonce: "x-nonce", Origin: "origin", Referrer: "referer", SecFetchDest: "sec-fetch-dest", SecFetchSite: "sec-fetch-site", UserAgent: "user-agent", ReportingEndpoints: "reporting-endpoints" }; var ContentTypes = { Json: "application/json" }; var constants = { Attributes, Cookies, Headers: Headers2, ContentTypes, QueryParameters }; // src/createRedirect.ts var import_buildAccountsBaseUrl = require("@clerk/shared/buildAccountsBaseUrl"); // src/util/shared.ts var import_deprecated = require("@clerk/shared/deprecated"); var import_keys = require("@clerk/shared/keys"); var import_retry = require("@clerk/shared/retry"); var import_url = require("@clerk/shared/url"); var import_error = require("@clerk/shared/error"); var import_keys2 = require("@clerk/shared/keys"); var errorThrower = (0, import_error.buildErrorThrower)({ packageName: "@clerk/backend" }); var { isDevOrStagingUrl } = (0, import_keys2.createDevOrStagingUrlCache)(); // src/createRedirect.ts var buildUrl = (_baseUrl, _targetUrl, _returnBackUrl, _devBrowserToken) => { if (_baseUrl === "") { return legacyBuildUrl(_targetUrl.toString(), _returnBackUrl?.toString()); } const baseUrl = new URL(_baseUrl); const returnBackUrl = _returnBackUrl ? new URL(_returnBackUrl, baseUrl) : void 0; const res = new URL(_targetUrl, baseUrl); const isCrossOriginRedirect = `${baseUrl.hostname}:${baseUrl.port}` !== `${res.hostname}:${res.port}`; if (returnBackUrl) { if (isCrossOriginRedirect) { returnBackUrl.searchParams.delete(constants.QueryParameters.ClerkSynced); } res.searchParams.set("redirect_url", returnBackUrl.toString()); } if (isCrossOriginRedirect && _devBrowserToken) { res.searchParams.set(constants.QueryParameters.DevBrowser, _devBrowserToken); } return res.toString(); }; var legacyBuildUrl = (targetUrl, redirectUrl) => { let url; if (!targetUrl.startsWith("http")) { if (!redirectUrl || !redirectUrl.startsWith("http")) { throw new Error("destination url or return back url should be an absolute path url!"); } const baseURL = new URL(redirectUrl); url = new URL(targetUrl, baseURL.origin); } else { url = new URL(targetUrl); } if (redirectUrl) { url.searchParams.set("redirect_url", redirectUrl); } return url.toString(); }; var createRedirect = (params) => { const { publishableKey, redirectAdapter, signInUrl, signUpUrl, baseUrl, sessionStatus } = params; const parsedPublishableKey = (0, import_keys.parsePublishableKey)(publishableKey); const frontendApi = parsedPublishableKey?.frontendApi; const isDevelopment = parsedPublishableKey?.instanceType === "development"; const accountsBaseUrl = (0, import_buildAccountsBaseUrl.buildAccountsBaseUrl)(frontendApi); const hasPendingStatus = sessionStatus === "pending"; const redirectToTasks = (url, { returnBackUrl }) => { return redirectAdapter( buildUrl(baseUrl, `${url}/tasks`, returnBackUrl, isDevelopment ? params.devBrowserToken : null) ); }; const redirectToSignUp = ({ returnBackUrl } = {}) => { if (!signUpUrl && !accountsBaseUrl) { errorThrower.throwMissingPublishableKeyError(); } const accountsSignUpUrl = `${accountsBaseUrl}/sign-up`; function buildSignUpUrl(signIn) { if (!signIn) { return; } const url = new URL(signIn, baseUrl); url.pathname = `${url.pathname}/create`; return url.toString(); } const targetUrl = signUpUrl || buildSignUpUrl(signInUrl) || accountsSignUpUrl; if (hasPendingStatus) { return redirectToTasks(targetUrl, { returnBackUrl }); } return redirectAdapter(buildUrl(baseUrl, targetUrl, returnBackUrl, isDevelopment ? params.devBrowserToken : null)); }; const redirectToSignIn = ({ returnBackUrl } = {}) => { if (!signInUrl && !accountsBaseUrl) { errorThrower.throwMissingPublishableKeyError(); } const accountsSignInUrl = `${accountsBaseUrl}/sign-in`; const targetUrl = signInUrl || accountsSignInUrl; if (hasPendingStatus) { return redirectToTasks(targetUrl, { returnBackUrl }); } return redirectAdapter(buildUrl(baseUrl, targetUrl, returnBackUrl, isDevelopment ? params.devBrowserToken : null)); }; return { redirectToSignUp, redirectToSignIn }; }; // src/util/mergePreDefinedOptions.ts function mergePreDefinedOptions(preDefinedOptions, options) { return Object.keys(preDefinedOptions).reduce( (obj, key) => { return { ...obj, [key]: options[key] || obj[key] }; }, { ...preDefinedOptions } ); } // src/errors.ts var TokenVerificationErrorCode = { InvalidSecretKey: "clerk_key_invalid" }; var TokenVerificationErrorReason = { TokenExpired: "token-expired", TokenInvalid: "token-invalid", TokenInvalidAlgorithm: "token-invalid-algorithm", TokenInvalidAuthorizedParties: "token-invalid-authorized-parties", TokenInvalidSignature: "token-invalid-signature", TokenNotActiveYet: "token-not-active-yet", TokenIatInTheFuture: "token-iat-in-the-future", TokenVerificationFailed: "token-verification-failed", InvalidSecretKey: "secret-key-invalid", LocalJWKMissing: "jwk-local-missing", RemoteJWKFailedToLoad: "jwk-remote-failed-to-load", RemoteJWKInvalid: "jwk-remote-invalid", RemoteJWKMissing: "jwk-remote-missing", JWKFailedToResolve: "jwk-failed-to-resolve", JWKKidMismatch: "jwk-kid-mismatch" }; var TokenVerificationErrorAction = { ContactSupport: "Contact support@clerk.com", EnsureClerkJWT: "Make sure that this is a valid Clerk-generated JWT.", SetClerkJWTKey: "Set the CLERK_JWT_KEY environment variable.", SetClerkSecretKey: "Set the CLERK_SECRET_KEY environment variable.", EnsureClockSync: "Make sure your system clock is in sync (e.g. turn off and on automatic time synchronization)." }; var TokenVerificationError = class _TokenVerificationError extends Error { constructor({ action, message, reason }) { super(message); Object.setPrototypeOf(this, _TokenVerificationError.prototype); this.reason = reason; this.message = message; this.action = action; } getFullMessage() { return `${[this.message, this.action].filter((m) => m).join(" ")} (reason=${this.reason}, token-carrier=${this.tokenCarrier})`; } }; var MachineTokenVerificationErrorCode = { TokenInvalid: "token-invalid", InvalidSecretKey: "secret-key-invalid", UnexpectedError: "unexpected-error", TokenVerificationFailed: "token-verification-failed" }; var MachineTokenVerificationError = class _MachineTokenVerificationError extends Error { constructor({ message, code, status, action }) { super(message); Object.setPrototypeOf(this, _MachineTokenVerificationError.prototype); this.code = code; this.status = status; this.action = action; } getFullMessage() { return `${this.message} (code=${this.code}, status=${this.status || "n/a"})`; } }; // src/runtime.ts var import_crypto = require("#crypto"); var globalFetch = fetch.bind(globalThis); var runtime = { crypto: import_crypto.webcrypto, get fetch() { return process.env.NODE_ENV === "test" ? fetch : globalFetch; }, AbortController: globalThis.AbortController, Blob: globalThis.Blob, FormData: globalThis.FormData, Headers: globalThis.Headers, Request: globalThis.Request, Response: globalThis.Response }; // src/util/rfc4648.ts var base64url = { parse(string, opts) { return parse(string, base64UrlEncoding, opts); }, stringify(data, opts) { return stringify(data, base64UrlEncoding, opts); } }; var base64UrlEncoding = { chars: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", bits: 6 }; function parse(string, encoding, opts = {}) { if (!encoding.codes) { encoding.codes = {}; for (let i = 0; i < encoding.chars.length; ++i) { encoding.codes[encoding.chars[i]] = i; } } if (!opts.loose && string.length * encoding.bits & 7) { throw new SyntaxError("Invalid padding"); } let end = string.length; while (string[end - 1] === "=") { --end; if (!opts.loose && !((string.length - end) * encoding.bits & 7)) { throw new SyntaxError("Invalid padding"); } } const out = new (opts.out ?? Uint8Array)(end * encoding.bits / 8 | 0); let bits = 0; let buffer = 0; let written = 0; for (let i = 0; i < end; ++i) { const value = encoding.codes[string[i]]; if (value === void 0) { throw new SyntaxError("Invalid character " + string[i]); } buffer = buffer << encoding.bits | value; bits += encoding.bits; if (bits >= 8) { bits -= 8; out[written++] = 255 & buffer >> bits; } } if (bits >= encoding.bits || 255 & buffer << 8 - bits) { throw new SyntaxError("Unexpected end of data"); } return out; } function stringify(data, encoding, opts = {}) { const { pad = true } = opts; const mask = (1 << encoding.bits) - 1; let out = ""; let bits = 0; let buffer = 0; for (let i = 0; i < data.length; ++i) { buffer = buffer << 8 | 255 & data[i]; bits += 8; while (bits > encoding.bits) { bits -= encoding.bits; out += encoding.chars[mask & buffer >> bits]; } } if (bits) { out += encoding.chars[mask & buffer << encoding.bits - bits]; } if (pad) { while (out.length * encoding.bits & 7) { out += "="; } } return out; } // src/jwt/algorithms.ts var algToHash = { RS256: "SHA-256", RS384: "SHA-384", RS512: "SHA-512" }; var RSA_ALGORITHM_NAME = "RSASSA-PKCS1-v1_5"; var jwksAlgToCryptoAlg = { RS256: RSA_ALGORITHM_NAME, RS384: RSA_ALGORITHM_NAME, RS512: RSA_ALGORITHM_NAME }; var algs = Object.keys(algToHash); function getCryptoAlgorithm(algorithmName) { const hash = algToHash[algorithmName]; const name = jwksAlgToCryptoAlg[algorithmName]; if (!hash || !name) { throw new Error(`Unsupported algorithm ${algorithmName}, expected one of ${algs.join(",")}.`); } return { hash: { name: algToHash[algorithmName] }, name: jwksAlgToCryptoAlg[algorithmName] }; } // src/jwt/assertions.ts var isArrayString = (s) => { return Array.isArray(s) && s.length > 0 && s.every((a) => typeof a === "string"); }; var assertAudienceClaim = (aud, audience) => { const audienceList = [audience].flat().filter((a) => !!a); const audList = [aud].flat().filter((a) => !!a); const shouldVerifyAudience = audienceList.length > 0 && audList.length > 0; if (!shouldVerifyAudience) { return; } if (typeof aud === "string") { if (!audienceList.includes(aud)) { throw new TokenVerificationError({ action: TokenVerificationErrorAction.EnsureClerkJWT, reason: TokenVerificationErrorReason.TokenVerificationFailed, message: `Invalid JWT audience claim (aud) ${JSON.stringify(aud)}. Is not included in "${JSON.stringify( audienceList )}".` }); } } else if (isArrayString(aud)) { if (!aud.some((a) => audienceList.includes(a))) { throw new TokenVerificationError({ action: TokenVerificationErrorAction.EnsureClerkJWT, reason: TokenVerificationErrorReason.TokenVerificationFailed, message: `Invalid JWT audience claim array (aud) ${JSON.stringify(aud)}. Is not included in "${JSON.stringify( audienceList )}".` }); } } }; var assertHeaderType = (typ, allowedTypes = "JWT") => { if (typeof typ === "undefined") { return; } const allowed = Array.isArray(allowedTypes) ? allowedTypes : [allowedTypes]; if (!allowed.includes(typ)) { throw new TokenVerificationError({ action: TokenVerificationErrorAction.EnsureClerkJWT, reason: TokenVerificationErrorReason.TokenInvalid, message: `Invalid JWT type ${JSON.stringify(typ)}. Expected "${allowed.join(", ")}".` }); } }; var assertHeaderAlgorithm = (alg) => { if (!algs.includes(alg)) { throw new TokenVerificationError({ action: TokenVerificationErrorAction.EnsureClerkJWT, reason: TokenVerificationErrorReason.TokenInvalidAlgorithm, message: `Invalid JWT algorithm ${JSON.stringify(alg)}. Supported: ${algs}.` }); } }; var assertSubClaim = (sub) => { if (typeof sub !== "string") { throw new TokenVerificationError({ action: TokenVerificationErrorAction.EnsureClerkJWT, reason: TokenVerificationErrorReason.TokenVerificationFailed, message: `Subject claim (sub) is required and must be a string. Received ${JSON.stringify(sub)}.` }); } }; var assertAuthorizedPartiesClaim = (azp, authorizedParties) => { if (!azp || !authorizedParties || authorizedParties.length === 0) { return; } if (!authorizedParties.includes(azp)) { throw new TokenVerificationError({ reason: TokenVerificationErrorReason.TokenInvalidAuthorizedParties, message: `Invalid JWT Authorized party claim (azp) ${JSON.stringify(azp)}. Expected "${authorizedParties}".` }); } }; var assertExpirationClaim = (exp, clockSkewInMs) => { if (typeof exp !== "number") { throw new TokenVerificationError({ action: TokenVerificationErrorAction.EnsureClerkJWT, reason: TokenVerificationErrorReason.TokenVerificationFailed, message: `Invalid JWT expiry date claim (exp) ${JSON.stringify(exp)}. Expected number.` }); } const currentDate = new Date(Date.now()); const expiryDate = /* @__PURE__ */ new Date(0); expiryDate.setUTCSeconds(exp); const expired = expiryDate.getTime() <= currentDate.getTime() - clockSkewInMs; if (expired) { throw new TokenVerificationError({ reason: TokenVerificationErrorReason.TokenExpired, message: `JWT is expired. Expiry date: ${expiryDate.toUTCString()}, Current date: ${currentDate.toUTCString()}.` }); } }; var assertActivationClaim = (nbf, clockSkewInMs) => { if (typeof nbf === "undefined") { return; } if (typeof nbf !== "number") { throw new TokenVerificationError({ action: TokenVerificationErrorAction.EnsureClerkJWT, reason: TokenVerificationErrorReason.TokenVerificationFailed, message: `Invalid JWT not before date claim (nbf) ${JSON.stringify(nbf)}. Expected number.` }); } const currentDate = new Date(Date.now()); const notBeforeDate = /* @__PURE__ */ new Date(0); notBeforeDate.setUTCSeconds(nbf); const early = notBeforeDate.getTime() > currentDate.getTime() + clockSkewInMs; if (early) { throw new TokenVerificationError({ reason: TokenVerificationErrorReason.TokenNotActiveYet, message: `JWT cannot be used prior to not before date claim (nbf). Not before date: ${notBeforeDate.toUTCString()}; Current date: ${currentDate.toUTCString()};` }); } }; var assertIssuedAtClaim = (iat, clockSkewInMs) => { if (typeof iat === "undefined") { return; } if (typeof iat !== "number") { throw new TokenVerificationError({ action: TokenVerificationErrorAction.EnsureClerkJWT, reason: TokenVerificationErrorReason.TokenVerificationFailed, message: `Invalid JWT issued at date claim (iat) ${JSON.stringify(iat)}. Expected number.` }); } const currentDate = new Date(Date.now()); const issuedAtDate = /* @__PURE__ */ new Date(0); issuedAtDate.setUTCSeconds(iat); const postIssued = issuedAtDate.getTime() > currentDate.getTime() + clockSkewInMs; if (postIssued) { throw new TokenVerificationError({ reason: TokenVerificationErrorReason.TokenIatInTheFuture, message: `JWT issued at date claim (iat) is in the future. Issued at date: ${issuedAtDate.toUTCString()}; Current date: ${currentDate.toUTCString()};` }); } }; // src/jwt/cryptoKeys.ts var import_isomorphicAtob = require("@clerk/shared/isomorphicAtob"); function pemToBuffer(secret) { const trimmed = secret.replace(/-----BEGIN.*?-----/g, "").replace(/-----END.*?-----/g, "").replace(/\s/g, ""); const decoded = (0, import_isomorphicAtob.isomorphicAtob)(trimmed); const buffer = new ArrayBuffer(decoded.length); const bufView = new Uint8Array(buffer); for (let i = 0, strLen = decoded.length; i < strLen; i++) { bufView[i] = decoded.charCodeAt(i); } return bufView; } function importKey(key, algorithm, keyUsage) { if (typeof key === "object") { return runtime.crypto.subtle.importKey("jwk", key, algorithm, false, [keyUsage]); } const keyData = pemToBuffer(key); const format = keyUsage === "sign" ? "pkcs8" : "spki"; return runtime.crypto.subtle.importKey(format, keyData, algorithm, false, [keyUsage]); } // src/jwt/verifyJwt.ts var DEFAULT_CLOCK_SKEW_IN_MS = 5 * 1e3; async function hasValidSignature(jwt, key) { const { header, signature, raw } = jwt; const encoder = new TextEncoder(); const data = encoder.encode([raw.header, raw.payload].join(".")); const algorithm = getCryptoAlgorithm(header.alg); try { const cryptoKey = await importKey(key, algorithm, "verify"); const verified = await runtime.crypto.subtle.verify(algorithm.name, cryptoKey, signature, data); return { data: verified }; } catch (error) { return { errors: [ new TokenVerificationError({ reason: TokenVerificationErrorReason.TokenInvalidSignature, message: error?.message }) ] }; } } function decodeJwt(token) { const tokenParts = (token || "").toString().split("."); if (tokenParts.length !== 3) { return { errors: [ new TokenVerificationError({ reason: TokenVerificationErrorReason.TokenInvalid, message: `Invalid JWT form. A JWT consists of three parts separated by dots.` }) ] }; } const [rawHeader, rawPayload, rawSignature] = tokenParts; const decoder = new TextDecoder(); const header = JSON.parse(decoder.decode(base64url.parse(rawHeader, { loose: true }))); const payload = JSON.parse(decoder.decode(base64url.parse(rawPayload, { loose: true }))); const signature = base64url.parse(rawSignature, { loose: true }); const data = { header, payload, signature, raw: { header: rawHeader, payload: rawPayload, signature: rawSignature, text: token } }; return { data }; } async function verifyJwt(token, options) { const { audience, authorizedParties, clockSkewInMs, key, headerType } = options; const clockSkew = clockSkewInMs || DEFAULT_CLOCK_SKEW_IN_MS; const { data: decoded, errors } = decodeJwt(token); if (errors) { return { errors }; } const { header, payload } = decoded; try { const { typ, alg } = header; assertHeaderType(typ, headerType); assertHeaderAlgorithm(alg); const { azp, sub, aud, iat, exp, nbf } = payload; assertSubClaim(sub); assertAudienceClaim([aud], [audience]); assertAuthorizedPartiesClaim(azp, authorizedParties); assertExpirationClaim(exp, clockSkew); assertActivationClaim(nbf, clockSkew); assertIssuedAtClaim(iat, clockSkew); } catch (err) { return { errors: [err] }; } const { data: signatureValid, errors: signatureErrors } = await hasValidSignature(decoded, key); if (signatureErrors) { return { errors: [ new TokenVerificationError({ action: TokenVerificationErrorAction.EnsureClerkJWT, reason: TokenVerificationErrorReason.TokenVerificationFailed, message: `Error verifying JWT signature. ${signatureErrors[0]}` }) ] }; } if (!signatureValid) { return { errors: [ new TokenVerificationError({ reason: TokenVerificationErrorReason.TokenInvalidSignature, message: "JWT signature is invalid." }) ] }; } return { data: payload }; } // src/util/optionsAssertions.ts function assertValidSecretKey(val) { if (!val || typeof val !== "string") { throw Error("Missing Clerk Secret Key. Go to https://dashboard.clerk.com and get your key for your instance."); } } function assertValidPublishableKey(val) { (0, import_keys.parsePublishableKey)(val, { fatal: true }); } // src/tokens/authenticateContext.ts var import_buildAccountsBaseUrl2 = require("@clerk/shared/buildAccountsBaseUrl"); var import_url2 = require("@clerk/shared/url"); // src/tokens/tokenTypes.ts var TokenType = { SessionToken: "session_token", ApiKey: "api_key", M2MToken: "m2m_token", OAuthToken: "oauth_token" }; // src/tokens/authenticateContext.ts var AuthenticateContext = class { constructor(cookieSuffix, clerkRequest, options) { this.cookieSuffix = cookieSuffix; this.clerkRequest = clerkRequest; /** * The original Clerk frontend API URL, extracted from publishable key before proxy URL override. * Used for backend operations like token validation and issuer checking. */ this.originalFrontendApi = ""; if (options.acceptsToken === TokenType.M2MToken || options.acceptsToken === TokenType.ApiKey) { this.initHeaderValues(); } else { this.initPublishableKeyValues(options); this.initHeaderValues(); this.initCookieValues(); this.initHandshakeValues(); } Object.assign(this, options); this.clerkUrl = this.clerkRequest.clerkUrl; } /** * Retrieves the session token from either the cookie or the header. * * @returns {string | undefined} The session token if available, otherwise undefined. */ get sessionToken() { return this.sessionTokenInCookie || this.tokenInHeader; } usesSuffixedCookies() { const suffixedClientUat = this.getSuffixedCookie(constants.Cookies.ClientUat); const clientUat = this.getCookie(constants.Cookies.ClientUat); const suffixedSession = this.getSuffixedCookie(constants.Cookies.Session) || ""; const session = this.getCookie(constants.Cookies.Session) || ""; if (session && !this.tokenHasIssuer(session)) { return false; } if (session && !this.tokenBelongsToInstance(session)) { return true; } if (!suffixedClientUat && !suffixedSession) { return false; } const { data: sessionData } = decodeJwt(session); const sessionIat = sessionData?.payload.iat || 0; const { data: suffixedSessionData } = decodeJwt(suffixedSession); const suffixedSessionIat = suffixedSessionData?.payload.iat || 0; if (suffixedClientUat !== "0" && clientUat !== "0" && sessionIat > suffixedSessionIat) { return false; } if (suffixedClientUat === "0" && clientUat !== "0") { return false; } if (this.instanceType !== "production") { const isSuffixedSessionExpired = this.sessionExpired(suffixedSessionData); if (suffixedClientUat !== "0" && clientUat === "0" && isSuffixedSessionExpired) { return false; } } if (!suffixedClientUat && suffixedSession) { return false; } return true; } /** * Determines if the request came from a different origin based on the referrer header. * Used for cross-origin detection in multi-domain authentication flows. * * @returns {boolean} True if referrer exists and is from a different origin, false otherwise. */ isCrossOriginReferrer() { if (!this.referrer || !this.clerkUrl.origin) { return false; } try { const referrerOrigin = new URL(this.referrer).origin; return referrerOrigin !== this.clerkUrl.origin; } catch { return false; } } /** * Determines if the referrer URL is from a Clerk domain (accounts portal or FAPI). * This includes both development and production account portal domains, as well as FAPI domains * used for redirect-based authentication flows. * * @returns {boolean} True if the referrer is from a Clerk accounts portal or FAPI domain, false otherwise */ isKnownClerkReferrer() { if (!this.referrer) { return false; } try { const referrerOrigin = new URL(this.referrer); const referrerHost = referrerOrigin.hostname; if (this.frontendApi) { const fapiHost = this.frontendApi.startsWith("http") ? new URL(this.frontendApi).hostname : this.frontendApi; if (referrerHost === fapiHost) { return true; } } if ((0, import_url2.isLegacyDevAccountPortalOrigin)(referrerHost) || (0, import_url2.isCurrentDevAccountPortalOrigin)(referrerHost)) { return true; } const expectedAccountsUrl = (0, import_buildAccountsBaseUrl2.buildAccountsBaseUrl)(this.frontendApi); if (expectedAccountsUrl) { const expectedAccountsOrigin = new URL(expectedAccountsUrl).origin; if (referrerOrigin.origin === expectedAccountsOrigin) { return true; } } if (referrerHost.startsWith("accounts.")) { return true; } return false; } catch { return false; } } initPublishableKeyValues(options) { assertValidPublishableKey(options.publishableKey); this.publishableKey = options.publishableKey; const originalPk = (0, import_keys.parsePublishableKey)(this.publishableKey, { fatal: true, domain: options.domain, isSatellite: options.isSatellite }); this.originalFrontendApi = originalPk.frontendApi; const pk = (0, import_keys.parsePublishableKey)(this.publishableKey, { fatal: true, proxyUrl: options.proxyUrl, domain: options.domain, isSatellite: options.isSatellite }); this.instanceType = pk.instanceType; this.frontendApi = pk.frontendApi; } initHeaderValues() { this.tokenInHeader = this.parseAuthorizationHeader(this.getHeader(constants.Headers.Authorization)); this.origin = this.getHeader(constants.Headers.Origin); this.host = this.getHeader(constants.Headers.Host); this.forwardedHost = this.getHeader(constants.Headers.ForwardedHost); this.forwardedProto = this.getHeader(constants.Headers.CloudFrontForwardedProto) || this.getHeader(constants.Headers.ForwardedProto); this.referrer = this.getHeader(constants.Headers.Referrer); this.userAgent = this.getHeader(constants.Headers.UserAgent); this.secFetchDest = this.getHeader(constants.Headers.SecFetchDest); this.accept = this.getHeader(constants.Headers.Accept); } initCookieValues() { this.sessionTokenInCookie = this.getSuffixedOrUnSuffixedCookie(constants.Cookies.Session); this.refreshTokenInCookie = this.getSuffixedCookie(constants.Cookies.Refresh); this.clientUat = Number.parseInt(this.getSuffixedOrUnSuffixedCookie(constants.Cookies.ClientUat) || "") || 0; } initHandshakeValues() { this.devBrowserToken = this.getQueryParam(constants.QueryParameters.DevBrowser) || this.getSuffixedOrUnSuffixedCookie(constants.Cookies.DevBrowser); this.handshakeToken = this.getQueryParam(constants.QueryParameters.Handshake) || this.getCookie(constants.Cookies.Handshake); this.handshakeRedirectLoopCounter = Number(this.getCookie(constants.Cookies.RedirectCount)) || 0; this.handshakeNonce = this.getQueryParam(constants.QueryParameters.HandshakeNonce) || this.getCookie(constants.Cookies.HandshakeNonce); } getQueryParam(name) { return this.clerkRequest.clerkUrl.searchParams.get(name); } getHeader(name) { return this.clerkRequest.headers.get(name) || void 0; } getCookie(name) { return this.clerkRequest.cookies.get(name) || void 0; } getSuffixedCookie(name) { return this.getCookie((0, import_keys.getSuffixedCookieName)(name, this.cookieSuffix)) || void 0; } getSuffixedOrUnSuffixedCookie(cookieName) { if (this.usesSuffixedCookies()) { return this.getSuffixedCookie(cookieName); } return this.getCookie(cookieName); } parseAuthorizationHeader(authorizationHeader) { if (!authorizationHeader) { return void 0; } const [scheme, token] = authorizationHeader.split(" ", 2); if (!token) { return scheme; } if (scheme === "Bearer") { return token; } return void 0; } tokenHasIssuer(token) { const { data, errors } = decodeJwt(token); if (errors) { return false; } return !!data.payload.iss; } tokenBelongsToInstance(token) { if (!token) { return false; } const { data, errors } = decodeJwt(token); if (errors) { return false; } const tokenIssuer = data.payload.iss.replace(/https?:\/\//gi, ""); return this.originalFrontendApi === tokenIssuer; } sessionExpired(jwt) { return !!jwt && jwt?.payload.exp <= Date.now() / 1e3 >> 0; } }; var createAuthenticateContext = async (clerkRequest, options) => { const cookieSuffix = options.publishableKey ? await (0, import_keys.getCookieSuffix)(options.publishableKey, runtime.crypto.subtle) : ""; return new AuthenticateContext(cookieSuffix, clerkRequest, options); }; // src/tokens/authObjects.ts var import_authorization = require("@clerk/shared/authorization"); var import_jwtPayloadParser = require("@clerk/shared/jwtPayloadParser"); // src/util/path.ts var SEPARATOR = "/"; var MULTIPLE_SEPARATOR_REGEX = new RegExp("(?<!:)" + SEPARATOR + "{1,}", "g"); function joinPaths(...args) { return args.filter((p) => p).join(SEPARATOR).replace(MULTIPLE_SEPARATOR_REGEX, SEPARATOR); } // src/api/endpoints/AbstractApi.ts var AbstractAPI = class { constructor(request) { this.request = request; } requireId(id) { if (!id) { throw new Error("A valid resource ID is required."); } } }; // src/api/endpoints/ActorTokenApi.ts var basePath = "/actor_tokens"; var ActorTokenAPI = class extends AbstractAPI { async create(params) { return this.request({ method: "POST", path: basePath, bodyParams: params }); } async revoke(actorTokenId) { this.requireId(actorTokenId); return this.request({ method: "POST", path: joinPaths(basePath, actorTokenId, "revoke") }); } }; // src/api/endpoints/AccountlessApplicationsAPI.ts var basePath2 = "/accountless_applications"; var AccountlessApplicationAPI = class extends AbstractAPI { async createAccountlessApplication(params) { const headerParams = params?.requestHeaders ? Object.fromEntries(params.requestHeaders.entries()) : void 0; return this.request({ method: "POST", path: basePath2, headerParams }); } async completeAccountlessApplicationOnboarding(params) { const headerParams = params?.requestHeaders ? Object.fromEntries(params.requestHeaders.entries()) : void 0; return this.request({ method: "POST", path: joinPaths(basePath2, "complete"), headerParams }); } }; // src/api/endpoints/AllowlistIdentifierApi.ts var basePath3 = "/allowlist_identifiers"; var AllowlistIdentifierAPI = class extends AbstractAPI { async getAllowlistIdentifierList(params = {}) { return this.request({ method: "GET", path: basePath3, queryParams: { ...params, paginated: true } }); } async createAllowlistIdentifier(params) { return this.request({ method: "POST", path: basePath3, bodyParams: params }); } async deleteAllowlistIdentifier(allowlistIdentifierId) { this.requireId(allowlistIdentifierId); return this.request({ method: "DELETE", path: joinPaths(basePath3, allowlistIdentifierId) }); } }; // src/api/endpoints/APIKeysApi.ts var basePath4 = "/api_keys"; var APIKeysAPI = class extends AbstractAPI { async list(queryParams) { return this.request({ method: "GET", path: basePath4, queryParams }); } async create(params) { return this.request({ method: "POST", path: basePath4, bodyParams: params }); } async get(apiKeyId) { this.requireId(apiKeyId); return this.request({ method: "GET", path: joinPaths(basePath4, apiKeyId) }); } async update(params) { const { apiKeyId, ...bodyParams } = params; this.requireId(apiKeyId); return this.request({ method: "PATCH", path: joinPaths(basePath4, apiKeyId), bodyParams }); } async delete(apiKeyId) { this.requireId(apiKeyId); return this.request({ method: "DELETE", path: joinPaths(basePath4, apiKeyId) }); } async revoke(params) { const { apiKeyId, revocationReason = null } = params; this.requireId(apiKeyId); return this.request({ method: "POST", path: joinPaths(basePath4, apiKeyId, "revoke"), bodyParams: { revocationReason } }); } async getSecret(apiKeyId) { this.requireId(apiKeyId); return this.request({ method: "GET", path: joinPaths(basePath4, apiKeyId, "secret") }); } async verify(secret) { return this.request({ method: "POST", path: joinPaths(basePath4, "verify"), bodyParams: { secret } }); } /** * @deprecated Use `verify()` instead. This method will be removed in the next major release. */ async verifySecret(secret) { (0, import_deprecated.deprecated)("apiKeys.verifySecret()", "Use `apiKeys.verify()` instead."); return this.verify(secret); } }; // src/api/endpoints/BetaFeaturesApi.ts var basePath5 = "/beta_features"; var BetaFeaturesAPI = class extends AbstractAPI { /** * Change the domain of a production instance. * * Changing the domain requires updating the DNS records accordingly, deploying new SSL certificates, * updating your Social Connection's redirect URLs and setting the new keys in your code. * * @remarks * WARNING: Changing your domain will invalidate all current user sessions (i.e. users will be logged out). * Also, while your application is being deployed, a small downtime is expected to occur. */ async changeDomain(params) { return this.request({ method: "POST", path: joinPaths(basePath5, "change_domain"), bodyParams: params }); } }; // src/api/endpoints/BlocklistIdentifierApi.ts var basePath6 = "/blocklist_identifiers"; var BlocklistIdentifierAPI = class extends AbstractAPI { async getBlocklistIdentifierList(params = {}) { return this.request({ method: "GET", path: basePath6, queryParams: params }); } async createBlocklistIdentifier(params) { return this.request({ method: "POST", path: basePath6, bodyParams: params }); } async deleteBlocklistIdentifier(blocklistIdentifierId) { this.requireId(blocklistIdentifierId); return this.request({ method: "DELETE", path: joinPaths(basePath6, blocklistIdentifierId) }); } }; // src/api/endpoints/ClientApi.ts var basePath7 = "/clients"; var ClientAPI = class extends AbstractAPI { async getClientList(params = {}) { return this.request({ method: "GET", path: basePath7, queryParams: { ...params, paginated: true } }); } async getClient(clientId) { this.requireId(clientId); return this.request({ method: "GET", path: joinPaths(basePath7, clientId) }); } verifyClient(token) { return this.request({ method: "POST", path: joinPaths(basePath7, "verify"), bodyParams: { token } }); } async getHandshakePayload(queryParams) { return this.request({ method: "GET", path: joinPaths(basePath7, "handshake_payload"), queryParams }); } }; // src/api/endpoints/DomainApi.ts var basePath8 = "/domains"; var DomainAPI = class extends AbstractAPI { async list() { return this.request({ method: "GET", path: basePath8 }); } async add(params) { return this.request({ method: "POST", path: basePath8, bodyParams: params }); } async update(params) { const { domainId, ...bodyParams } = params; this.requireId(domainId); return this.request({ method: "PATCH", path: joinPaths(basePath8, domainId), bodyParams }); } /** * Deletes a satellite domain for the instance. * It is currently not possible to delete the instance's primary domain. */ async delete(satelliteDomainId) { return this.deleteDomain(satelliteDomainId); } /** * @deprecated Use `delete` instead */ async deleteDomain(satelliteDomainId) { this.requireId(satelliteDomainId); return this.request({ method: "DELETE", path: joinPaths(basePath8, satelliteDomainId) }); } }; // src/api/endpoints/EmailAddressApi.ts var basePath9 = "/email_addresses"; var EmailAddressAPI = class extends AbstractAPI { async getEmailAddress(emailAddressId) { this.requireId(emailAddressId); return this.request({ method: "GET", path: joinPaths(basePath9, emailAddressId) }); } async createEmailAddress(params) { return this.request({ method: "POST", path: basePath9, bodyParams: params }); } async updateEmailAddress(emailAddressId, params = {}) { this.requireId(emailAddressId); return this.request({ method: "PATCH", path: joinPaths(basePath9, emailAddressId), bodyParams: params }); } async deleteEmailAddress(emailAddressId) { this.requireId(emailAddressId); return this.request({ method: "DELETE", path: joinPaths(basePath9, emailAddressId) }); } }; // src/api/endpoints/IdPOAuthAccessTokenApi.ts var basePath10 = "/oauth_applications/access_tokens"; var IdPOAuthAccessTokenApi = class extends AbstractAPI { async verify(accessToken) { return this.request({ method: "POST", path: joinPaths(basePath10, "verify"), bodyParams: { access_token: accessToken } }); } /** * @deprecated Use `verify()` instead. This method will be removed in the next major release. */ async verifyAccessToken(accessToken) { (0, import_deprecated.deprecated)("idPOAuthAccessToken.verifyAccessToken()", "Use `idPOAuthAccessToken.verify()` instead."); return this.verify(accessToken); } }; // src/api/endpoints/InstanceApi.ts var basePath11 = "/instance"; var InstanceAPI = class extends AbstractAPI { async get() { return this.request({ method: "GET", path: basePath11 }); } async update(params) { return this.request({ method: "PATCH", path: basePath11, bodyParams: params }); } async updateRestrictions(params) { return this.request({ method: "PATCH", path: joinPaths(basePath11, "restrictions"), bodyParams: params }); } async updateOrganizationSettings(params) { return this.request({ method: "PATCH", path: joinPaths(basePath11, "organization_settings"), bodyParams: params }); } }; // src/api/endpoints/InvitationApi.ts var basePath12 = "/invitations"; var InvitationAPI = class extends AbstractAPI { async getInvitationList(params = {}) { return this.request({ method: "GET", path: basePath12, queryParams: { ...params, paginated: true } }); } async createInvitation(params) { return this.request({ method: "POST", path: basePath12, bodyParams: params }); } async createInvitationBulk(params) { return this.request({ method: "POST", path: joinPaths(basePath12, "bulk"), bodyParams: params }); } async revokeInvitation(invitationId) { this.requireId(invitationId); return this.request({ method: "POST", path: j