import {z} from 'zod' export type GetApiWellKnownOauthAuthorizationServerOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const authorizationServerMetadata = z.object({issuer: z.string(), authorization_endpoint: z.string().optional(), token_endpoint: z.string().optional(), jwks_uri: z.string().optional(), registration_endpoint: z.string().optional(), scopes_supported: z.array(z.string()).optional(), response_types_supported: z.array(z.enum(["code", "token", "id_token", "code token", "code id_token", "token id_token", "code token id_token"])), response_modes_supported: z.array(z.enum(["query", "fragment", "form_post"])).optional(), grant_types_supported: z.array(z.string()).optional(), token_endpoint_auth_methods_supported: z.array(z.enum(["client_secret_basic", "client_secret_post", "client_secret_jwt", "private_key_jwt", "none"])).optional(), token_endpoint_auth_signing_alg_values_supported: z.array(z.string()).optional(), service_documentation: z.string().optional(), ui_locales_supported: z.array(z.string()).optional(), op_policy_uri: z.string().optional(), op_tos_uri: z.string().optional(), revocation_endpoint: z.string().optional(), revocation_endpoint_auth_methods_supported: z.array(z.enum(["client_secret_basic", "client_secret_post", "client_secret_jwt", "private_key_jwt", "none"])).optional(), revocation_endpoint_auth_signing_alg_values_supported: z.array(z.string()).optional(), introspection_endpoint: z.string().optional(), introspection_endpoint_auth_methods_supported: z.array(z.enum(["client_secret_basic", "client_secret_post", "client_secret_jwt", "private_key_jwt", "none"])).optional(), introspection_endpoint_auth_signing_alg_values_supported: z.array(z.string()).optional(), code_challenge_methods_supported: z.array(z.enum(["plain", "S256"])).optional(), pushed_authorization_request_endpoint: z.string().optional(), require_pushed_authorization_requests: z.boolean().optional(), dpop_signing_alg_values_supported: z.array(z.string()).optional(), userinfo_endpoint: z.string().optional(), check_session_iframe: z.string().optional(), end_session_endpoint: z.string().optional(), acr_values_supported: z.array(z.string()).optional(), subject_types_supported: z.array(z.enum(["public", "pairwise"])).optional(), id_token_signing_alg_values_supported: z.array(z.string()).optional(), id_token_encryption_alg_values_supported: z.array(z.string()).optional(), id_token_encryption_enc_values_supported: z.array(z.string()).optional(), request_object_signing_alg_values_supported: z.array(z.string()).optional(), request_object_encryption_alg_values_supported: z.array(z.string()).optional(), request_object_encryption_enc_values_supported: z.array(z.string()).optional(), display_values_supported: z.array(z.enum(["page", "popup", "touch", "wap"])).optional(), claim_types_supported: z.array(z.enum(["normal", "aggregated", "distributed"])).optional(), claims_supported: z.array(z.string()).optional(), claims_parameter_supported: z.boolean().optional(), request_parameter_supported: z.boolean().optional(), request_uri_parameter_supported: z.boolean().optional(), require_request_uri_registration: z.boolean().optional(), frontchannel_logout_supported: z.boolean().optional(), frontchannel_logout_session_supported: z.boolean().optional(), backchannel_logout_supported: z.boolean().optional(), backchannel_logout_session_supported: z.boolean().optional(), "pre-authorized_grant_anonymous_access_supported": z.boolean().optional(), authorization_challenge_endpoint: z.string().optional(), credential_endpoint: z.string().optional(), deferred_credential_endpoint: z.string().optional(), nonce_endpoint: z.string().optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Get authorization server metadata, if the integrated authorization server is enabled. Conforms to OAuth2 * * GET /.well-known/oauth-authorization-server */ export const getApiWellKnownOauthAuthorizationServer = async (options?: GetApiWellKnownOauthAuthorizationServerOptions) => { const {baseUrl = "https://agent.findynet.demo.sphereon.com/oid4vci", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") const url = `${baseUrl.replace(/\/+$/, '')}/.well-known/oauth-authorization-server${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(authorizationServerMetadata, await res.json()) };