@@ -10,7 +10,7 @@ import {
1010 auth ,
1111 type OAuthClientProvider ,
1212} from "./auth.js" ;
13- import { OAuthMetadata } from 'src /shared/auth.js' ;
13+ import { OAuthMetadata } from '.. /shared/auth.js' ;
1414
1515// Mock fetch globally
1616const mockFetch = jest . fn ( ) ;
@@ -1615,6 +1615,11 @@ describe("OAuth Authorization", () => {
16151615 token_endpoint_auth_methods_supported : [ "none" ] ,
16161616 } ;
16171617
1618+ const metadataWithAllBuiltinMethods = {
1619+ ...metadataWithBasicOnly ,
1620+ token_endpoint_auth_methods_supported : [ "client_secret_basic" , "client_secret_post" , "none" ] ,
1621+ } ;
1622+
16181623 it ( "uses HTTP Basic authentication when client_secret_basic is supported" , async ( ) => {
16191624 mockFetch . mockResolvedValueOnce ( {
16201625 ok : true ,
@@ -1639,8 +1644,8 @@ describe("OAuth Authorization", () => {
16391644 expect ( authHeader ) . toBe ( expected ) ;
16401645
16411646 const body = request . body as URLSearchParams ;
1642- expect ( body . get ( "client_id" ) ) . toBeNull ( ) ; // should not be in body
1643- expect ( body . get ( "client_secret" ) ) . toBeNull ( ) ; // should not be in body
1647+ expect ( body . get ( "client_id" ) ) . toBeNull ( ) ;
1648+ expect ( body . get ( "client_secret" ) ) . toBeNull ( ) ;
16441649 } ) ;
16451650
16461651 it ( "includes credentials in request body when client_secret_post is supported" , async ( ) => {
@@ -1669,6 +1674,35 @@ describe("OAuth Authorization", () => {
16691674 expect ( body . get ( "client_secret" ) ) . toBe ( "secret123" ) ;
16701675 } ) ;
16711676
1677+ it ( "it picks client_secret_basic when all builtin methods are supported" , async ( ) => {
1678+ mockFetch . mockResolvedValueOnce ( {
1679+ ok : true ,
1680+ status : 200 ,
1681+ json : async ( ) => validTokens ,
1682+ } ) ;
1683+
1684+ const tokens = await exchangeAuthorization ( "https://auth.example.com" , {
1685+ metadata : metadataWithAllBuiltinMethods ,
1686+ clientInformation : validClientInfo ,
1687+ authorizationCode : "code123" ,
1688+ redirectUri : "http://localhost:3000/callback" ,
1689+ codeVerifier : "verifier123" ,
1690+ } ) ;
1691+
1692+ expect ( tokens ) . toEqual ( validTokens ) ;
1693+ const request = mockFetch . mock . calls [ 0 ] [ 1 ] ;
1694+
1695+ // Check Authorization header - should use Basic auth as it's the most secure
1696+ const authHeader = request . headers . get ( "Authorization" ) ;
1697+ const expected = "Basic " + btoa ( "client123:secret123" ) ;
1698+ expect ( authHeader ) . toBe ( expected ) ;
1699+
1700+ // Credentials should not be in body when using Basic auth
1701+ const body = request . body as URLSearchParams ;
1702+ expect ( body . get ( "client_id" ) ) . toBeNull ( ) ;
1703+ expect ( body . get ( "client_secret" ) ) . toBeNull ( ) ;
1704+ } ) ;
1705+
16721706 it ( "uses public client authentication when none method is specified" , async ( ) => {
16731707 mockFetch . mockResolvedValueOnce ( {
16741708 ok : true ,
0 commit comments