diff --git a/src/app-check/token-verifier.ts b/src/app-check/token-verifier.ts index 6c6503f05d..cde4878a42 100644 --- a/src/app-check/token-verifier.ts +++ b/src/app-check/token-verifier.ts @@ -37,7 +37,7 @@ export class AppCheckTokenVerifier { private readonly signatureVerifier: SignatureVerifier; constructor(private readonly app: App) { - this.signatureVerifier = PublicKeySignatureVerifier.withJwksUrl(JWKS_URL); + this.signatureVerifier = PublicKeySignatureVerifier.withJwksUrl(JWKS_URL, app.options.httpAgent); } /** diff --git a/src/utils/jwt.ts b/src/utils/jwt.ts index 5d8f88344f..1b1fea6af9 100644 --- a/src/utils/jwt.ts +++ b/src/utils/jwt.ts @@ -53,7 +53,7 @@ export class JwksFetcher implements KeyFetcher { private publicKeysExpireAt = 0; private client: jwks.JwksClient; - constructor(jwksUrl: string) { + constructor(jwksUrl: string, httpAgent?: Agent) { if (!validator.isURL(jwksUrl)) { throw new Error('The provided JWKS URL is not a valid URL.'); } @@ -61,6 +61,7 @@ export class JwksFetcher implements KeyFetcher { this.client = jwks({ jwksUri: jwksUrl, cache: false, // disable jwks-rsa LRU cache as the keys are always cached for 6 hours. + requestAgent: httpAgent, }); } @@ -190,8 +191,8 @@ export class PublicKeySignatureVerifier implements SignatureVerifier { return new PublicKeySignatureVerifier(new UrlKeyFetcher(clientCertUrl, httpAgent)); } - public static withJwksUrl(jwksUrl: string): PublicKeySignatureVerifier { - return new PublicKeySignatureVerifier(new JwksFetcher(jwksUrl)); + public static withJwksUrl(jwksUrl: string, httpAgent?: Agent): PublicKeySignatureVerifier { + return new PublicKeySignatureVerifier(new JwksFetcher(jwksUrl, httpAgent)); } public verify(token: string): Promise { diff --git a/test/unit/app-check/token-verifier.spec.ts b/test/unit/app-check/token-verifier.spec.ts index c6cf897c05..ecc664783b 100644 --- a/test/unit/app-check/token-verifier.spec.ts +++ b/test/unit/app-check/token-verifier.spec.ts @@ -22,6 +22,7 @@ import * as chai from 'chai'; import * as sinon from 'sinon'; import * as mocks from '../../resources/mocks'; import * as nock from 'nock'; +import { Agent } from 'http'; import { AppCheckTokenVerifier } from '../../../src/app-check/token-verifier'; import { JwtError, JwtErrorCode, PublicKeySignatureVerifier } from '../../../src/utils/jwt'; @@ -55,6 +56,25 @@ describe('AppCheckTokenVerifier', () => { } }); + describe('Constructor', () => { + it('AppOptions.httpAgent should be passed to PublicKeySignatureVerifier.withJwksUrl', () => { + const mockAppWithAgent = mocks.appWithOptions({ + httpAgent: new Agent() + }); + const agentForApp = mockAppWithAgent.options.httpAgent; + const verifierSpy = sinon.spy(PublicKeySignatureVerifier, 'withJwksUrl'); + + expect(verifierSpy.args).to.be.empty; + + new AppCheckTokenVerifier( + mockAppWithAgent + ); + + expect(verifierSpy.args[0][1]).to.equal(agentForApp); + verifierSpy.restore(); + }); + }); + describe('verifyJWT()', () => { let mockedRequests: nock.Scope[] = []; let stubs: sinon.SinonStub[] = []; diff --git a/test/unit/utils/jwt.spec.ts b/test/unit/utils/jwt.spec.ts index 18cff06ff7..8dd49dfaf6 100644 --- a/test/unit/utils/jwt.spec.ts +++ b/test/unit/utils/jwt.spec.ts @@ -17,6 +17,7 @@ 'use strict'; // Use untyped import syntax for Node built-ins +import http = require('http'); import https = require('https'); import * as _ from 'lodash'; @@ -380,6 +381,16 @@ describe('PublicKeySignatureVerifier', () => { expect(verifier).to.be.an.instanceOf(PublicKeySignatureVerifier); expect((verifier as any).keyFetcher).to.be.an.instanceOf(JwksFetcher); }); + + it('should return a PublicKeySignatureVerifier instance with a JwksFetcher when a ' + + 'valid jwks url and httpAgent is provided', () => { + const mockHttpAgent = sinon.createStubInstance(http.Agent); + const verifier = PublicKeySignatureVerifier.withJwksUrl('https://www.example.com/publicKeys', mockHttpAgent); + expect(verifier).to.be.an.instanceOf(PublicKeySignatureVerifier); + expect((verifier as any).keyFetcher).to.be.an.instanceOf(JwksFetcher); + expect((verifier as any).keyFetcher.client.options.requestAgent).to.be.an.instanceOf(http.Agent); + expect((verifier as any).keyFetcher.client.options.requestAgent).to.eq(mockHttpAgent); + }); }); describe('verify', () => {