@@ -727,7 +727,7 @@ describe("OAuth Authorization", () => {
727
727
} ) ;
728
728
} ) ;
729
729
730
- it ( "falls back to OpenID Connect discovery when OAuth discovery fails" , async ( ) => {
730
+ it ( "falls back to OpenID Connect discovery when OAuth discovery fails (no path component) " , async ( ) => {
731
731
// First call (OAuth) returns 404
732
732
mockFetch . mockResolvedValueOnce ( {
733
733
ok : false ,
@@ -781,43 +781,64 @@ describe("OAuth Authorization", () => {
781
781
status : 404 ,
782
782
} ) ;
783
783
784
- // Second call (OIDC with path insertion) returns 404
784
+ // Second call should be OAuth root fallback
785
+ mockFetch . mockResolvedValueOnce ( {
786
+ ok : true ,
787
+ status : 200 ,
788
+ json : async ( ) => validOAuthMetadata ,
789
+ } ) ;
790
+
791
+ const metadata = await discoverAuthorizationServerMetadata (
792
+ "https://mcp.example.com" ,
793
+ "https://auth.example.com/tenant1"
794
+ ) ;
795
+
796
+ expect ( metadata ) . toEqual ( validOAuthMetadata ) ;
797
+ const calls = mockFetch . mock . calls ;
798
+ expect ( calls . length ) . toBe ( 2 ) ;
799
+
800
+ // Should try OAuth with path first
801
+ expect ( calls [ 0 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server/tenant1" ) ;
802
+
803
+ // Should fall back to OAuth root discovery
804
+ expect ( calls [ 1 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server" ) ;
805
+ } ) ;
806
+
807
+ it ( "should try OIDC discovery after OAuth attempts fail" , async ( ) => {
808
+ // First call (OAuth with path) returns 404
785
809
mockFetch . mockResolvedValueOnce ( {
786
810
ok : false ,
787
811
status : 404 ,
788
812
} ) ;
789
813
790
- // Third call (OIDC with path appending ) returns 404
814
+ // Second call (OAuth root ) returns 404
791
815
mockFetch . mockResolvedValueOnce ( {
792
816
ok : false ,
793
817
status : 404 ,
794
818
} ) ;
795
819
796
- // Fourth call should be OAuth root fallback
820
+ // Third call (OIDC with path insertion) succeeds
797
821
mockFetch . mockResolvedValueOnce ( {
798
822
ok : true ,
799
823
status : 200 ,
800
- json : async ( ) => validOAuthMetadata ,
824
+ json : async ( ) => validOpenIdMetadata ,
801
825
} ) ;
802
826
803
827
const metadata = await discoverAuthorizationServerMetadata (
804
828
"https://mcp.example.com" ,
805
829
"https://auth.example.com/tenant1"
806
830
) ;
807
831
808
- expect ( metadata ) . toEqual ( validOAuthMetadata ) ;
832
+ expect ( metadata ) . toEqual ( validOpenIdMetadata ) ;
809
833
const calls = mockFetch . mock . calls ;
810
- expect ( calls . length ) . toBe ( 4 ) ;
811
-
812
- // Should try OAuth with path first
834
+ expect ( calls . length ) . toBe ( 3 ) ;
835
+
836
+ // Should try OAuth attempts first
813
837
expect ( calls [ 0 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server/tenant1" ) ;
814
-
815
- // Should try OIDC discoveries next
816
- expect ( calls [ 1 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/openid-configuration/tenant1" ) ;
817
- expect ( calls [ 2 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/tenant1/.well-known/openid-configuration" ) ;
818
-
819
- // Should finally fall back to OAuth root discovery
820
- expect ( calls [ 3 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server" ) ;
838
+ expect ( calls [ 1 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server" ) ;
839
+
840
+ // Then try OIDC discovery
841
+ expect ( calls [ 2 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/openid-configuration/tenant1" ) ;
821
842
} ) ;
822
843
823
844
it ( "handles authorization server URL with path in OAuth discovery" , async ( ) => {
@@ -840,7 +861,13 @@ describe("OAuth Authorization", () => {
840
861
} ) ;
841
862
842
863
it ( "handles authorization server URL with path in OpenID Connect discovery" , async ( ) => {
843
- // OAuth discovery fails
864
+ // OAuth discovery with path fails
865
+ mockFetch . mockResolvedValueOnce ( {
866
+ ok : false ,
867
+ status : 404 ,
868
+ } ) ;
869
+
870
+ // OAuth discovery at root fails
844
871
mockFetch . mockResolvedValueOnce ( {
845
872
ok : false ,
846
873
status : 404 ,
@@ -860,17 +887,26 @@ describe("OAuth Authorization", () => {
860
887
861
888
expect ( metadata ) . toEqual ( validOpenIdMetadata ) ;
862
889
const calls = mockFetch . mock . calls ;
863
- expect ( calls . length ) . toBe ( 2 ) ;
890
+ expect ( calls . length ) . toBe ( 3 ) ;
864
891
865
892
// First call should be OAuth with path
866
893
expect ( calls [ 0 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server/tenant1" ) ;
867
894
868
- // Second call should be OpenID Connect with path insertion
869
- expect ( calls [ 1 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/openid-configuration/tenant1" ) ;
895
+ // Second call should be OAuth at root
896
+ expect ( calls [ 1 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server" ) ;
897
+
898
+ // Third call should be OpenID Connect with path insertion
899
+ expect ( calls [ 2 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/openid-configuration/tenant1" ) ;
870
900
} ) ;
871
901
872
902
it ( "tries multiple OpenID Connect endpoints when path is present" , async ( ) => {
873
- // OAuth discovery fails
903
+ // OAuth discovery with path fails
904
+ mockFetch . mockResolvedValueOnce ( {
905
+ ok : false ,
906
+ status : 404 ,
907
+ } ) ;
908
+
909
+ // OAuth discovery at root fails
874
910
mockFetch . mockResolvedValueOnce ( {
875
911
ok : false ,
876
912
status : 404 ,
@@ -896,16 +932,19 @@ describe("OAuth Authorization", () => {
896
932
897
933
expect ( metadata ) . toEqual ( validOpenIdMetadata ) ;
898
934
const calls = mockFetch . mock . calls ;
899
- expect ( calls . length ) . toBe ( 3 ) ;
935
+ expect ( calls . length ) . toBe ( 4 ) ;
900
936
901
937
// First call should be OAuth with path
902
938
expect ( calls [ 0 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server/tenant1" ) ;
903
939
904
- // Second call should be OpenID Connect with path insertion
905
- expect ( calls [ 1 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/openid-configuration/tenant1" ) ;
940
+ // Second call should be OAuth at root
941
+ expect ( calls [ 1 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server" ) ;
942
+
943
+ // Third call should be OpenID Connect with path insertion
944
+ expect ( calls [ 2 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/openid-configuration/tenant1" ) ;
906
945
907
- // Third call should be OpenID Connect with path prepending
908
- expect ( calls [ 2 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/tenant1/.well-known/openid-configuration" ) ;
946
+ // Fourth call should be OpenID Connect with path prepending
947
+ expect ( calls [ 3 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/tenant1/.well-known/openid-configuration" ) ;
909
948
} ) ;
910
949
911
950
it ( "throws error when OIDC provider does not support S256 PKCE" , async ( ) => {
0 commit comments