From 3bf0a2a3f94df260aafa17234652dd3aaddfb59e Mon Sep 17 00:00:00 2001 From: adamjmcgrath Date: Tue, 12 Jan 2021 12:43:23 +0000 Subject: [PATCH] AggregateError#message from `Issuer.discover` includes stack trace --- src/auth0-session/client.ts | 18 +++++++++++++++++- tests/auth0-session/client.test.ts | 14 +++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/auth0-session/client.ts b/src/auth0-session/client.ts index 753c531a7..7658503d6 100644 --- a/src/auth0-session/client.ts +++ b/src/auth0-session/client.ts @@ -19,6 +19,17 @@ function sortSpaceDelimitedString(str: string): string { return str.split(' ').sort().join(' '); } +// Issuer.discover throws an `AggregateError` in some cases, this error includes the stack trace in the +// message which causes the stack to be exposed when reporting the error in production. Am using the non standard +// `_errors` property to identify the polyfilled `AggregateError` +// See https://github.com/sindresorhus/aggregate-error/issues/4#issuecomment-488356468 +function normalizeAggregateError(e: Error | (Error & { _errors: Error[] })): Error { + if ('_errors' in e) { + return e._errors[0]; + } + return e; +} + export default function get(config: Config, { name, version }: Telemetry): ClientFactory { let client: Client | null = null; @@ -54,7 +65,12 @@ export default function get(config: Config, { name, version }: Telemetry): Clien }; applyHttpOptionsCustom(Issuer); - const issuer = await Issuer.discover(config.issuerBaseURL); + let issuer: Issuer; + try { + issuer = await Issuer.discover(config.issuerBaseURL); + } catch (e) { + throw normalizeAggregateError(e); + } applyHttpOptionsCustom(issuer); const issuerTokenAlgs = Array.isArray(issuer.id_token_signing_alg_values_supported) diff --git a/tests/auth0-session/client.test.ts b/tests/auth0-session/client.test.ts index ab803e61f..de4ea4896 100644 --- a/tests/auth0-session/client.test.ts +++ b/tests/auth0-session/client.test.ts @@ -1,5 +1,5 @@ import nock from 'nock'; -import { Client } from 'openid-client'; +import { Client, Issuer } from 'openid-client'; import { getConfig, clientFactory, ConfigParameters } from '../../src/auth0-session'; import { jwks } from './fixtures/cert'; import pkg from '../../package.json'; @@ -132,4 +132,16 @@ describe('clientFactory', function () { }) ).resolves.not.toThrow(); }); + + it('should not disclose stack trace in AggregateError message when discovery fails', async () => { + nock.cleanAll(); + nock('https://op.example.com').get('/.well-known/oauth-authorization-server').reply(500); + nock('https://op.example.com').get('/.well-known/openid-configuration').reply(500); + await expect(getClient()).rejects.toThrowError(new Error('expected 200 OK, got: 500 Internal Server Error')); + }); + + it('should not normalize individual errors from discovery', async () => { + jest.spyOn(Issuer, 'discover').mockRejectedValue(new Error('foo')); + await expect(getClient()).rejects.toThrowError(new Error('foo')); + }); });