Skip to content

Commit 48b187d

Browse files
authored
fix(backend): return IdPOAuthAccessToken JWT timestamps in milliseconds (#8771)
1 parent c722955 commit 48b187d

3 files changed

Lines changed: 12 additions & 3 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/backend': patch
3+
---
4+
5+
Return `IdPOAuthAccessToken` timestamps in milliseconds when an OAuth access token is verified as a JWT. The `expiration`, `createdAt`, and `updatedAt` fields were previously populated with the JWT's raw second-based `exp`/`iat` values, making them inconsistent with the same fields on `M2MToken` and with the values returned when the token is fetched from the API. Comparing `expiration` against `Date.now()` now behaves as expected. The `expired` flag was already computed correctly and is unaffected.

packages/backend/src/api/resources/IdPOAuthAccessToken.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ export class IdPOAuthAccessToken {
5757
false,
5858
null,
5959
payload.exp * 1000 <= Date.now() - clockSkewInMs,
60-
payload.exp,
61-
payload.iat,
62-
payload.iat,
60+
payload.exp * 1000, // milliseconds: expiration, converted from JWT exp claim
61+
payload.iat * 1000, // milliseconds: createdAt, converted from JWT iat claim
62+
payload.iat * 1000, // milliseconds: updatedAt, no JWT equivalent, defaults to iat
6363
);
6464
}
6565
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,10 @@ describe('tokens.verifyMachineAuthToken(token, options)', () => {
407407
expect(data.type).toBe('oauth_token');
408408
expect(data.subject).toBe('user_2vYVtestTESTtestTESTtestTESTtest');
409409
expect(data.scopes).toEqual(['read:foo', 'write:bar']);
410+
// Timestamps are exposed in milliseconds, matching M2MToken and the API JSON shape
411+
expect(data.expiration).toBe(mockOAuthAccessTokenJwtPayload.exp * 1000);
412+
expect(data.createdAt).toBe(mockOAuthAccessTokenJwtPayload.iat * 1000);
413+
expect(data.updatedAt).toBe(mockOAuthAccessTokenJwtPayload.iat * 1000);
410414
});
411415

412416
it('fails if JWT type is not at+jwt or application/at+jwt', async () => {

0 commit comments

Comments
 (0)