Skip to content

Commit

Permalink
feat: Added callback for fetch
Browse files Browse the repository at this point in the history
Signed-off-by: Tom Lanser <tom@devv.nl>
  • Loading branch information
Tommylans committed Dec 4, 2024
1 parent d86835e commit 42ca85e
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
import { verifyJwtSignature } from '../jsonWeb/verifyJsonWebToken'
import { type VerifyCallback, addPaths, fetcher } from '../utils'
import { type FetchCallback, type VerifyCallback, addPaths, fetcher } from '../utils'
import { validate } from '../utils/validate'
import { entityConfigurationJwtSchema } from './entityConfigurationJwt'

export type FetchEntityConfigurationOptions = {
entityId: string
verifyJwtCallback: VerifyCallback
fetchCallback?: FetchCallback
}

/**
*
* {@link https://openid.net/specs/openid-federation-1_0.html#section-9.1 | Federation Entity Request}
*
*/
export const fetchEntityConfiguration = async ({ entityId, verifyJwtCallback }: FetchEntityConfigurationOptions) => {
export const fetchEntityConfiguration = async ({
entityId,
verifyJwtCallback,
fetchCallback,
}: FetchEntityConfigurationOptions) => {
// Create the entity URL
const federationUrl = addPaths(entityId, '.well-known', 'openid-federation')

// Fetch the JWT entity configuration
const entityConfigurationJwt = await fetcher.get({
url: federationUrl,
requiredContentType: 'application/entity-statement+jwt',
fetchCallback,
})

// Parse the JWT into its claims
Expand Down
7 changes: 5 additions & 2 deletions packages/core/src/entityStatement/fetchEntityStatement.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { type EntityConfigurationClaims, fetchEntityConfiguration } from '../entityConfiguration'
import { verifyJwtSignature } from '../jsonWeb/verifyJsonWebToken'
import { type VerifyCallback, fetcher } from '../utils'
import { type FetchCallback, type VerifyCallback, fetcher } from '../utils'
import { validate } from '../utils/validate'
import { entityStatementJwtSchema } from './entityStatementJwt'

export type FetchEntityStatementOptions = {
iss: string
sub: string
verifyJwtCallback: VerifyCallback
fetchCallback?: FetchCallback
/**
*
* The issuers entity configuration
Expand All @@ -32,9 +33,10 @@ export const fetchEntityStatement = async ({
iss,
endpoint,
issEntityConfiguration,
fetchCallback,
}: FetchEntityStatementOptions) => {
const issEntityConfigurationClaims =
issEntityConfiguration ?? (await fetchEntityConfiguration({ entityId: iss, verifyJwtCallback }))
issEntityConfiguration ?? (await fetchEntityConfiguration({ entityId: iss, verifyJwtCallback, fetchCallback }))

const fetchEndpoint = endpoint ?? issEntityConfigurationClaims.metadata?.federation_entity?.federation_fetch_endpoint

Expand All @@ -46,6 +48,7 @@ export const fetchEntityStatement = async ({
url: fetchEndpoint,
searchParams: { iss, sub },
requiredContentType: 'application/entity-statement+jwt',
fetchCallback,
})

// Parse the JWT into its claims and header claims
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/metadata/entity/openIdProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { createEntity } from './utils'
*/
export const openIdProviderEntityMetadata = createEntity({
identifier: 'openid_provider',
passThroughUnknownProperties: true,
additionalValidation: {
client_registration_types_supported: z.array(z.union([z.literal('automatic'), z.literal('explicit')])),
federation_registration_endpoint: z.string().url().optional(),
Expand Down
11 changes: 8 additions & 3 deletions packages/core/src/utils/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { z } from 'zod'
import type { FetchCallback } from './types'
import { addSearchParams } from './url'
import { validate } from './validate'

Expand All @@ -7,16 +8,18 @@ const get = async <T extends z.ZodSchema>({
searchParams,
responseValidationSchema,
requiredContentType,
fetchCallback = global.fetch,
}: {
url: string
searchParams?: Record<string, string>
responseValidationSchema?: T
requiredContentType?: string
fetchCallback?: FetchCallback
}): Promise<typeof responseValidationSchema extends T ? z.output<T> : string> => {
// Fetch the url with the search params
const urlSearchParams = new URLSearchParams(searchParams)
const urlWithSearchParams = addSearchParams(url, urlSearchParams)
const response = await global.fetch(urlWithSearchParams, {
const response = await fetchCallback(urlWithSearchParams, {
method: 'GET',
})

Expand Down Expand Up @@ -53,12 +56,14 @@ const post = async ({
url,
body,
responseValidationSchema,
fetchCallback = global.fetch,
}: {
url: string
body?: Record<string, unknown>
responseValidationSchema?: z.ZodSchema
fetchCallback?: FetchCallback
}) => {
const response = await global.fetch(url, {
const response = await fetchCallback(url, {
method: 'POST',
body: body ? JSON.stringify(body) : undefined,
headers: { 'Content-Type': 'application/json' },
Expand All @@ -81,4 +86,4 @@ const post = async ({
export const fetcher = {
get,
post,
}
} as const
2 changes: 2 additions & 0 deletions packages/core/src/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ export type VerifyCallback = (options: {
signature: Uint8Array
jwk: JsonWebKey
}) => Promise<boolean>

export type FetchCallback = typeof fetch

0 comments on commit 42ca85e

Please sign in to comment.