Skip to content

Commit 1e4074d

Browse files
fix(backend): Handle token type array in authenticateRequest (#7563)
Co-authored-by: Ayush2k02 <[email protected]>
1 parent faaeada commit 1e4074d

File tree

3 files changed

+99
-3
lines changed

3 files changed

+99
-3
lines changed

.changeset/weak-wombats-begin.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

packages/backend/src/tokens/__tests__/request.test.ts

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,7 +1393,7 @@ describe('tokens.authenticateRequest(options)', () => {
13931393
});
13941394

13951395
describe('Array of Accepted Token Types', () => {
1396-
test('accepts token when it is in the acceptsToken array', async () => {
1396+
test('accepts machine token when it is in the acceptsToken array', async () => {
13971397
server.use(
13981398
http.post(mockMachineAuthResponses.api_key.endpoint, () => {
13991399
return HttpResponse.json(mockVerificationResults.api_key);
@@ -1409,8 +1409,83 @@ describe('tokens.authenticateRequest(options)', () => {
14091409
expect(requestState).toBeMachineAuthenticated();
14101410
});
14111411

1412-
test('returns unauthenticated state when token type is not in the acceptsToken array', async () => {
1412+
test('accepts session token in header when session_token is in the acceptsToken array', async () => {
1413+
server.use(
1414+
http.get('https://api.clerk.test/v1/jwks', () => {
1415+
return HttpResponse.json(mockJwks);
1416+
}),
1417+
);
1418+
1419+
const request = mockRequest({ authorization: `Bearer ${mockJwt}` });
1420+
const requestState = await authenticateRequest(
1421+
request,
1422+
mockOptions({ acceptsToken: ['session_token', 'api_key'] }),
1423+
);
1424+
1425+
expect(requestState).toBeSignedIn();
1426+
expect(requestState.toAuth()).toBeSignedInToAuth();
1427+
});
1428+
1429+
test('accepts session token in cookie when session_token is in the acceptsToken array', async () => {
1430+
server.use(
1431+
http.get('https://api.clerk.test/v1/jwks', () => {
1432+
return HttpResponse.json(mockJwks);
1433+
}),
1434+
);
1435+
1436+
const requestState = await authenticateRequest(
1437+
mockRequestWithCookies(
1438+
{},
1439+
{
1440+
__session: mockJwt,
1441+
__client_uat: '12345',
1442+
},
1443+
),
1444+
mockOptions({ acceptsToken: ['session_token', 'api_key'] }),
1445+
);
1446+
1447+
// The key assertion: session token is accepted (not rejected as invalid token)
1448+
// Cookie-based auth may trigger handshake flow, but should not return TokenTypeMismatch
1449+
expect(requestState.tokenType).not.toBeNull();
1450+
expect(requestState.reason).not.toBe(AuthErrorReason.TokenTypeMismatch);
1451+
});
1452+
1453+
test('accepts machine token when acceptsToken array contains mixed token types', async () => {
1454+
server.use(
1455+
http.post(mockMachineAuthResponses.m2m_token.endpoint, () => {
1456+
return HttpResponse.json(mockVerificationResults.m2m_token);
1457+
}),
1458+
);
1459+
14131460
const request = mockRequest({ authorization: `Bearer ${mockTokens.m2m_token}` });
1461+
const requestState = await authenticateRequest(
1462+
request,
1463+
mockOptions({ acceptsToken: ['session_token', 'm2m_token'] }),
1464+
);
1465+
1466+
expect(requestState).toBeMachineAuthenticated();
1467+
});
1468+
1469+
test('returns unauthenticated state when machine token type is not in the acceptsToken array', async () => {
1470+
const request = mockRequest({ authorization: `Bearer ${mockTokens.m2m_token}` });
1471+
const requestState = await authenticateRequest(
1472+
request,
1473+
mockOptions({ acceptsToken: ['api_key', 'oauth_token'] }),
1474+
);
1475+
1476+
expect(requestState).toBeMachineUnauthenticated({
1477+
tokenType: null,
1478+
reason: AuthErrorReason.TokenTypeMismatch,
1479+
message: '',
1480+
});
1481+
expect(requestState.toAuth()).toBeMachineUnauthenticatedToAuth({
1482+
tokenType: null,
1483+
isAuthenticated: false,
1484+
});
1485+
});
1486+
1487+
test('returns unauthenticated state when session token is provided but not in the acceptsToken array', async () => {
1488+
const request = mockRequest({ authorization: `Bearer ${mockJwt}` });
14141489
const requestState = await authenticateRequest(
14151490
request,
14161491
mockOptions({ acceptsToken: ['api_key', 'oauth_token'] }),
@@ -1426,6 +1501,25 @@ describe('tokens.authenticateRequest(options)', () => {
14261501
isAuthenticated: false,
14271502
});
14281503
});
1504+
1505+
test('returns unauthenticated state when no token is provided and acceptsToken array contains only machine tokens', async () => {
1506+
const requestState = await authenticateRequest(
1507+
mockRequestWithCookies(
1508+
{},
1509+
{
1510+
__session: mockJwt,
1511+
__client_uat: '12345',
1512+
},
1513+
),
1514+
mockOptions({ acceptsToken: ['api_key', 'm2m_token'] }),
1515+
);
1516+
1517+
expect(requestState).toBeMachineUnauthenticated({
1518+
tokenType: null,
1519+
reason: AuthErrorReason.TokenTypeMismatch,
1520+
message: '',
1521+
});
1522+
});
14291523
});
14301524

14311525
describe('Token Location Validation', () => {

packages/backend/src/tokens/request.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,7 @@ export const authenticateRequest: AuthenticateRequest = (async (
782782
}
783783

784784
if (authenticateContext.tokenInHeader) {
785-
if (acceptsToken === 'any') {
785+
if (acceptsToken === 'any' || Array.isArray(acceptsToken)) {
786786
return authenticateAnyRequestWithTokenInHeader();
787787
}
788788
if (acceptsToken === TokenType.SessionToken) {

0 commit comments

Comments
 (0)