diff --git a/src/shared/auth.test.ts b/src/shared/auth.test.ts index 41f9dc1a9..71877f341 100644 --- a/src/shared/auth.test.ts +++ b/src/shared/auth.test.ts @@ -1,5 +1,11 @@ import { describe, it, expect } from '@jest/globals'; -import { SafeUrlSchema, OAuthMetadataSchema, OpenIdProviderMetadataSchema, OAuthClientMetadataSchema } from './auth.js'; +import { + SafeUrlSchema, + OAuthMetadataSchema, + OpenIdProviderMetadataSchema, + OAuthClientMetadataSchema, + OptionalSafeUrlSchema +} from './auth.js'; describe('SafeUrlSchema', () => { it('accepts valid HTTPS URLs', () => { @@ -26,6 +32,12 @@ describe('SafeUrlSchema', () => { }); }); +describe('OptionalSafeUrlSchema', () => { + it('accepts empty string and transforms it to undefined', () => { + expect(OptionalSafeUrlSchema.parse('')).toBe(undefined); + }); +}); + describe('OAuthMetadataSchema', () => { it('validates complete OAuth metadata', () => { const metadata = { diff --git a/src/shared/auth.ts b/src/shared/auth.ts index 0e079646b..c5ddbda16 100644 --- a/src/shared/auth.ts +++ b/src/shared/auth.ts @@ -151,6 +151,11 @@ export const OAuthErrorResponseSchema = z.object({ error_uri: z.string().optional() }); +/** + * Optional version of SafeUrlSchema that allows empty string for retrocompatibility on tos_uri and logo_uri + */ +export const OptionalSafeUrlSchema = SafeUrlSchema.optional().or(z.literal('').transform(() => undefined)); + /** * RFC 7591 OAuth 2.0 Dynamic Client Registration metadata */ @@ -162,10 +167,10 @@ export const OAuthClientMetadataSchema = z response_types: z.array(z.string()).optional(), client_name: z.string().optional(), client_uri: SafeUrlSchema.optional(), - logo_uri: SafeUrlSchema.optional(), + logo_uri: OptionalSafeUrlSchema, scope: z.string().optional(), contacts: z.array(z.string()).optional(), - tos_uri: SafeUrlSchema.optional(), + tos_uri: OptionalSafeUrlSchema, policy_uri: z.string().optional(), jwks_uri: SafeUrlSchema.optional(), jwks: z.any().optional(),