Skip to content

Commit 9bf578f

Browse files
authored
fix: loosen the allowed content type for JWK Set to include application/json (#79)
Signed-off-by: Timo Glastra <timo@animo.id>
1 parent 1a64f80 commit 9bf578f

4 files changed

Lines changed: 17 additions & 8 deletions

File tree

.changeset/sad-jokes-cry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@openid4vc/oauth2": patch
3+
---
4+
5+
fix: loosen the allowed content type for JWK Set to include application/json

packages/oauth2/src/metadata/fetch-jwks-uri.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { type JwkSet, zJwkSet } from '../common/jwk/z-jwk'
1515
export async function fetchJwks(jwksUrl: string, fetch?: Fetch): Promise<JwkSet> {
1616
const fetcher = createZodFetcher(fetch)
1717

18-
const { result, response } = await fetcher(zJwkSet, ContentType.JwkSet, jwksUrl)
18+
const { result, response } = await fetcher(zJwkSet, [ContentType.JwkSet, ContentType.Json], jwksUrl)
1919
if (!response.ok) {
2020
throw new InvalidFetchResponseError(
2121
`Fetching JWKs from jwks_uri '${jwksUrl}' resulted in an unsuccessfull response with status code '${response.status}'.`,

packages/utils/src/content-type.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ export enum ContentType {
1010
}
1111

1212
export function isContentType(contentType: ContentType, value: string) {
13-
return value.toLowerCase().trim().split(';')[0] === contentType
13+
return value.toLowerCase().includes(contentType)
1414
}
1515

16-
export function isResponseContentType(contentType: ContentType, response: FetchResponse) {
16+
export function isResponseContentType(contentType: ContentType | ContentType[], response: FetchResponse) {
17+
const contentTypeArray = Array.isArray(contentType) ? contentType : [contentType]
18+
1719
const header = response.headers.get('Content-Type')
1820
if (!header) return false
19-
return isContentType(contentType, header)
21+
return contentTypeArray.some((contentTypeEntry) => isContentType(contentTypeEntry, header))
2022
}

packages/utils/src/fetcher.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { type Fetch, URLSearchParams } from './globals'
1010
*/
1111
export type ZodFetcher = <Schema extends z.ZodTypeAny>(
1212
schema: Schema,
13-
expectedContentType: ContentType,
13+
expectedContentType: ContentType | ContentType[],
1414
...args: Parameters<Fetch>
1515
) => Promise<{ response: Awaited<ReturnType<Fetch>>; result?: z.SafeParseReturnType<Schema, z.infer<Schema>> }>
1616

@@ -62,15 +62,17 @@ export function createZodFetcher(fetcher?: Fetch): ZodFetcher {
6262
return async (schema, expectedContentType, ...args) => {
6363
const response = await createFetcher(fetcher)(...args)
6464

65-
if (response.ok && !isResponseContentType(expectedContentType, response)) {
65+
const expectedContentTypeArray = Array.isArray(expectedContentType) ? expectedContentType : [expectedContentType]
66+
67+
if (response.ok && !isResponseContentType(expectedContentTypeArray, response)) {
6668
throw new InvalidFetchResponseError(
67-
`Expected response to match content type '${expectedContentType}', but received '${response.headers.get('Content-Type')}'`,
69+
`Expected response to match content type ${expectedContentTypeArray.join(' | ')}, but received '${response.headers.get('Content-Type')}'`,
6870
await response.clone().text(),
6971
response
7072
)
7173
}
7274

73-
if (expectedContentType === ContentType.OAuthAuthorizationRequestJwt) {
75+
if (expectedContentTypeArray.includes(ContentType.OAuthAuthorizationRequestJwt)) {
7476
return {
7577
response,
7678
result: response.ok ? schema.safeParse(await response.text()) : undefined,

0 commit comments

Comments
 (0)