Skip to content

Commit c65de5f

Browse files
committed
Further tweaks.
1 parent a2abc0a commit c65de5f

File tree

4 files changed

+41
-22
lines changed

4 files changed

+41
-22
lines changed

packages/service-core/src/auth/KeyStore.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ export class KeyStore<Collector extends KeyCollector = KeyCollector> {
5050
clockTolerance: 60,
5151
// More specific algorithm checking is done when selecting the key to use.
5252
algorithms: SUPPORTED_ALGORITHMS,
53-
requiredClaims: ['aud', 'sub', 'iat', 'exp']
53+
// 'aud' presence is checked below, so we can add more details to the error message.
54+
requiredClaims: ['sub', 'iat', 'exp']
5455
});
5556

5657
let audiences = options.defaultAudiences;
@@ -61,8 +62,12 @@ export class KeyStore<Collector extends KeyCollector = KeyCollector> {
6162

6263
const tokenPayload = result.payload;
6364

64-
let aud = tokenPayload.aud!;
65-
if (!Array.isArray(aud)) {
65+
let aud = tokenPayload.aud;
66+
if (aud == null) {
67+
throw new AuthorizationError(ErrorCode.PSYNC_S2105, `JWT payload is missing a required claim "aud"`, {
68+
configurationDetails: `Current configuration allows these audience values: ${JSON.stringify(audiences)}`
69+
});
70+
} else if (!Array.isArray(aud)) {
6671
aud = [aud];
6772
}
6873
if (
@@ -125,6 +130,7 @@ export class KeyStore<Collector extends KeyCollector = KeyCollector> {
125130
if (key.kid == kid) {
126131
if (!key.matchesAlgorithm(header.alg)) {
127132
throw new AuthorizationError(ErrorCode.PSYNC_S2101, `Unexpected token algorithm ${header.alg}`, {
133+
configurationDetails: `Key kid: ${key.source.kid}, alg: ${key.source.alg}, kty: ${key.source.kty}`
128134
// Token details automatically populated elsewhere
129135
});
130136
}

packages/service-core/src/auth/RemoteJWKSCollector.ts

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,30 +47,43 @@ export class RemoteJWKSCollector implements KeyCollector {
4747
this.agent = this.resolveAgent();
4848
}
4949

50-
async getKeys(): Promise<KeyResult> {
50+
private async getJwksData(): Promise<any> {
5151
const abortController = new AbortController();
5252
const timeout = setTimeout(() => {
5353
abortController.abort();
5454
}, 30_000);
5555

56-
const res = await fetch(this.url, {
57-
method: 'GET',
58-
headers: {
59-
Accept: 'application/json'
60-
},
61-
signal: abortController.signal,
62-
agent: this.agent
63-
});
64-
65-
if (!res.ok) {
66-
throw new AuthorizationError(ErrorCode.PSYNC_S2204, `JWKS request failed with ${res.statusText}`, {
67-
configurationDetails: `JWKS URL: ${this.url}`
56+
try {
57+
const res = await fetch(this.url, {
58+
method: 'GET',
59+
headers: {
60+
Accept: 'application/json'
61+
},
62+
signal: abortController.signal,
63+
agent: this.agent
6864
});
69-
}
7065

71-
const data = (await res.json()) as any;
66+
if (!res.ok) {
67+
throw new AuthorizationError(ErrorCode.PSYNC_S2204, `JWKS request failed with ${res.statusText}`, {
68+
configurationDetails: `JWKS URL: ${this.url}`
69+
});
70+
}
7271

73-
clearTimeout(timeout);
72+
return (await res.json()) as any;
73+
} catch (e) {
74+
throw new AuthorizationError(ErrorCode.PSYNC_S2204, `JWKS request failed`, {
75+
configurationDetails: `JWKS URL: ${this.url}`,
76+
// This covers most cases of FetchError
77+
// `cause: e` could lose the error message
78+
cause: { message: e.message, code: e.code }
79+
});
80+
} finally {
81+
clearTimeout(timeout);
82+
}
83+
}
84+
85+
async getKeys(): Promise<KeyResult> {
86+
const data = await this.getJwksData();
7487

7588
// https://github.com/panva/jose/blob/358e864a0cccf1e0f9928a959f91f18f3f06a7de/src/jwks/local.ts#L36
7689
if (
@@ -81,7 +94,7 @@ export class RemoteJWKSCollector implements KeyCollector {
8194
return {
8295
keys: [],
8396
errors: [
84-
new AuthorizationError(ErrorCode.PSYNC_S2204, `JWKS request failed with ${res.statusText}`, {
97+
new AuthorizationError(ErrorCode.PSYNC_S2204, `Invalid JWKS response`, {
8598
configurationDetails: `JWKS URL: ${this.url}. Response:\n${JSON.stringify(data, null, 2)}`
8699
})
87100
]

packages/service-core/test/src/auth.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ describe('JWT Auth', () => {
308308
reject_ip_ranges: ['local']
309309
}
310310
});
311-
await expect(invalid.getKeys()).rejects.toThrow('IPs in this range are not supported');
311+
await expect(invalid.getKeys()).rejects.toThrow('[PSYNC_S2204] JWKS request failed');
312312

313313
// IPs throw an error immediately
314314
expect(

packages/service-errors/src/errors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ export class AuthorizationError extends ServiceError {
181181
status: 401,
182182
description
183183
});
184-
this.cause = this.cause;
184+
this.cause = options?.cause;
185185
this.tokenDetails = options?.tokenDetails;
186186
this.configurationDetails = options?.configurationDetails;
187187
}

0 commit comments

Comments
 (0)