Skip to content

Commit

Permalink
feat(backend): Add available kid to jwk-remote-missing error (#1816)
Browse files Browse the repository at this point in the history
  • Loading branch information
LekoArts authored Oct 3, 2023
1 parent 65903d5 commit fed24f1
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/cool-planes-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/backend': patch
---

Improve the `jwk-remote-missing` error by adding the available JWK IDs to the error message. This way you can understand why the entry was not found and compare the available ones with other keys.
12 changes: 10 additions & 2 deletions packages/backend/src/tokens/keys.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,11 @@ export default (QUnit: QUnit) => {
});

test('throws an error when JWKS can not be fetched from Backend or Frontend API and cache updated less than 5 minutes ago', async assert => {
const kid = 'ins_whatever';
try {
await loadClerkJWKFromRemote({
apiKey: 'deadbeef',
kid: 'ins_whatever',
kid,
});
assert.false(true);
} catch (err) {
Expand All @@ -201,6 +202,9 @@ export default (QUnit: QUnit) => {
reason: 'jwk-remote-missing',
action: 'Contact support@clerk.com',
});
assert.propContains(err, {
message: `Unable to find a signing key in JWKS that matches the kid='${kid}' of the provided session token. Please make sure that the __session cookie or the HTTP authorization header contain a Clerk-generated session JWT. The following kid are available: ${mockRsaJwkKid}, local`,
});
} else {
// This should never be reached. If it does, the suite should fail
assert.false(true);
Expand All @@ -210,11 +214,12 @@ export default (QUnit: QUnit) => {

test('throws an error when no JWK matches the provided kid', async assert => {
fakeFetch.onCall(0).returns(jsonOk(mockJwks));
const kid = 'ins_whatever';

try {
await loadClerkJWKFromRemote({
apiKey: 'deadbeef',
kid: 'ins_whatever',
kid,
});
assert.false(true);
} catch (err) {
Expand All @@ -223,6 +228,9 @@ export default (QUnit: QUnit) => {
reason: 'jwk-remote-missing',
action: 'Contact support@clerk.com',
});
assert.propContains(err, {
message: `Unable to find a signing key in JWKS that matches the kid='${kid}' of the provided session token. Please make sure that the __session cookie or the HTTP authorization header contain a Clerk-generated session JWT. The following kid are available: ${mockRsaJwkKid}, local`,
});
} else {
// This should never be reached. If it does, the suite should fail
assert.false(true);
Expand Down
13 changes: 11 additions & 2 deletions packages/backend/src/tokens/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ function getFromCache(kid: string) {
return cache[kid];
}

function getCacheValues() {
return Object.values(cache);
}

function setInCache(
jwk: JsonWebKeyWithKid,
jwksCacheTtlInMs: number = 1000 * 60 * 60, // 1 hour
Expand Down Expand Up @@ -144,7 +148,7 @@ export async function loadClerkJWKFromRemote({
});
}

const { keys }: { keys: JsonWebKeyWithKid[] } = await callWithRetry(fetcher);
const { keys } = await callWithRetry<{ keys: JsonWebKeyWithKid[] }>(fetcher);

if (!keys || !keys.length) {
throw new TokenVerificationError({
Expand All @@ -160,9 +164,14 @@ export async function loadClerkJWKFromRemote({
const jwk = getFromCache(kid);

if (!jwk) {
const cacheValues = getCacheValues();
const jwkKeys = cacheValues.map(jwk => jwk.kid).join(', ');

throw new TokenVerificationError({
action: TokenVerificationErrorAction.ContactSupport,
message: `Unable to find a signing key in JWKS that matches the kid='${kid}' of the provided session token. Please make sure that the __session cookie or the HTTP authorization header contain a Clerk-generated session JWT.`,
message: `Unable to find a signing key in JWKS that matches the kid='${kid}' of the provided session token. Please make sure that the __session cookie or the HTTP authorization header contain a Clerk-generated session JWT.${
jwkKeys ? ` The following kid are available: ${jwkKeys}` : ''
}`,
reason: TokenVerificationErrorReason.RemoteJWKMissing,
});
}
Expand Down

0 comments on commit fed24f1

Please sign in to comment.