diff --git a/.changeset/fix-multiple-token-types-array.md b/.changeset/fix-multiple-token-types-array.md new file mode 100644 index 00000000000..db48bdbb5db --- /dev/null +++ b/.changeset/fix-multiple-token-types-array.md @@ -0,0 +1,5 @@ +--- +"@clerk/backend": patch +--- + +Fix token-type-mismatch error when using multiple `acceptsToken` values in `authenticateRequest`. When `acceptsToken` is an array containing both session and machine token types (e.g., `['session_token', 'api_key']`), the function now correctly routes to the appropriate authentication handler based on the actual token type, instead of always treating them as machine tokens. \ No newline at end of file diff --git a/packages/backend/src/tokens/__tests__/request.test.ts b/packages/backend/src/tokens/__tests__/request.test.ts index 0d140f8b093..54b2e775e01 100644 --- a/packages/backend/src/tokens/__tests__/request.test.ts +++ b/packages/backend/src/tokens/__tests__/request.test.ts @@ -1426,6 +1426,38 @@ describe('tokens.authenticateRequest(options)', () => { isAuthenticated: false, }); }); + + test('accepts session_token when it is in acceptsToken array with machine tokens', async () => { + server.use( + http.get('https://api.clerk.test/v1/jwks', () => { + return HttpResponse.json(mockJwks); + }), + ); + + const request = mockRequest({ authorization: `Bearer ${mockJwt}` }); + const requestState = await authenticateRequest( + request, + mockOptions({ acceptsToken: ['session_token', 'api_key'] }), + ); + + expect(requestState).toBeSignedIn(); + }); + + test('accepts api_key when it is in acceptsToken array with session_token', async () => { + server.use( + http.post(mockMachineAuthResponses.api_key.endpoint, () => { + return HttpResponse.json(mockVerificationResults.api_key); + }), + ); + + const request = mockRequest({ authorization: `Bearer ${mockTokens.api_key}` }); + const requestState = await authenticateRequest( + request, + mockOptions({ acceptsToken: ['session_token', 'api_key'] }), + ); + + expect(requestState).toBeMachineAuthenticated(); + }); }); describe('Token Location Validation', () => { diff --git a/packages/backend/src/tokens/request.ts b/packages/backend/src/tokens/request.ts index 0061828b026..6624c292205 100644 --- a/packages/backend/src/tokens/request.ts +++ b/packages/backend/src/tokens/request.ts @@ -788,6 +788,13 @@ export const authenticateRequest: AuthenticateRequest = (async ( if (acceptsToken === TokenType.SessionToken) { return authenticateRequestWithTokenInHeader(); } + // When acceptsToken is an array, route based on the actual token type + if (Array.isArray(acceptsToken)) { + if (isMachineToken(authenticateContext.tokenInHeader)) { + return authenticateMachineRequestWithTokenInHeader(); + } + return authenticateRequestWithTokenInHeader(); + } return authenticateMachineRequestWithTokenInHeader(); }