@clerk/nextjs
Version:
Clerk SDK for NextJS
314 lines • 15.1 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var clerkMiddleware_exports = {};
__export(clerkMiddleware_exports, {
clerkMiddleware: () => clerkMiddleware,
createAuthenticateRequestOptions: () => createAuthenticateRequestOptions
});
module.exports = __toCommonJS(clerkMiddleware_exports);
var import_internal = require("@clerk/backend/internal");
var import_keys = require("@clerk/shared/keys");
var import_navigation = require("next/navigation");
var import_server = require("next/server");
var import_utils = require("../utils");
var import_debugLogger = require("../utils/debugLogger");
var import_feature_flags = require("../utils/feature-flags");
var import_clerkClient = require("./clerkClient");
var import_constants = require("./constants");
var import_content_security_policy = require("./content-security-policy");
var import_errorThrower = require("./errorThrower");
var import_headers_utils = require("./headers-utils");
var import_keyless = require("./keyless");
var import_middleware_storage = require("./middleware-storage");
var import_nextErrors = require("./nextErrors");
var import_protect = require("./protect");
var import_utils2 = require("./utils");
const clerkMiddleware = (...args) => {
const [request, event] = parseRequestAndEvent(args);
const [handler, params] = parseHandlerAndOptions(args);
const middleware = import_middleware_storage.clerkMiddlewareRequestDataStorage.run(import_middleware_storage.clerkMiddlewareRequestDataStore, () => {
const baseNextMiddleware = (0, import_debugLogger.withLogger)("clerkMiddleware", (logger) => async (request2, event2) => {
var _a, _b;
const resolvedParams = typeof params === "function" ? await params(request2) : params;
const keyless = await (0, import_keyless.getKeylessCookieValue)((name) => {
var _a2;
return (_a2 = request2.cookies.get(name)) == null ? void 0 : _a2.value;
});
const publishableKey = (0, import_utils2.assertKey)(
resolvedParams.publishableKey || import_constants.PUBLISHABLE_KEY || (keyless == null ? void 0 : keyless.publishableKey),
() => import_errorThrower.errorThrower.throwMissingPublishableKeyError()
);
const secretKey = (0, import_utils2.assertKey)(
resolvedParams.secretKey || import_constants.SECRET_KEY || (keyless == null ? void 0 : keyless.secretKey),
() => import_errorThrower.errorThrower.throwMissingSecretKeyError()
);
const signInUrl = resolvedParams.signInUrl || import_constants.SIGN_IN_URL;
const signUpUrl = resolvedParams.signUpUrl || import_constants.SIGN_UP_URL;
const options = {
publishableKey,
secretKey,
signInUrl,
signUpUrl,
...resolvedParams
};
import_middleware_storage.clerkMiddlewareRequestDataStore.set("requestData", options);
const resolvedClerkClient = await (0, import_clerkClient.clerkClient)();
if (options.debug) {
logger.enable();
}
const clerkRequest = (0, import_internal.createClerkRequest)(request2);
logger.debug("options", options);
logger.debug("url", () => clerkRequest.toJSON());
const authHeader = request2.headers.get(import_internal.constants.Headers.Authorization);
if (authHeader && authHeader.startsWith("Basic ")) {
logger.debug("Basic Auth detected");
}
const cspHeader = request2.headers.get(import_internal.constants.Headers.ContentSecurityPolicy);
if (cspHeader) {
logger.debug("Content-Security-Policy detected", () => ({
value: cspHeader
}));
}
const requestState = await resolvedClerkClient.authenticateRequest(
clerkRequest,
createAuthenticateRequestOptions(clerkRequest, options)
);
logger.debug("requestState", () => ({
status: requestState.status,
// @ts-expect-error : FIXME
headers: JSON.stringify(Object.fromEntries(requestState.headers)),
reason: requestState.reason
}));
const locationHeader = requestState.headers.get(import_internal.constants.Headers.Location);
if (locationHeader) {
return new Response(null, { status: 307, headers: requestState.headers });
} else if (requestState.status === import_internal.AuthStatus.Handshake) {
throw new Error("Clerk: handshake status without redirect");
}
const authObject = requestState.toAuth();
logger.debug("auth", () => ({ auth: authObject, debug: authObject.debug() }));
const redirectToSignIn = createMiddlewareRedirectToSignIn(clerkRequest);
const redirectToSignUp = createMiddlewareRedirectToSignUp(clerkRequest);
const protect = await createMiddlewareProtect(clerkRequest, authObject, redirectToSignIn);
const authHandler = createMiddlewareAuthHandler(authObject, redirectToSignIn, redirectToSignUp);
authHandler.protect = protect;
let handlerResult = import_server.NextResponse.next();
try {
const userHandlerResult = await import_middleware_storage.clerkMiddlewareRequestDataStorage.run(
import_middleware_storage.clerkMiddlewareRequestDataStore,
async () => handler == null ? void 0 : handler(authHandler, request2, event2)
);
handlerResult = userHandlerResult || handlerResult;
} catch (e) {
handlerResult = handleControlFlowErrors(e, clerkRequest, request2, requestState);
}
if (options.contentSecurityPolicy) {
const { headers } = (0, import_content_security_policy.createContentSecurityPolicyHeaders)(
((_b = (_a = (0, import_keys.parsePublishableKey)(publishableKey)) == null ? void 0 : _a.frontendApi) != null ? _b : "").replace("$", ""),
options.contentSecurityPolicy
);
headers.forEach(([key, value]) => {
(0, import_utils.setHeader)(handlerResult, key, value);
});
logger.debug("Clerk generated CSP", () => ({
headers
}));
}
if (requestState.headers) {
requestState.headers.forEach((value, key) => {
if (key === import_internal.constants.Headers.ContentSecurityPolicy) {
logger.debug("Content-Security-Policy detected", () => ({
value
}));
}
handlerResult.headers.append(key, value);
});
}
if ((0, import_utils.isRedirect)(handlerResult)) {
logger.debug("handlerResult is redirect");
return (0, import_utils.serverRedirectWithAuth)(clerkRequest, handlerResult, options);
}
if (options.debug) {
(0, import_utils2.setRequestHeadersOnNextResponse)(handlerResult, clerkRequest, { [import_internal.constants.Headers.EnableDebug]: "true" });
}
const keylessKeysForRequestData = (
// Only pass keyless credentials when there are no explicit keys
secretKey === (keyless == null ? void 0 : keyless.secretKey) ? {
publishableKey: keyless == null ? void 0 : keyless.publishableKey,
secretKey: keyless == null ? void 0 : keyless.secretKey
} : {}
);
(0, import_utils2.decorateRequest)(clerkRequest, handlerResult, requestState, resolvedParams, keylessKeysForRequestData);
return handlerResult;
});
const keylessMiddleware = async (request2, event2) => {
var _a, _b;
if (isKeylessSyncRequest(request2)) {
return returnBackFromKeylessSync(request2);
}
const resolvedParams = typeof params === "function" ? await params(request2) : params;
const keyless = await (0, import_keyless.getKeylessCookieValue)((name) => {
var _a2;
return (_a2 = request2.cookies.get(name)) == null ? void 0 : _a2.value;
});
const isMissingPublishableKey = !(resolvedParams.publishableKey || import_constants.PUBLISHABLE_KEY || (keyless == null ? void 0 : keyless.publishableKey));
const authHeader = (_b = (_a = (0, import_headers_utils.getHeader)(request2, import_internal.constants.Headers.Authorization)) == null ? void 0 : _a.replace("Bearer ", "")) != null ? _b : "";
if (isMissingPublishableKey && !(0, import_internal.isMachineTokenByPrefix)(authHeader)) {
const res = import_server.NextResponse.next();
(0, import_utils2.setRequestHeadersOnNextResponse)(res, request2, {
[import_internal.constants.Headers.AuthStatus]: "signed-out"
});
return res;
}
return baseNextMiddleware(request2, event2);
};
const nextMiddleware = async (request2, event2) => {
if (import_feature_flags.canUseKeyless) {
return keylessMiddleware(request2, event2);
}
return baseNextMiddleware(request2, event2);
};
if (request && event) {
return nextMiddleware(request, event);
}
return nextMiddleware;
});
return middleware;
};
const parseRequestAndEvent = (args) => {
return [args[0] instanceof Request ? args[0] : void 0, args[0] instanceof Request ? args[1] : void 0];
};
const parseHandlerAndOptions = (args) => {
return [
typeof args[0] === "function" ? args[0] : void 0,
(args.length === 2 ? args[1] : typeof args[0] === "function" ? {} : args[0]) || {}
];
};
const isKeylessSyncRequest = (request) => request.nextUrl.pathname === "/clerk-sync-keyless";
const returnBackFromKeylessSync = (request) => {
const returnUrl = request.nextUrl.searchParams.get("returnUrl");
const url = new URL(request.url);
url.pathname = "";
return import_server.NextResponse.redirect(returnUrl || url.toString());
};
const createAuthenticateRequestOptions = (clerkRequest, options) => {
return {
...options,
...(0, import_utils2.handleMultiDomainAndProxy)(clerkRequest, options),
// TODO: Leaving the acceptsToken as 'any' opens up the possibility of
// an economic attack. We should revisit this and only verify a token
// when auth() or auth.protect() is invoked.
acceptsToken: "any"
};
};
const createMiddlewareRedirectToSignIn = (clerkRequest) => {
return (opts = {}) => {
const url = clerkRequest.clerkUrl.toString();
(0, import_nextErrors.redirectToSignInError)(url, opts.returnBackUrl);
};
};
const createMiddlewareRedirectToSignUp = (clerkRequest) => {
return (opts = {}) => {
const url = clerkRequest.clerkUrl.toString();
(0, import_nextErrors.redirectToSignUpError)(url, opts.returnBackUrl);
};
};
const createMiddlewareProtect = (clerkRequest, rawAuthObject, redirectToSignIn) => {
return async (params, options) => {
const notFound = () => (0, import_navigation.notFound)();
const redirect = (url) => (0, import_nextErrors.nextjsRedirectError)(url, {
redirectUrl: url
});
const requestedToken = (params == null ? void 0 : params.token) || (options == null ? void 0 : options.token) || import_internal.TokenType.SessionToken;
const authObject = (0, import_internal.getAuthObjectForAcceptedToken)({ authObject: rawAuthObject, acceptsToken: requestedToken });
return (0, import_protect.createProtect)({
request: clerkRequest,
redirect,
notFound,
unauthorized: import_nextErrors.unauthorized,
authObject,
redirectToSignIn
})(params, options);
};
};
const createMiddlewareAuthHandler = (rawAuthObject, redirectToSignIn, redirectToSignUp) => {
const authHandler = async (options) => {
var _a;
const acceptsToken = (_a = options == null ? void 0 : options.acceptsToken) != null ? _a : import_internal.TokenType.SessionToken;
const authObject = (0, import_internal.getAuthObjectForAcceptedToken)({ authObject: rawAuthObject, acceptsToken });
if (authObject.tokenType === import_internal.TokenType.SessionToken && (0, import_internal.isTokenTypeAccepted)(import_internal.TokenType.SessionToken, acceptsToken)) {
return Object.assign(authObject, {
redirectToSignIn,
redirectToSignUp
});
}
return authObject;
};
return authHandler;
};
const handleControlFlowErrors = (e, clerkRequest, nextRequest, requestState) => {
var _a;
if ((0, import_nextErrors.isNextjsUnauthorizedError)(e)) {
const response = new import_server.NextResponse(null, { status: 401 });
const authObject = requestState.toAuth();
if (authObject && authObject.tokenType === import_internal.TokenType.OAuthToken) {
const publishableKey = (0, import_keys.parsePublishableKey)(requestState.publishableKey);
return (0, import_utils.setHeader)(
response,
"WWW-Authenticate",
`Bearer resource_metadata="https://${publishableKey == null ? void 0 : publishableKey.frontendApi}/.well-known/oauth-protected-resource"`
);
}
return response;
}
if ((0, import_nextErrors.isNextjsNotFoundError)(e)) {
return (0, import_utils.setHeader)(
// This is an internal rewrite purely to trigger a not found error. We do not want Next.js to think that the
// destination URL is a valid page, so we use `nextRequest.url` as the base for the fake URL, which Next.js
// understands is an internal URL and won't run middleware against the request.
import_server.NextResponse.rewrite(new URL(`/clerk_${Date.now()}`, nextRequest.url)),
import_internal.constants.Headers.AuthReason,
"protect-rewrite"
);
}
const isRedirectToSignIn = (0, import_nextErrors.isRedirectToSignInError)(e);
const isRedirectToSignUp = (0, import_nextErrors.isRedirectToSignUpError)(e);
if (isRedirectToSignIn || isRedirectToSignUp) {
const redirect = (0, import_internal.createRedirect)({
redirectAdapter: import_utils2.redirectAdapter,
baseUrl: clerkRequest.clerkUrl,
signInUrl: requestState.signInUrl,
signUpUrl: requestState.signUpUrl,
publishableKey: requestState.publishableKey,
sessionStatus: (_a = requestState.toAuth()) == null ? void 0 : _a.sessionStatus
});
const { returnBackUrl } = e;
return redirect[isRedirectToSignIn ? "redirectToSignIn" : "redirectToSignUp"]({ returnBackUrl });
}
if ((0, import_nextErrors.isNextjsRedirectError)(e)) {
return (0, import_utils2.redirectAdapter)(e.redirectUrl);
}
throw e;
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
clerkMiddleware,
createAuthenticateRequestOptions
});
//# sourceMappingURL=clerkMiddleware.js.map
;