Skip to content

Commit

Permalink
fix(createRemoteJWKSet): ensure a default user-agent header is present
Browse files Browse the repository at this point in the history
resolves #600
  • Loading branch information
panva committed Nov 2, 2023
1 parent 651979a commit 887dd3c
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 4 deletions.
2 changes: 1 addition & 1 deletion .versionrc.json
@@ -1,7 +1,7 @@
{
"commit-all": true,
"scripts": {
"prerelease": "npm run-script build-all",
"prerelease": "node ./tools/prebump.js && npm run-script build-all",
"postbump": "node ./tools/postbump.js",
"postchangelog": "sed -i '' -e 's/### \\[/## [/g' CHANGELOG.md"
},
Expand Down
23 changes: 22 additions & 1 deletion src/jwks/remote.ts
Expand Up @@ -16,6 +16,17 @@ function isCloudflareWorkers() {
)
}

// An explicit user-agent in browser environment is a trigger for CORS preflight requests which
// are not needed for our request, so we're omitting setting a default user-agent in browser
// environments.
let USER_AGENT: string
// @ts-ignore
if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
const NAME = 'jose'
const VERSION = 'v5.0.1'
USER_AGENT = `${NAME}/${VERSION}`
}

/** Options for the remote JSON Web Key Set. */
export interface RemoteJWKSetOptions {
/**
Expand Down Expand Up @@ -46,7 +57,11 @@ export interface RemoteJWKSetOptions {
*/
agent?: any

/** Optional headers to be sent with the HTTP request. */
/**
* Headers to be sent with the HTTP request. Default is that `User-Agent: jose/v${version}` header
* is added unless the runtime is a browser in which adding an explicit headers fetch
* configuration would cause an unnecessary CORS preflight request.
*/
headers?: Record<string, string>
}

Expand Down Expand Up @@ -122,6 +137,12 @@ class RemoteJWKSet<KeyLikeType extends KeyLike = KeyLike> extends LocalJWKSet<Ke
this._pendingFetch = undefined
}

const headers = new Headers(this._options.headers)
if (USER_AGENT && !headers.has('User-Agent')) {
headers.set('User-Agent', USER_AGENT)
this._options.headers = Object.fromEntries(headers.entries())
}

this._pendingFetch ||= fetchJwks(this._url, this._timeoutDuration, this._options)
.then((json) => {
if (!isJWKSLike(json)) {
Expand Down
5 changes: 4 additions & 1 deletion test/jwks/remote.test.mjs
Expand Up @@ -119,7 +119,10 @@ test.serial('RemoteJWKSet', async (t) => {
],
}

nock('https://as.example.com').get('/jwks').reply(200, jwks)
nock('https://as.example.com')
.matchHeader('user-agent', /jose\/v\d+\.\d+\.\d+/)
.get('/jwks')
.reply(200, jwks)
const url = new URL('https://as.example.com/jwks')
const JWKS = createRemoteJWKSet(url)
// Signed JWT
Expand Down
13 changes: 13 additions & 0 deletions tools/prebump.js
@@ -0,0 +1,13 @@
const { execSync } = require('child_process')
const { readFileSync, writeFileSync } = require('fs')

const dryRun = execSync('standard-version --dry-run', { encoding: 'utf-8' })

;/tagging release v(\d+\.\d+\.\d+)/gm.test(dryRun)

const version = RegExp.$1
const tagName = `v${version}`

const path = './src/jwks/remote.ts'
writeFileSync(path, readFileSync(path, { encoding: 'utf-8' }).replace(/v(\d+\.\d+\.\d+)/g, tagName))
execSync(`git add ${path}`, { stdio: 'inherit' })
2 changes: 1 addition & 1 deletion tsconfig/base.json
@@ -1,7 +1,7 @@
{
"files": ["../src/index.ts"],
"compilerOptions": {
"lib": ["ES2020", "DOM"],
"lib": ["ES2020", "DOM", "DOM.iterable"],
"types": [],
"strict": true,
"forceConsistentCasingInFileNames": true,
Expand Down

0 comments on commit 887dd3c

Please sign in to comment.