feat: optional headers options for createRemoteJWKSet (#397)

Co-authored-by: Filip Skokan <panva.ip@gmail.com>
This commit is contained in:
Roland Zwaga 2022-04-26 11:49:43 +02:00 committed by GitHub
parent c58c80ae98
commit b4612f5d25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 34 additions and 5 deletions

View file

@ -42,6 +42,11 @@ export interface RemoteJWKSetOptions {
* runtime.
*/
agent?: any
/**
* Optional headers to be sent with the HTTP request.
*/
headers?: Record<string, string>
}
class RemoteJWKSet extends LocalJWKSet {
@ -57,7 +62,7 @@ class RemoteJWKSet extends LocalJWKSet {
private _pendingFetch?: Promise<unknown>
private _options: Pick<RemoteJWKSetOptions, 'agent'>
private _options: Pick<RemoteJWKSetOptions, 'agent' | 'headers'>
constructor(url: unknown, options?: RemoteJWKSetOptions) {
super({ keys: [] })
@ -68,7 +73,7 @@ class RemoteJWKSet extends LocalJWKSet {
throw new TypeError('url must be an instance of URL')
}
this._url = new URL(url.href)
this._options = { agent: options?.agent }
this._options = { agent: options?.agent, headers: options?.headers }
this._timeoutDuration =
typeof options?.timeoutDuration === 'number' ? options?.timeoutDuration : 5000
this._cooldownDuration =

View file

@ -1,7 +1,13 @@
import type { FetchFunction } from '../interfaces.d'
import { JOSEError, JWKSTimeout } from '../../util/errors.js'
const fetchJwks: FetchFunction = async (url: URL, timeout: number) => {
type AcceptedRequestOptions = Pick<RequestInit, 'headers'>
const fetchJwks: FetchFunction = async (
url: URL,
timeout: number,
options: AcceptedRequestOptions,
) => {
let controller!: AbortController
let id!: ReturnType<typeof setTimeout>
let timedOut = false
@ -16,6 +22,7 @@ const fetchJwks: FetchFunction = async (url: URL, timeout: number) => {
const response = await fetch(url.href, {
signal: controller ? controller.signal : undefined,
redirect: 'manual',
headers: options.headers,
}).catch((err) => {
if (timedOut) throw new JWKSTimeout()
throw err

View file

@ -8,7 +8,7 @@ import type { FetchFunction } from '../interfaces.d'
import { JOSEError, JWKSTimeout } from '../../util/errors.js'
import { concat, decoder } from '../../lib/buffer_utils.js'
type AcceptedRequestOptions = Pick<RequestOptions, 'agent'>
type AcceptedRequestOptions = Pick<RequestOptions, 'agent' | 'headers'>
const fetchJwks: FetchFunction = async (
url: URL,
@ -27,10 +27,11 @@ const fetchJwks: FetchFunction = async (
throw new TypeError('Unsupported URL protocol.')
}
const { agent } = options
const { agent, headers } = options
const req = get(url.href, {
agent,
timeout,
headers,
})
const [response] = <[IncomingMessage]>(

View file

@ -362,6 +362,22 @@ skipOnUndiciTestSerial('throws on invalid JWKSet', async (t) => {
})
})
skipOnUndiciTestSerial('can have headers configured', async (t) => {
const scope = nock('https://as.example.com', {
reqheaders: {
'x-custom': 'foo',
},
})
.get('/jwks')
.once()
.reply(200, 'null')
const url = new URL('https://as.example.com/jwks')
const JWKS = createRemoteJWKSet(url, { headers: { 'x-custom': 'foo' } })
await JWKS().catch(() => {})
t.true(scope.isDone())
})
skipOnUndiciTest('handles ENOTFOUND', async (t) => {
nock.enableNetConnect()
const url = new URL('https://op.example.com/jwks')