Skip to content

Commit b4612f5

Browse files
rolandzwagapanva
andauthored
feat: optional headers options for createRemoteJWKSet (#397)
Co-authored-by: Filip Skokan <[email protected]>
1 parent c58c80a commit b4612f5

File tree

4 files changed

+34
-5
lines changed

4 files changed

+34
-5
lines changed

src/jwks/remote.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ export interface RemoteJWKSetOptions {
4242
* runtime.
4343
*/
4444
agent?: any
45+
46+
/**
47+
* Optional headers to be sent with the HTTP request.
48+
*/
49+
headers?: Record<string, string>
4550
}
4651

4752
class RemoteJWKSet extends LocalJWKSet {
@@ -57,7 +62,7 @@ class RemoteJWKSet extends LocalJWKSet {
5762

5863
private _pendingFetch?: Promise<unknown>
5964

60-
private _options: Pick<RemoteJWKSetOptions, 'agent'>
65+
private _options: Pick<RemoteJWKSetOptions, 'agent' | 'headers'>
6166

6267
constructor(url: unknown, options?: RemoteJWKSetOptions) {
6368
super({ keys: [] })
@@ -68,7 +73,7 @@ class RemoteJWKSet extends LocalJWKSet {
6873
throw new TypeError('url must be an instance of URL')
6974
}
7075
this._url = new URL(url.href)
71-
this._options = { agent: options?.agent }
76+
this._options = { agent: options?.agent, headers: options?.headers }
7277
this._timeoutDuration =
7378
typeof options?.timeoutDuration === 'number' ? options?.timeoutDuration : 5000
7479
this._cooldownDuration =

src/runtime/browser/fetch_jwks.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import type { FetchFunction } from '../interfaces.d'
22
import { JOSEError, JWKSTimeout } from '../../util/errors.js'
33

4-
const fetchJwks: FetchFunction = async (url: URL, timeout: number) => {
4+
type AcceptedRequestOptions = Pick<RequestInit, 'headers'>
5+
6+
const fetchJwks: FetchFunction = async (
7+
url: URL,
8+
timeout: number,
9+
options: AcceptedRequestOptions,
10+
) => {
511
let controller!: AbortController
612
let id!: ReturnType<typeof setTimeout>
713
let timedOut = false
@@ -16,6 +22,7 @@ const fetchJwks: FetchFunction = async (url: URL, timeout: number) => {
1622
const response = await fetch(url.href, {
1723
signal: controller ? controller.signal : undefined,
1824
redirect: 'manual',
25+
headers: options.headers,
1926
}).catch((err) => {
2027
if (timedOut) throw new JWKSTimeout()
2128
throw err

src/runtime/node/fetch_jwks.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { FetchFunction } from '../interfaces.d'
88
import { JOSEError, JWKSTimeout } from '../../util/errors.js'
99
import { concat, decoder } from '../../lib/buffer_utils.js'
1010

11-
type AcceptedRequestOptions = Pick<RequestOptions, 'agent'>
11+
type AcceptedRequestOptions = Pick<RequestOptions, 'agent' | 'headers'>
1212

1313
const fetchJwks: FetchFunction = async (
1414
url: URL,
@@ -27,10 +27,11 @@ const fetchJwks: FetchFunction = async (
2727
throw new TypeError('Unsupported URL protocol.')
2828
}
2929

30-
const { agent } = options
30+
const { agent, headers } = options
3131
const req = get(url.href, {
3232
agent,
3333
timeout,
34+
headers,
3435
})
3536

3637
const [response] = <[IncomingMessage]>(

test/jwks/remote.test.mjs

+16
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,22 @@ skipOnUndiciTestSerial('throws on invalid JWKSet', async (t) => {
362362
})
363363
})
364364

365+
skipOnUndiciTestSerial('can have headers configured', async (t) => {
366+
const scope = nock('https://as.example.com', {
367+
reqheaders: {
368+
'x-custom': 'foo',
369+
},
370+
})
371+
.get('/jwks')
372+
.once()
373+
.reply(200, 'null')
374+
375+
const url = new URL('https://as.example.com/jwks')
376+
const JWKS = createRemoteJWKSet(url, { headers: { 'x-custom': 'foo' } })
377+
await JWKS().catch(() => {})
378+
t.true(scope.isDone())
379+
})
380+
365381
skipOnUndiciTest('handles ENOTFOUND', async (t) => {
366382
nock.enableNetConnect()
367383
const url = new URL('https://op.example.com/jwks')

0 commit comments

Comments
 (0)