UNPKG

@clerk/nextjs

Version:

Clerk SDK for NextJS

181 lines • 6.82 kB
import "../chunk-BUSYA2B4.js"; import { constants } from "@clerk/backend/internal"; import { isDevelopmentFromSecretKey } from "@clerk/shared/keys"; import { logger } from "@clerk/shared/logger"; import { isHttpOrHttps } from "@clerk/shared/proxy"; import { handleValueOrFn, isProductionEnvironment } from "@clerk/shared/utils"; import { NextResponse } from "next/server"; import { constants as nextConstants } from "../constants"; import { canUseKeyless } from "../utils/feature-flags"; import { AES, HmacSHA1, Utf8 } from "../vendor/crypto-es"; import { DOMAIN, ENCRYPTION_KEY, IS_SATELLITE, PROXY_URL, SECRET_KEY, SIGN_IN_URL } from "./constants"; import { authSignatureInvalid, encryptionKeyInvalid, encryptionKeyInvalidDev, missingDomainAndProxy, missingSignInUrlInDev } from "./errors"; import { errorThrower } from "./errorThrower"; import { detectClerkMiddleware } from "./headers-utils"; const OVERRIDE_HEADERS = "x-middleware-override-headers"; const MIDDLEWARE_HEADER_PREFIX = "x-middleware-request"; const setRequestHeadersOnNextResponse = (res, req, newHeaders) => { if (!res.headers.get(OVERRIDE_HEADERS)) { res.headers.set(OVERRIDE_HEADERS, [...req.headers.keys()]); req.headers.forEach((val, key) => { res.headers.set(`${MIDDLEWARE_HEADER_PREFIX}-${key}`, val); }); } Object.entries(newHeaders).forEach(([key, val]) => { res.headers.set(OVERRIDE_HEADERS, `${res.headers.get(OVERRIDE_HEADERS)},${key}`); res.headers.set(`${MIDDLEWARE_HEADER_PREFIX}-${key}`, val); }); }; function decorateRequest(req, res, requestState, requestData, keylessMode) { const { reason, message, status, token } = requestState; if (!res) { res = NextResponse.next(); } if (res.headers.get(nextConstants.Headers.NextRedirect)) { return res; } let rewriteURL; if (res.headers.get(nextConstants.Headers.NextResume) === "1") { res.headers.delete(nextConstants.Headers.NextResume); rewriteURL = new URL(req.url); } const rewriteURLHeader = res.headers.get(nextConstants.Headers.NextRewrite); if (rewriteURLHeader) { const reqURL = new URL(req.url); rewriteURL = new URL(rewriteURLHeader); if (rewriteURL.origin !== reqURL.origin) { return res; } } if (rewriteURL) { const clerkRequestData = encryptClerkRequestData(requestData, keylessMode); setRequestHeadersOnNextResponse(res, req, { [constants.Headers.AuthStatus]: status, [constants.Headers.AuthToken]: token || "", [constants.Headers.AuthSignature]: token ? createTokenSignature(token, (requestData == null ? void 0 : requestData.secretKey) || SECRET_KEY || keylessMode.secretKey || "") : "", [constants.Headers.AuthMessage]: message || "", [constants.Headers.AuthReason]: reason || "", [constants.Headers.ClerkUrl]: req.clerkUrl.toString(), ...clerkRequestData ? { [constants.Headers.ClerkRequestData]: clerkRequestData } : {} }); res.headers.set(nextConstants.Headers.NextRewrite, rewriteURL.href); } return res; } const handleMultiDomainAndProxy = (clerkRequest, opts) => { const relativeOrAbsoluteProxyUrl = handleValueOrFn(opts == null ? void 0 : opts.proxyUrl, clerkRequest.clerkUrl, PROXY_URL); let proxyUrl; if (!!relativeOrAbsoluteProxyUrl && !isHttpOrHttps(relativeOrAbsoluteProxyUrl)) { proxyUrl = new URL(relativeOrAbsoluteProxyUrl, clerkRequest.clerkUrl).toString(); } else { proxyUrl = relativeOrAbsoluteProxyUrl; } const isSatellite = handleValueOrFn(opts.isSatellite, new URL(clerkRequest.url), IS_SATELLITE); const domain = handleValueOrFn(opts.domain, new URL(clerkRequest.url), DOMAIN); const signInUrl = (opts == null ? void 0 : opts.signInUrl) || SIGN_IN_URL; if (isSatellite && !proxyUrl && !domain) { throw new Error(missingDomainAndProxy); } if (isSatellite && !isHttpOrHttps(signInUrl) && isDevelopmentFromSecretKey(opts.secretKey || SECRET_KEY)) { throw new Error(missingSignInUrlInDev); } return { proxyUrl, isSatellite, domain, signInUrl }; }; const redirectAdapter = (url) => { return NextResponse.redirect(url, { headers: { [constants.Headers.ClerkRedirectTo]: "true" } }); }; function assertAuthStatus(req, error) { if (!detectClerkMiddleware(req)) { throw new Error(error); } } function assertKey(key, onError) { if (!key) { onError(); } return key; } function createTokenSignature(token, key) { return HmacSHA1(token, key).toString(); } function assertTokenSignature(token, key, signature) { if (!signature) { throw new Error(authSignatureInvalid); } const expectedSignature = createTokenSignature(token, key); if (expectedSignature !== signature) { throw new Error(authSignatureInvalid); } } const KEYLESS_ENCRYPTION_KEY = "clerk_keyless_dummy_key"; function encryptClerkRequestData(requestData, keylessMode) { const isEmpty = (obj) => { if (!obj) { return true; } return !Object.values(obj).some((v) => v !== void 0); }; if (isEmpty(requestData) && isEmpty(keylessMode)) { return; } if (requestData.secretKey && !ENCRYPTION_KEY) { logger.warnOnce( "Clerk: Missing `CLERK_ENCRYPTION_KEY`. Required for propagating `secretKey` middleware option. See docs: https://clerk.com/docs/references/nextjs/clerk-middleware#dynamic-keys" ); return; } const maybeKeylessEncryptionKey = isProductionEnvironment() ? ENCRYPTION_KEY || assertKey(SECRET_KEY, () => errorThrower.throwMissingSecretKeyError()) : ENCRYPTION_KEY || SECRET_KEY || KEYLESS_ENCRYPTION_KEY; return AES.encrypt(JSON.stringify({ ...keylessMode, ...requestData }), maybeKeylessEncryptionKey).toString(); } function decryptClerkRequestData(encryptedRequestData) { if (!encryptedRequestData) { return {}; } const maybeKeylessEncryptionKey = isProductionEnvironment() ? ENCRYPTION_KEY || SECRET_KEY : ENCRYPTION_KEY || SECRET_KEY || KEYLESS_ENCRYPTION_KEY; try { return decryptData(encryptedRequestData, maybeKeylessEncryptionKey); } catch { if (canUseKeyless) { try { return decryptData(encryptedRequestData, KEYLESS_ENCRYPTION_KEY); } catch { throwInvalidEncryptionKey(); } } throwInvalidEncryptionKey(); } } function throwInvalidEncryptionKey() { if (isProductionEnvironment()) { throw new Error(encryptionKeyInvalid); } throw new Error(encryptionKeyInvalidDev); } function decryptData(data, key) { const decryptedBytes = AES.decrypt(data, key); const encoded = decryptedBytes.toString(Utf8); return JSON.parse(encoded); } export { assertAuthStatus, assertKey, assertTokenSignature, decorateRequest, decryptClerkRequestData, encryptClerkRequestData, handleMultiDomainAndProxy, redirectAdapter, setRequestHeadersOnNextResponse }; //# sourceMappingURL=utils.js.map