Skip to content

Commit

Permalink
fix(backend): Replace session-token-outdated error with more specif…
Browse files Browse the repository at this point in the history
…ic errors (#4205)
  • Loading branch information
anagstef authored Sep 23, 2024
1 parent 5e0da19 commit c59636a
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/ninety-comics-scream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@clerk/backend": patch
---

Improve debugging error reasons.
1 change: 1 addition & 0 deletions packages/backend/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const TokenVerificationErrorReason = {
TokenInvalidAuthorizedParties: 'token-invalid-authorized-parties',
TokenInvalidSignature: 'token-invalid-signature',
TokenNotActiveYet: 'token-not-active-yet',
TokenIatInTheFuture: 'token-iat-in-the-future',
TokenVerificationFailed: 'token-verification-failed',
InvalidSecretKey: 'secret-key-invalid',
LocalJWKMissing: 'jwk-local-missing',
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/jwt/assertions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export const assertIssuedAtClaim = (iat: number | undefined, clockSkewInMs: numb
const postIssued = issuedAtDate.getTime() > currentDate.getTime() + clockSkewInMs;
if (postIssued) {
throw new TokenVerificationError({
reason: TokenVerificationErrorReason.TokenNotActiveYet,
reason: TokenVerificationErrorReason.TokenIatInTheFuture,
message: `JWT issued at date claim (iat) is in the future. Issued at date: ${issuedAtDate.toUTCString()}; Current date: ${currentDate.toUTCString()};`,
});
}
Expand Down
6 changes: 3 additions & 3 deletions packages/backend/src/tokens/__tests__/request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ export default (QUnit: QUnit) => {

const requestState = await authenticateRequest(mockRequestWithHeaderAuth(), mockOptions());

assertHandshake(assert, requestState, { reason: AuthErrorReason.SessionTokenOutdated });
assertHandshake(assert, requestState, { reason: AuthErrorReason.SessionTokenExpired });
assert.strictEqual(requestState.toAuth(), null);
});

Expand Down Expand Up @@ -487,7 +487,7 @@ export default (QUnit: QUnit) => {
mockOptions(),
);

assertHandshake(assert, requestState, { reason: AuthErrorReason.SessionTokenOutdated });
assertHandshake(assert, requestState, { reason: AuthErrorReason.SessionTokenIATBeforeClientUAT });
assert.equal(requestState.message, '');
assert.strictEqual(requestState.toAuth(), null);
});
Expand Down Expand Up @@ -554,7 +554,7 @@ export default (QUnit: QUnit) => {
mockOptions(),
);

assertHandshake(assert, requestState, { reason: AuthErrorReason.SessionTokenOutdated });
assertHandshake(assert, requestState, { reason: AuthErrorReason.SessionTokenExpired });
assert.true(/^JWT is expired/.test(requestState.message || ''));
assert.strictEqual(requestState.toAuth(), null);
});
Expand Down
5 changes: 4 additions & 1 deletion packages/backend/src/tokens/authStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ export const AuthErrorReason = {
SatelliteCookieNeedsSyncing: 'satellite-needs-syncing',
SessionTokenAndUATMissing: 'session-token-and-uat-missing',
SessionTokenMissing: 'session-token-missing',
SessionTokenOutdated: 'session-token-outdated',
SessionTokenExpired: 'session-token-expired',
SessionTokenIATBeforeClientUAT: 'session-token-iat-before-client-uat',
SessionTokenNotActiveYet: 'session-token-not-active-yet',
SessionTokenIatInTheFuture: 'session-token-iat-in-the-future',
SessionTokenWithoutClientUAT: 'session-token-but-no-client-uat',
UnexpectedError: 'unexpected-error',
} as const;
Expand Down
23 changes: 20 additions & 3 deletions packages/backend/src/tokens/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ export async function authenticateRequest(
if (
authenticateContext.instanceType === 'development' &&
(error?.reason === TokenVerificationErrorReason.TokenExpired ||
error?.reason === TokenVerificationErrorReason.TokenNotActiveYet)
error?.reason === TokenVerificationErrorReason.TokenNotActiveYet ||
error?.reason === TokenVerificationErrorReason.TokenIatInTheFuture)
) {
error.tokenCarrier = 'cookie';
// This probably means we're dealing with clock skew
Expand Down Expand Up @@ -456,7 +457,7 @@ ${error.getFullMessage()}`,
}

if (decodeResult.payload.iat < authenticateContext.clientUat) {
return handleMaybeHandshakeStatus(authenticateContext, AuthErrorReason.SessionTokenOutdated, '');
return handleMaybeHandshakeStatus(authenticateContext, AuthErrorReason.SessionTokenIATBeforeClientUAT, '');
}

try {
Expand Down Expand Up @@ -502,12 +503,13 @@ ${error.getFullMessage()}`,
const reasonToHandshake = [
TokenVerificationErrorReason.TokenExpired,
TokenVerificationErrorReason.TokenNotActiveYet,
TokenVerificationErrorReason.TokenIatInTheFuture,
].includes(err.reason);

if (reasonToHandshake) {
return handleMaybeHandshakeStatus(
authenticateContext,
AuthErrorReason.SessionTokenOutdated,
convertTokenVerificationErrorReasonToAuthErrorReason(err.reason),
err.getFullMessage(),
undefined,
refreshError,
Expand All @@ -531,3 +533,18 @@ export const debugRequestState = (params: RequestState) => {
const { isSignedIn, proxyUrl, reason, message, publishableKey, isSatellite, domain } = params;
return { isSignedIn, proxyUrl, reason, message, publishableKey, isSatellite, domain };
};

const convertTokenVerificationErrorReasonToAuthErrorReason = (
reason: TokenVerificationErrorReason,
): AuthErrorReason => {
switch (reason) {
case TokenVerificationErrorReason.TokenExpired:
return AuthErrorReason.SessionTokenExpired;
case TokenVerificationErrorReason.TokenNotActiveYet:
return AuthErrorReason.SessionTokenNotActiveYet;
case TokenVerificationErrorReason.TokenIatInTheFuture:
return AuthErrorReason.SessionTokenIatInTheFuture;
default:
return AuthErrorReason.UnexpectedError;
}
};

0 comments on commit c59636a

Please sign in to comment.