From 1fd2eff38dc71e45d2ff95a5b6e5a99cca53c6e7 Mon Sep 17 00:00:00 2001 From: George Desipris <73396808+desiprisg@users.noreply.github.com> Date: Fri, 29 Mar 2024 17:20:50 +0200 Subject: [PATCH] fix(nextjs,shared): Allow manually passed publishable/secret key to middleware (#3001) * fix(nextjs,shared): Allow manually passed publishable/secret key to middleware * chore(nextjs): Authmiddleware cleanup * chore(nextjs): Clerkmiddleware cleanup * feat(nextjs): Better typing for assertKey util --- .changeset/stupid-coats-smell.md | 6 ++ .../backend/src/util/assertValidSecretKey.ts | 4 +- .../nextjs/src/server/authMiddleware.test.ts | 44 +++-------- packages/nextjs/src/server/authMiddleware.ts | 75 ++++++++++++------- .../nextjs/src/server/clerkMiddleware.test.ts | 15 ++++ packages/nextjs/src/server/clerkMiddleware.ts | 35 ++++++--- packages/nextjs/src/server/errorThrower.ts | 3 + packages/nextjs/src/server/utils.ts | 12 +++ .../src/utils/serverRedirectWithAuth.ts | 8 +- packages/shared/src/error.ts | 7 ++ playground/nextjs/middleware.ts | 2 +- 11 files changed, 135 insertions(+), 76 deletions(-) create mode 100644 .changeset/stupid-coats-smell.md create mode 100644 packages/nextjs/src/server/errorThrower.ts diff --git a/.changeset/stupid-coats-smell.md b/.changeset/stupid-coats-smell.md new file mode 100644 index 0000000000..e24687a223 --- /dev/null +++ b/.changeset/stupid-coats-smell.md @@ -0,0 +1,6 @@ +--- +'@clerk/nextjs': minor +'@clerk/shared': minor +--- + +Allow manually passing a publishable/secret key pair to the `authMiddleware` and `clerkMiddleware` helpers. \ No newline at end of file diff --git a/packages/backend/src/util/assertValidSecretKey.ts b/packages/backend/src/util/assertValidSecretKey.ts index 3fe269c5e5..eecd6db204 100644 --- a/packages/backend/src/util/assertValidSecretKey.ts +++ b/packages/backend/src/util/assertValidSecretKey.ts @@ -1,8 +1,6 @@ export function assertValidSecretKey(val: unknown): asserts val is string { if (!val || typeof val !== 'string') { - throw Error( - 'Missing Clerk Secret Key or API Key. Go to https://dashboard.clerk.com and get your key for your instance.', - ); + throw Error('Missing Clerk Secret Key. Go to https://dashboard.clerk.com and get your key for your instance.'); } //TODO: Check if the key is invalid and throw error diff --git a/packages/nextjs/src/server/authMiddleware.test.ts b/packages/nextjs/src/server/authMiddleware.test.ts index d43f660dae..73d2bd0383 100644 --- a/packages/nextjs/src/server/authMiddleware.test.ts +++ b/packages/nextjs/src/server/authMiddleware.test.ts @@ -10,6 +10,15 @@ const authenticateRequestMock = jest.fn().mockResolvedValue({ headers: new Headers(), }); +// Removing this mock will cause the authMiddleware tests to fail due to missing publishable key +// This mock SHOULD exist before the imports +jest.mock('./constants', () => { + return { + PUBLISHABLE_KEY: 'pk_test_Y2xlcmsuaW5jbHVkZWQua2F0eWRpZC05Mi5sY2wuZGV2JA', + SECRET_KEY: 'sk_test_xxxxxxxxxxxxxxxxxx', + }; +}); + jest.mock('./clerkClient', () => { return { clerkClient: { @@ -19,20 +28,7 @@ jest.mock('./clerkClient', () => { }; }); -const mockRedirectToSignIn = jest.fn().mockImplementation(() => { - const res = NextResponse.redirect( - 'https://accounts.included.katydid-92.lcl.dev/sign-in?redirect_url=https%3A%2F%2Fwww.clerk.com%2Fprotected', - ); - return setHeader(res, 'x-clerk-redirect-to', 'true'); -}); - -jest.mock('./redirectHelpers', () => { - return { - redirectToSignIn: mockRedirectToSignIn, - }; -}); - -import { paths, setHeader } from '../utils'; +import { paths } from '../utils'; import { authMiddleware, DEFAULT_CONFIG_MATCHER, DEFAULT_IGNORED_ROUTES } from './authMiddleware'; // used to assert the mock import { clerkClient } from './clerkClient'; @@ -50,15 +46,6 @@ afterAll(() => { global.console.warn = consoleWarn; }); -// Removing this mock will cause the authMiddleware tests to fail due to missing publishable key -// This mock SHOULD exist before the imports -jest.mock('./constants', () => { - return { - PUBLISHABLE_KEY: 'pk_test_Y2xlcmsuaW5jbHVkZWQua2F0eWRpZC05Mi5sY2wuZGV2JA', - SECRET_KEY: 'sk_test_xxxxxxxxxxxxxxxxxx', - }; -}); - type MockRequestParams = { url: string; appendDevBrowserCookie?: boolean; @@ -449,19 +436,12 @@ describe('Dev Browser JWT when redirecting to cross origin', function () { }); it('does NOT append the Dev Browser JWT if x-clerk-redirect-to header is not set', async () => { - mockRedirectToSignIn.mockReturnValueOnce( - NextResponse.redirect( - 'https://accounts.included.katydid-92.lcl.dev/sign-in?redirect_url=https%3A%2F%2Fwww.clerk.com%2Fprotected', - ), - ); const resp = await authMiddleware({ - beforeAuth: () => NextResponse.next(), + beforeAuth: () => NextResponse.redirect('https://google.com/'), })(mockRequest({ url: '/protected', appendDevBrowserCookie: true }), {} as NextFetchEvent); expect(resp?.status).toEqual(307); - expect(resp?.headers.get('location')).toEqual( - 'https://accounts.included.katydid-92.lcl.dev/sign-in?redirect_url=https%3A%2F%2Fwww.clerk.com%2Fprotected', - ); + expect(resp?.headers.get('location')).toEqual('https://google.com/'); expect(clerkClient.authenticateRequest).toBeCalled(); }); }); diff --git a/packages/nextjs/src/server/authMiddleware.ts b/packages/nextjs/src/server/authMiddleware.ts index 43bf64ab5b..6d66ca7562 100644 --- a/packages/nextjs/src/server/authMiddleware.ts +++ b/packages/nextjs/src/server/authMiddleware.ts @@ -1,5 +1,5 @@ import type { AuthenticateRequestOptions, AuthObject, ClerkRequest } from '@clerk/backend/internal'; -import { AuthStatus, constants, createClerkRequest } from '@clerk/backend/internal'; +import { AuthStatus, constants, createClerkRequest, createRedirect } from '@clerk/backend/internal'; import { isDevelopmentFromSecretKey } from '@clerk/shared/keys'; import { eventMethodCalled } from '@clerk/shared/telemetry'; import type { NextFetchEvent, NextMiddleware, NextRequest } from 'next/server'; @@ -9,13 +9,19 @@ import { isRedirect, mergeResponses, serverRedirectWithAuth, setHeader, stringif import { withLogger } from '../utils/debugLogger'; import { clerkClient } from './clerkClient'; import { createAuthenticateRequestOptions } from './clerkMiddleware'; -import { SECRET_KEY } from './constants'; +import { PUBLISHABLE_KEY, SECRET_KEY, SIGN_IN_URL, SIGN_UP_URL } from './constants'; import { informAboutProtectedRouteInfo, receivedRequestForIgnoredRoute } from './errors'; -import { redirectToSignIn } from './redirectHelpers'; +import { errorThrower } from './errorThrower'; import type { RouteMatcherParam } from './routeMatcher'; import { createRouteMatcher } from './routeMatcher'; import type { NextMiddlewareReturn } from './types'; -import { apiEndpointUnauthorizedNextResponse, decorateRequest, setRequestHeadersOnNextResponse } from './utils'; +import { + apiEndpointUnauthorizedNextResponse, + assertKey, + decorateRequest, + redirectAdapter, + setRequestHeadersOnNextResponse, +} from './utils'; /** * The default ideal matcher that excludes the _next directory (internals) and all static files, @@ -115,19 +121,26 @@ export interface AuthMiddleware { */ const authMiddleware: AuthMiddleware = (...args: unknown[]) => { const [params = {}] = args as [AuthMiddlewareParams?]; - const { beforeAuth, afterAuth, publicRoutes, ignoredRoutes, apiRoutes, ...options } = params; + const publishableKey = assertKey(params.publishableKey || PUBLISHABLE_KEY, () => + errorThrower.throwMissingPublishableKeyError(), + ); + const secretKey = assertKey(params.secretKey || SECRET_KEY, () => errorThrower.throwMissingPublishableKeyError()); + const signInUrl = params.signInUrl || SIGN_IN_URL; + const signUpUrl = params.signUpUrl || SIGN_UP_URL; + + const options = { ...params, publishableKey, secretKey, signInUrl, signUpUrl }; - const isIgnoredRoute = createRouteMatcher(ignoredRoutes || DEFAULT_IGNORED_ROUTES); - const isPublicRoute = createRouteMatcher(withDefaultPublicRoutes(publicRoutes)); - const isApiRoute = createApiRoutes(apiRoutes); - const defaultAfterAuth = createDefaultAfterAuth(isPublicRoute, isApiRoute, params); + const isIgnoredRoute = createRouteMatcher(options.ignoredRoutes || DEFAULT_IGNORED_ROUTES); + const isPublicRoute = createRouteMatcher(withDefaultPublicRoutes(options.publicRoutes)); + const isApiRoute = createApiRoutes(options.apiRoutes); + const defaultAfterAuth = createDefaultAfterAuth(isPublicRoute, isApiRoute, options); clerkClient.telemetry.record( eventMethodCalled('authMiddleware', { - publicRoutes: Boolean(publicRoutes), - ignoredRoutes: Boolean(ignoredRoutes), - beforeAuth: Boolean(beforeAuth), - afterAuth: Boolean(afterAuth), + publicRoutes: Boolean(options.publicRoutes), + ignoredRoutes: Boolean(options.ignoredRoutes), + beforeAuth: Boolean(options.beforeAuth), + afterAuth: Boolean(options.afterAuth), }), ); @@ -146,11 +159,11 @@ const authMiddleware: AuthMiddleware = (...args: unknown[]) => { clerkUrl: nextRequest.experimental_clerkUrl.href, }); - logger.debug('Options debug', { ...options, beforeAuth: !!beforeAuth, afterAuth: !!afterAuth }); + logger.debug('Options debug', { ...options, beforeAuth: !!options.beforeAuth, afterAuth: !!options.afterAuth }); if (isIgnoredRoute(nextRequest)) { logger.debug({ isIgnoredRoute: true }); - if (isDevelopmentFromSecretKey(options.secretKey || SECRET_KEY) && !params.ignoredRoutes) { + if (isDevelopmentFromSecretKey(options.secretKey) && !options.ignoredRoutes) { console.warn( receivedRequestForIgnoredRoute( nextRequest.experimental_clerkUrl.href, @@ -161,7 +174,7 @@ const authMiddleware: AuthMiddleware = (...args: unknown[]) => { return setHeader(NextResponse.next(), constants.Headers.AuthReason, 'ignored-route'); } - const beforeAuthRes = await (beforeAuth && beforeAuth(nextRequest, evt)); + const beforeAuthRes = await (options.beforeAuth && options.beforeAuth(nextRequest, evt)); if (beforeAuthRes === false) { logger.debug('Before auth returned false, skipping'); @@ -192,7 +205,7 @@ const authMiddleware: AuthMiddleware = (...args: unknown[]) => { }); logger.debug(() => ({ auth: JSON.stringify(auth), debug: auth.debug() })); - const afterAuthRes = await (afterAuth || defaultAfterAuth)(auth, nextRequest, evt); + const afterAuthRes = await (options.afterAuth || defaultAfterAuth)(auth, nextRequest, evt); const finalRes = mergeResponses(beforeAuthRes, afterAuthRes) || NextResponse.next(); logger.debug(() => ({ mergedHeaders: stringifyHeaders(finalRes.headers) })); @@ -223,17 +236,25 @@ export { authMiddleware }; const createDefaultAfterAuth = ( isPublicRoute: ReturnType, isApiRoute: ReturnType, - params: AuthMiddlewareParams, + options: { signInUrl: string; signUpUrl: string; publishableKey: string; secretKey: string }, ) => { return (auth: AuthObject, req: WithExperimentalClerkUrl) => { if (!auth.userId && !isPublicRoute(req)) { if (isApiRoute(req)) { - informAboutProtectedRoute(req.experimental_clerkUrl.pathname, params, true); + informAboutProtectedRoute(req.experimental_clerkUrl.pathname, options, true); return apiEndpointUnauthorizedNextResponse(); } else { - informAboutProtectedRoute(req.experimental_clerkUrl.pathname, params, false); + informAboutProtectedRoute(req.experimental_clerkUrl.pathname, options, false); } - return redirectToSignIn({ returnBackUrl: req.experimental_clerkUrl.href }); + return createRedirect({ + redirectAdapter, + signInUrl: options.signInUrl, + signUpUrl: options.signUpUrl, + publishableKey: options.publishableKey, + // We're setting baseUrl to '' here as we want to keep the legacy behavior of + // the redirectToSignIn, redirectToSignUp helpers in the backend package. + baseUrl: '', + }).redirectToSignIn({ returnBackUrl: req.experimental_clerkUrl.href }); } return NextResponse.next(); }; @@ -305,13 +326,17 @@ const withNormalizedClerkUrl = ( return Object.assign(nextRequest, { experimental_clerkUrl: res }); }; -const informAboutProtectedRoute = (path: string, params: AuthMiddlewareParams, isApiRoute: boolean) => { - if (params.debug || isDevelopmentFromSecretKey(params.secretKey || SECRET_KEY)) { +const informAboutProtectedRoute = ( + path: string, + options: AuthMiddlewareParams & { secretKey: string }, + isApiRoute: boolean, +) => { + if (options.debug || isDevelopmentFromSecretKey(options.secretKey)) { console.warn( informAboutProtectedRouteInfo( path, - !!params.publicRoutes, - !!params.ignoredRoutes, + !!options.publicRoutes, + !!options.ignoredRoutes, isApiRoute, DEFAULT_IGNORED_ROUTES, ), diff --git a/packages/nextjs/src/server/clerkMiddleware.test.ts b/packages/nextjs/src/server/clerkMiddleware.test.ts index b26e50ec15..e30d46c22f 100644 --- a/packages/nextjs/src/server/clerkMiddleware.test.ts +++ b/packages/nextjs/src/server/clerkMiddleware.test.ts @@ -5,9 +5,11 @@ import { describe, expect } from '@jest/globals'; import type { NextFetchEvent } from 'next/server'; import { NextRequest, NextResponse } from 'next/server'; +const publishableKey = 'pk_test_Y2xlcmsuaW5jbHVkZWQua2F0eWRpZC05Mi5sY2wuZGV2JA'; const authenticateRequestMock = jest.fn().mockResolvedValue({ toAuth: () => ({}), headers: new Headers(), + publishableKey, }); jest.mock('./clerkClient', () => { @@ -170,6 +172,7 @@ describe('authenticateRequest & handshake', () => { it('returns 307 and starts the handshake flow for handshake requestState status', async () => { const mockLocationUrl = 'https://example.com'; authenticateRequestMock.mockResolvedValueOnce({ + publishableKey, status: AuthStatus.Handshake, headers: new Headers({ Location: mockLocationUrl }), }); @@ -293,6 +296,7 @@ describe('clerkMiddleware(params)', () => { }); authenticateRequestMock.mockResolvedValueOnce({ + publishableKey, status: AuthStatus.SignedOut, headers: new Headers(), toAuth: () => ({ userId: null }), @@ -315,6 +319,7 @@ describe('clerkMiddleware(params)', () => { }); authenticateRequestMock.mockResolvedValueOnce({ + publishableKey, status: AuthStatus.SignedIn, headers: new Headers(), toAuth: () => ({ userId: 'user-id' }), @@ -337,6 +342,7 @@ describe('clerkMiddleware(params)', () => { }); authenticateRequestMock.mockResolvedValueOnce({ + publishableKey, status: AuthStatus.SignedOut, headers: new Headers(), toAuth: () => ({ userId: null }), @@ -359,6 +365,7 @@ describe('clerkMiddleware(params)', () => { }); authenticateRequestMock.mockResolvedValueOnce({ + publishableKey, status: AuthStatus.SignedIn, headers: new Headers(), toAuth: () => ({ userId: 'user-id', has: () => false }), @@ -381,6 +388,7 @@ describe('clerkMiddleware(params)', () => { }); authenticateRequestMock.mockResolvedValueOnce({ + publishableKey, status: AuthStatus.SignedOut, headers: new Headers(), toAuth: () => ({ userId: null }), @@ -404,6 +412,7 @@ describe('clerkMiddleware(params)', () => { }); authenticateRequestMock.mockResolvedValueOnce({ + publishableKey, status: AuthStatus.SignedIn, headers: new Headers(), toAuth: () => ({ userId: 'user-id', has: () => false }), @@ -435,6 +444,7 @@ describe('clerkMiddleware(params)', () => { }); authenticateRequestMock.mockResolvedValueOnce({ + publishableKey, status: AuthStatus.SignedOut, headers: new Headers(), toAuth: () => ({ userId: null }), @@ -457,6 +467,7 @@ describe('clerkMiddleware(params)', () => { }); authenticateRequestMock.mockResolvedValueOnce({ + publishableKey, status: AuthStatus.SignedOut, headers: new Headers(), toAuth: () => ({ userId: null }), @@ -483,6 +494,7 @@ describe('clerkMiddleware(params)', () => { }); authenticateRequestMock.mockResolvedValueOnce({ + publishableKey, status: AuthStatus.SignedOut, headers: new Headers(), toAuth: () => ({ userId: 'userId', has: () => false }), @@ -515,6 +527,7 @@ describe('Dev Browser JWT when redirecting to cross origin for page requests', f }); authenticateRequestMock.mockResolvedValueOnce({ + publishableKey, status: AuthStatus.SignedOut, headers: new Headers(), toAuth: () => ({ userId: null }), @@ -539,6 +552,7 @@ describe('Dev Browser JWT when redirecting to cross origin for page requests', f }); authenticateRequestMock.mockResolvedValueOnce({ + publishableKey, status: AuthStatus.SignedOut, headers: new Headers(), toAuth: () => ({ userId: null }), @@ -562,6 +576,7 @@ describe('Dev Browser JWT when redirecting to cross origin for page requests', f }); authenticateRequestMock.mockResolvedValueOnce({ + publishableKey, status: AuthStatus.SignedOut, headers: new Headers(), toAuth: () => ({ userId: null }), diff --git a/packages/nextjs/src/server/clerkMiddleware.ts b/packages/nextjs/src/server/clerkMiddleware.ts index 030375d2c5..a478c29c2e 100644 --- a/packages/nextjs/src/server/clerkMiddleware.ts +++ b/packages/nextjs/src/server/clerkMiddleware.ts @@ -12,11 +12,18 @@ import { NextResponse } from 'next/server'; import { isRedirect, serverRedirectWithAuth, setHeader } from '../utils'; import { clerkClient } from './clerkClient'; -import { PUBLISHABLE_KEY, SECRET_KEY } from './constants'; +import { PUBLISHABLE_KEY, SECRET_KEY, SIGN_IN_URL, SIGN_UP_URL } from './constants'; +import { errorThrower } from './errorThrower'; import type { AuthProtect } from './protect'; import { createProtect } from './protect'; import type { NextMiddlewareEvtParam, NextMiddlewareRequestParam, NextMiddlewareReturn } from './types'; -import { decorateRequest, handleMultiDomainAndProxy, setRequestHeadersOnNextResponse } from './utils'; +import { + assertKey, + decorateRequest, + handleMultiDomainAndProxy, + redirectAdapter, + setRequestHeadersOnNextResponse, +} from './utils'; const CONTROL_FLOW_ERROR = { FORCE_NOT_FOUND: 'CLERK_PROTECT_REWRITE', @@ -63,7 +70,21 @@ interface ClerkMiddleware { export const clerkMiddleware: ClerkMiddleware = (...args: unknown[]): any => { const [request, event] = parseRequestAndEvent(args); - const [handler, options] = parseHandlerAndOptions(args); + const [handler, params] = parseHandlerAndOptions(args); + const publishableKey = assertKey(params.publishableKey || PUBLISHABLE_KEY, () => + errorThrower.throwMissingPublishableKeyError(), + ); + const secretKey = assertKey(params.secretKey || SECRET_KEY, () => errorThrower.throwMissingSecretKeyError()); + const signInUrl = params.signInUrl || SIGN_IN_URL; + const signUpUrl = params.signUpUrl || SIGN_UP_URL; + + const options = { + ...params, + publishableKey, + secretKey, + signInUrl, + signUpUrl, + }; clerkClient.telemetry.record( eventMethodCalled('clerkMiddleware', { @@ -150,16 +171,10 @@ const parseHandlerAndOptions = (args: unknown[]) => { export const createAuthenticateRequestOptions = (clerkRequest: ClerkRequest, options: ClerkMiddlewareOptions) => { return { ...options, - secretKey: options.secretKey || SECRET_KEY, - publishableKey: options.publishableKey || PUBLISHABLE_KEY, ...handleMultiDomainAndProxy(clerkRequest, options), }; }; -const redirectAdapter = (url: string | URL) => { - return NextResponse.redirect(url, { headers: { [constants.Headers.ClerkRedirectTo]: 'true' } }); -}; - const createMiddlewareRedirectToSignIn = ( clerkRequest: ClerkRequest, ): ClerkMiddlewareAuthObject['redirectToSignIn'] => { @@ -215,7 +230,7 @@ const handleControlFlowErrors = (e: any, clerkRequest: ClerkRequest, requestStat baseUrl: clerkRequest.clerkUrl, signInUrl: requestState.signInUrl, signUpUrl: requestState.signUpUrl, - publishableKey: PUBLISHABLE_KEY, + publishableKey: requestState.publishableKey, }).redirectToSignIn({ returnBackUrl: e.returnBackUrl }); default: throw e; diff --git a/packages/nextjs/src/server/errorThrower.ts b/packages/nextjs/src/server/errorThrower.ts new file mode 100644 index 0000000000..d96fe311cb --- /dev/null +++ b/packages/nextjs/src/server/errorThrower.ts @@ -0,0 +1,3 @@ +import { buildErrorThrower } from '@clerk/shared/error'; + +export const errorThrower = buildErrorThrower({ packageName: '@clerk/nextjs' }); diff --git a/packages/nextjs/src/server/utils.ts b/packages/nextjs/src/server/utils.ts index 3e1cc8d1d1..ada36bd618 100644 --- a/packages/nextjs/src/server/utils.ts +++ b/packages/nextjs/src/server/utils.ts @@ -194,3 +194,15 @@ export const handleMultiDomainAndProxy = (clerkRequest: ClerkRequest, opts: Auth signInUrl, }; }; + +export const redirectAdapter = (url: string | URL) => { + return NextResponse.redirect(url, { headers: { [constants.Headers.ClerkRedirectTo]: 'true' } }); +}; + +export function assertKey(key: string, onError: () => never): string { + if (!key) { + onError(); + } + + return key; +} diff --git a/packages/nextjs/src/utils/serverRedirectWithAuth.ts b/packages/nextjs/src/utils/serverRedirectWithAuth.ts index 082a222f53..69229efb9c 100644 --- a/packages/nextjs/src/utils/serverRedirectWithAuth.ts +++ b/packages/nextjs/src/utils/serverRedirectWithAuth.ts @@ -1,23 +1,21 @@ // Middleware runs on the server side, before clerk-js is loaded, that's why we need Cookies. -import type { AuthenticateRequestOptions, ClerkRequest } from '@clerk/backend/internal'; +import type { ClerkRequest } from '@clerk/backend/internal'; import { constants } from '@clerk/backend/internal'; import { DEV_BROWSER_JWT_KEY, setDevBrowserJWTInURL } from '@clerk/shared/devBrowser'; import { isDevelopmentFromSecretKey } from '@clerk/shared/keys'; import { NextResponse } from 'next/server'; -import { SECRET_KEY } from '../server/constants'; - /** * Grabs the dev browser JWT from cookies and appends it to the redirect URL when redirecting to cross-origin. */ -export const serverRedirectWithAuth = (clerkRequest: ClerkRequest, res: Response, opts: AuthenticateRequestOptions) => { +export const serverRedirectWithAuth = (clerkRequest: ClerkRequest, res: Response, opts: { secretKey: string }) => { const location = res.headers.get('location'); const shouldAppendDevBrowser = res.headers.get(constants.Headers.ClerkRedirectTo) === 'true'; if ( shouldAppendDevBrowser && !!location && - isDevelopmentFromSecretKey(opts.secretKey || SECRET_KEY) && + isDevelopmentFromSecretKey(opts.secretKey) && clerkRequest.clerkUrl.isCrossOrigin(location) ) { const dbJwt = clerkRequest.cookies.get(DEV_BROWSER_JWT_KEY) || ''; diff --git a/packages/shared/src/error.ts b/packages/shared/src/error.ts index ade9c89e20..c7c88c5640 100644 --- a/packages/shared/src/error.ts +++ b/packages/shared/src/error.ts @@ -194,6 +194,7 @@ const DefaultMessages = Object.freeze({ InvalidProxyUrlErrorMessage: `The proxyUrl passed to Clerk is invalid. The expected value for proxyUrl is an absolute URL or a relative path with a leading '/'. (key={{url}})`, InvalidPublishableKeyErrorMessage: `The publishableKey passed to Clerk is invalid. You can get your Publishable key at https://dashboard.clerk.com/last-active?path=api-keys. (key={{key}})`, MissingPublishableKeyErrorMessage: `Missing publishableKey. You can get your key at https://dashboard.clerk.com/last-active?path=api-keys.`, + MissingSecretKeyErrorMessage: `Missing secretKey. You can get your key at https://dashboard.clerk.com/last-active?path=api-keys.`, MissingClerkProvider: `{{source}} can only be used within the component. Learn more: https://clerk.com/docs/components/clerk-provider`, }); @@ -219,6 +220,8 @@ export interface ErrorThrower { throwMissingPublishableKeyError(): never; + throwMissingSecretKeyError(): never; + throwMissingClerkProviderError(params: { source?: string }): never; throw(message: string): never; @@ -273,6 +276,10 @@ export function buildErrorThrower({ packageName, customMessages }: ErrorThrowerO throw new Error(buildMessage(messages.MissingPublishableKeyErrorMessage)); }, + throwMissingSecretKeyError(): never { + throw new Error(buildMessage(messages.MissingSecretKeyErrorMessage)); + }, + throwMissingClerkProviderError(params: { source?: string }): never { throw new Error(buildMessage(messages.MissingClerkProvider, params)); }, diff --git a/playground/nextjs/middleware.ts b/playground/nextjs/middleware.ts index e41136e55e..7c387d67ed 100644 --- a/playground/nextjs/middleware.ts +++ b/playground/nextjs/middleware.ts @@ -9,4 +9,4 @@ export default authMiddleware({ export const config = { matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)'], -}; +} \ No newline at end of file