@@ -5,9 +5,97 @@ import { describe, it, expect } from 'vitest'
55 *
66 * The resolveTrustedOrigins function in auth.ts dynamically adds IdP origins
77 * for SSO callback flows. These tests verify the URL parsing and filtering
8- * logic that would be applied to registered SSO provider issuers.
8+ * logic that would be applied to registered SSO provider issuers and
9+ * OIDC discovery documents.
910 */
1011
12+ describe ( 'SSO trusted origins — OIDC discovery endpoint extraction' , ( ) => {
13+ /**
14+ * Simulates the endpoint origin extraction from prefetchOidcEndpointOrigins.
15+ * This mirrors the logic in server/utils/auth.ts without network calls.
16+ */
17+ function extractEndpointOrigins ( discoveryDoc : Record < string , unknown > ) : string [ ] {
18+ const endpointKeys = [
19+ 'authorization_endpoint' ,
20+ 'token_endpoint' ,
21+ 'userinfo_endpoint' ,
22+ 'revocation_endpoint' ,
23+ 'introspection_endpoint' ,
24+ 'end_session_endpoint' ,
25+ 'jwks_uri' ,
26+ ]
27+ const origins = new Set < string > ( )
28+ for ( const key of endpointKeys ) {
29+ const value = discoveryDoc [ key ]
30+ if ( typeof value === 'string' ) {
31+ try { origins . add ( new URL ( value ) . origin ) } catch { }
32+ }
33+ }
34+ return [ ...origins ]
35+ }
36+
37+ it ( 'extracts origins from Google discovery doc (multi-domain)' , ( ) => {
38+ // Google uses different domains for issuer vs endpoints
39+ const googleDiscovery = {
40+ issuer : 'https://accounts.google.com' ,
41+ authorization_endpoint : 'https://accounts.google.com/o/oauth2/v2/auth' ,
42+ token_endpoint : 'https://oauth2.googleapis.com/token' ,
43+ userinfo_endpoint : 'https://openidconnect.googleapis.com/v1/userinfo' ,
44+ jwks_uri : 'https://www.googleapis.com/oauth2/v3/certs' ,
45+ revocation_endpoint : 'https://oauth2.googleapis.com/revoke' ,
46+ }
47+ const origins = extractEndpointOrigins ( googleDiscovery )
48+ expect ( origins ) . toContain ( 'https://accounts.google.com' )
49+ expect ( origins ) . toContain ( 'https://oauth2.googleapis.com' )
50+ expect ( origins ) . toContain ( 'https://openidconnect.googleapis.com' )
51+ expect ( origins ) . toContain ( 'https://www.googleapis.com' )
52+ } )
53+
54+ it ( 'extracts origins from Azure AD discovery doc' , ( ) => {
55+ const azureDiscovery = {
56+ authorization_endpoint : 'https://login.microsoftonline.com/tenant/oauth2/v2.0/authorize' ,
57+ token_endpoint : 'https://login.microsoftonline.com/tenant/oauth2/v2.0/token' ,
58+ userinfo_endpoint : 'https://graph.microsoft.com/oidc/userinfo' ,
59+ jwks_uri : 'https://login.microsoftonline.com/tenant/discovery/v2.0/keys' ,
60+ end_session_endpoint : 'https://login.microsoftonline.com/tenant/oauth2/v2.0/logout' ,
61+ }
62+ const origins = extractEndpointOrigins ( azureDiscovery )
63+ expect ( origins ) . toContain ( 'https://login.microsoftonline.com' )
64+ expect ( origins ) . toContain ( 'https://graph.microsoft.com' )
65+ } )
66+
67+ it ( 'deduplicates origins from same-domain endpoints' , ( ) => {
68+ const keycloakDiscovery = {
69+ authorization_endpoint : 'https://kc.corp.com/realms/prod/protocol/openid-connect/auth' ,
70+ token_endpoint : 'https://kc.corp.com/realms/prod/protocol/openid-connect/token' ,
71+ userinfo_endpoint : 'https://kc.corp.com/realms/prod/protocol/openid-connect/userinfo' ,
72+ jwks_uri : 'https://kc.corp.com/realms/prod/protocol/openid-connect/certs' ,
73+ }
74+ const origins = extractEndpointOrigins ( keycloakDiscovery )
75+ expect ( origins ) . toEqual ( [ 'https://kc.corp.com' ] )
76+ } )
77+
78+ it ( 'skips non-string and missing endpoint values' , ( ) => {
79+ const partialDoc = {
80+ authorization_endpoint : 'https://auth.example.com/authorize' ,
81+ token_endpoint : null ,
82+ userinfo_endpoint : 12345 ,
83+ jwks_uri : undefined ,
84+ }
85+ const origins = extractEndpointOrigins ( partialDoc )
86+ expect ( origins ) . toEqual ( [ 'https://auth.example.com' ] )
87+ } )
88+
89+ it ( 'skips malformed URLs gracefully' , ( ) => {
90+ const badDoc = {
91+ authorization_endpoint : 'not-a-url' ,
92+ token_endpoint : 'https://valid.example.com/token' ,
93+ }
94+ const origins = extractEndpointOrigins ( badDoc )
95+ expect ( origins ) . toEqual ( [ 'https://valid.example.com' ] )
96+ } )
97+ } )
98+
1199describe ( 'SSO trusted origins — issuer URL parsing' , ( ) => {
12100 /**
13101 * Simulates the issuer → origin extraction from resolveTrustedOrigins.
0 commit comments