Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/app-check/token-verifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
Expand Down
7 changes: 4 additions & 3 deletions src/utils/jwt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,15 @@ 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.');
}

this.client = jwks({
jwksUri: jwksUrl,
cache: false, // disable jwks-rsa LRU cache as the keys are always cached for 6 hours.
requestAgent: httpAgent,
});
}

Expand Down Expand Up @@ -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<void> {
Expand Down
20 changes: 20 additions & 0 deletions test/unit/app-check/token-verifier.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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[] = [];
Expand Down
11 changes: 11 additions & 0 deletions test/unit/utils/jwt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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', () => {
Expand Down