From 9a7208bef08ce8c06a32aadc352e4d2c7bb786fd Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 1 May 2024 14:08:32 +0300 Subject: [PATCH 1/4] fix(clerk-sdk-node): Inherit verifyToken options from clerkClient --- .changeset/modern-boxes-peel.md | 12 ++++++++++++ packages/backend/src/tokens/verify.ts | 12 ++++++++++++ packages/sdk-node/src/clerkClient.ts | 16 ++++++++++++---- 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 .changeset/modern-boxes-peel.md diff --git a/.changeset/modern-boxes-peel.md b/.changeset/modern-boxes-peel.md new file mode 100644 index 00000000000..ef40054c701 --- /dev/null +++ b/.changeset/modern-boxes-peel.md @@ -0,0 +1,12 @@ +--- +'@clerk/clerk-sdk-node': patch +'@clerk/backend': patch +--- + +Inherit verifyToken options from clerkClient. +The below code now works as expected: (requires CLERK_SECRET_KEY env var to have been set) +```ts +import { clerkClient } from "@clerk/clerk-sdk-node"; + +clerkClient.verifyToken(token, {}) +``` diff --git a/packages/backend/src/tokens/verify.ts b/packages/backend/src/tokens/verify.ts index 523cee883be..63f16565229 100644 --- a/packages/backend/src/tokens/verify.ts +++ b/packages/backend/src/tokens/verify.ts @@ -31,6 +31,18 @@ export async function verifyToken( // Fetch JWKS from Backend API using the key key = await loadClerkJWKFromRemote({ ...options, kid }); } else { + if (!options.secretKey || !options.jwtKey) { + return { + errors: [ + new TokenVerificationError({ + action: TokenVerificationErrorAction.SetClerkSecretKey, + message: 'Both JWT Key and Secret Key are missing. Operation could not be completed.', + reason: TokenVerificationErrorReason.InvalidSecretKey, + }), + ], + }; + } + return { errors: [ new TokenVerificationError({ diff --git a/packages/sdk-node/src/clerkClient.ts b/packages/sdk-node/src/clerkClient.ts index fe58cb9dd3c..7a17170d6ea 100644 --- a/packages/sdk-node/src/clerkClient.ts +++ b/packages/sdk-node/src/clerkClient.ts @@ -1,5 +1,5 @@ -import type { ClerkOptions } from '@clerk/backend'; -import { createClerkClient as _createClerkClient, verifyToken } from '@clerk/backend'; +import type { ClerkOptions, VerifyTokenOptions } from '@clerk/backend'; +import { createClerkClient as _createClerkClient, verifyToken as _verifyToken } from '@clerk/backend'; import { createClerkExpressRequireAuth } from './clerkExpressRequireAuth'; import { createClerkExpressWithAuth } from './clerkExpressWithAuth'; @@ -8,7 +8,15 @@ import { loadApiEnv, loadClientEnv } from './utils'; type ClerkClient = ReturnType & { expressWithAuth: ReturnType; expressRequireAuth: ReturnType; - verifyToken: typeof verifyToken; + verifyToken: typeof _verifyToken; +}; + +const buildVerifyToken = (params: VerifyTokenOptions) => { + return (...args: Parameters) => + _verifyToken(args[0], { + ...params, + ...args[1], + }); }; /** @@ -24,7 +32,7 @@ export function createClerkClient(options: ClerkOptions): ClerkClient { return Object.assign(clerkClient, { expressWithAuth, expressRequireAuth, - verifyToken, + verifyToken: buildVerifyToken(options), }); } From 1dec021f5e388e797e9be251ce74630ba01d085e Mon Sep 17 00:00:00 2001 From: panteliselef Date: Fri, 10 May 2024 13:53:18 +0300 Subject: [PATCH 2/4] fix(backend): Drop the InvalidSecretKey error --- packages/backend/src/tokens/verify.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/packages/backend/src/tokens/verify.ts b/packages/backend/src/tokens/verify.ts index 63f16565229..523cee883be 100644 --- a/packages/backend/src/tokens/verify.ts +++ b/packages/backend/src/tokens/verify.ts @@ -31,18 +31,6 @@ export async function verifyToken( // Fetch JWKS from Backend API using the key key = await loadClerkJWKFromRemote({ ...options, kid }); } else { - if (!options.secretKey || !options.jwtKey) { - return { - errors: [ - new TokenVerificationError({ - action: TokenVerificationErrorAction.SetClerkSecretKey, - message: 'Both JWT Key and Secret Key are missing. Operation could not be completed.', - reason: TokenVerificationErrorReason.InvalidSecretKey, - }), - ], - }; - } - return { errors: [ new TokenVerificationError({ From 9d852ad73baa0c816eab67150768d8da8a8af2c9 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Fri, 10 May 2024 14:29:48 +0300 Subject: [PATCH 3/4] fix(clerk-sdk-node): Support verifyToken with optional 2nd param --- .changeset/modern-boxes-peel.md | 7 ++++++- packages/sdk-node/src/clerkClient.ts | 7 +++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.changeset/modern-boxes-peel.md b/.changeset/modern-boxes-peel.md index ef40054c701..ee264083e0e 100644 --- a/.changeset/modern-boxes-peel.md +++ b/.changeset/modern-boxes-peel.md @@ -8,5 +8,10 @@ The below code now works as expected: (requires CLERK_SECRET_KEY env var to have ```ts import { clerkClient } from "@clerk/clerk-sdk-node"; -clerkClient.verifyToken(token, {}) +// Use the default settings from the already instanciated clerkClient +clerkClient.verifyToken(token) +// or provide overrides the options +clerkClient.verifyToken(token, { + secretKey: 'xxxx' +}) ``` diff --git a/packages/sdk-node/src/clerkClient.ts b/packages/sdk-node/src/clerkClient.ts index 7a17170d6ea..b9f26da14cf 100644 --- a/packages/sdk-node/src/clerkClient.ts +++ b/packages/sdk-node/src/clerkClient.ts @@ -5,14 +5,17 @@ import { createClerkExpressRequireAuth } from './clerkExpressRequireAuth'; import { createClerkExpressWithAuth } from './clerkExpressWithAuth'; import { loadApiEnv, loadClientEnv } from './utils'; +type MakeOptionalSecondArgument = T extends (a: string, b: infer U) => infer R ? (a: string, b?: U) => R : never; +type VerifyTokenWithOptionalSecondArgument = MakeOptionalSecondArgument; + type ClerkClient = ReturnType & { expressWithAuth: ReturnType; expressRequireAuth: ReturnType; - verifyToken: typeof _verifyToken; + verifyToken: VerifyTokenWithOptionalSecondArgument; }; const buildVerifyToken = (params: VerifyTokenOptions) => { - return (...args: Parameters) => + return (...args: Parameters) => _verifyToken(args[0], { ...params, ...args[1], From b9c92b82a2e4180274c4a27f4ceb8f02384e4418 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Fri, 10 May 2024 20:22:00 +0300 Subject: [PATCH 4/4] test(clerk-sdk-node): Add test to verify the change --- .../src/__tests__/authenticateRequest.test.ts | 6 --- .../src/__tests__/verifyToken.test.ts | 48 +++++++++++++++++++ 2 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 packages/sdk-node/src/__tests__/verifyToken.test.ts diff --git a/packages/sdk-node/src/__tests__/authenticateRequest.test.ts b/packages/sdk-node/src/__tests__/authenticateRequest.test.ts index 1d1751d43e3..27753a593cb 100644 --- a/packages/sdk-node/src/__tests__/authenticateRequest.test.ts +++ b/packages/sdk-node/src/__tests__/authenticateRequest.test.ts @@ -3,12 +3,6 @@ import { Request } from 'express'; import { authenticateRequest } from '../authenticateRequest'; -const mockNext = jest.fn(); - -afterEach(() => { - mockNext.mockReset(); -}); - const mockClerkClient = () => ({ authenticateRequest: jest.fn(), }); diff --git a/packages/sdk-node/src/__tests__/verifyToken.test.ts b/packages/sdk-node/src/__tests__/verifyToken.test.ts new file mode 100644 index 00000000000..39d5db1044e --- /dev/null +++ b/packages/sdk-node/src/__tests__/verifyToken.test.ts @@ -0,0 +1,48 @@ +const verifyTokenMock = jest.fn(); + +jest.mock('@clerk/backend', () => ({ + ...jest.requireActual('@clerk/backend'), + verifyToken: verifyTokenMock, +})); + +import { createClerkClient } from '../clerkClient'; + +afterEach(() => { + verifyTokenMock.mockReset(); +}); + +describe('verifyToken', () => { + it('correctly use the predefined options of clerkClient', async () => { + const clerkClient = createClerkClient({ + secretKey: '123', + jwtKey: '456', + }); + + await clerkClient.verifyToken('token'); + expect(verifyTokenMock).toHaveBeenCalledWith( + 'token', + expect.objectContaining({ + secretKey: '123', + jwtKey: '456', + }), + ); + }); + + it('correctly use the passed options in verifyToken', async () => { + const clerkClient = createClerkClient({ + secretKey: '123', + jwtKey: '456', + }); + + await clerkClient.verifyToken('token', { + secretKey: '987', + }); + expect(verifyTokenMock).toHaveBeenCalledWith( + 'token', + expect.objectContaining({ + secretKey: '987', + jwtKey: '456', + }), + ); + }); +});