@@ -15,7 +15,7 @@ import {
1515 isHttpsUrl
1616} from './auth.js' ;
1717import { InvalidClientMetadataError , ServerError } from '../server/auth/errors.js' ;
18- import { AuthorizationServerMetadata } from '../shared/auth.js' ;
18+ import { AuthorizationServerMetadata , OAuthTokens } from '../shared/auth.js' ;
1919import { expect , vi , type Mock } from 'vitest' ;
2020
2121// Mock pkce-challenge
@@ -1093,7 +1093,7 @@ describe('OAuth Authorization', () => {
10931093 } ) ;
10941094
10951095 describe ( 'exchangeAuthorization' , ( ) => {
1096- const validTokens = {
1096+ const validTokens : OAuthTokens = {
10971097 access_token : 'access123' ,
10981098 token_type : 'Bearer' ,
10991099 expires_in : 3600 ,
@@ -1154,6 +1154,44 @@ describe('OAuth Authorization', () => {
11541154 expect ( body . get ( 'resource' ) ) . toBe ( 'https://api.example.com/mcp-server' ) ;
11551155 } ) ;
11561156
1157+ it ( 'allows for string "expires_in" values' , async ( ) => {
1158+ mockFetch . mockResolvedValueOnce ( {
1159+ ok : true ,
1160+ status : 200 ,
1161+ json : async ( ) => ( { ...validTokens , expires_in : '3600' } )
1162+ } ) ;
1163+
1164+ const tokens = await exchangeAuthorization ( 'https://auth.example.com' , {
1165+ clientInformation : validClientInfo ,
1166+ authorizationCode : 'code123' ,
1167+ codeVerifier : 'verifier123' ,
1168+ redirectUri : 'http://localhost:3000/callback' ,
1169+ resource : new URL ( 'https://api.example.com/mcp-server' )
1170+ } ) ;
1171+
1172+ expect ( tokens ) . toEqual ( validTokens ) ;
1173+ expect ( mockFetch ) . toHaveBeenCalledWith (
1174+ expect . objectContaining ( {
1175+ href : 'https://auth.example.com/token'
1176+ } ) ,
1177+ expect . objectContaining ( {
1178+ method : 'POST'
1179+ } )
1180+ ) ;
1181+
1182+ const options = mockFetch . mock . calls [ 0 ] [ 1 ] ;
1183+ expect ( options . headers ) . toBeInstanceOf ( Headers ) ;
1184+ expect ( options . headers . get ( 'Content-Type' ) ) . toBe ( 'application/x-www-form-urlencoded' ) ;
1185+
1186+ const body = options . body as URLSearchParams ;
1187+ expect ( body . get ( 'grant_type' ) ) . toBe ( 'authorization_code' ) ;
1188+ expect ( body . get ( 'code' ) ) . toBe ( 'code123' ) ;
1189+ expect ( body . get ( 'code_verifier' ) ) . toBe ( 'verifier123' ) ;
1190+ expect ( body . get ( 'client_id' ) ) . toBe ( 'client123' ) ;
1191+ expect ( body . get ( 'client_secret' ) ) . toBe ( 'secret123' ) ;
1192+ expect ( body . get ( 'redirect_uri' ) ) . toBe ( 'http://localhost:3000/callback' ) ;
1193+ expect ( body . get ( 'resource' ) ) . toBe ( 'https://api.example.com/mcp-server' ) ;
1194+ } ) ;
11571195 it ( 'exchanges code for tokens with auth' , async ( ) => {
11581196 mockFetch . mockResolvedValueOnce ( {
11591197 ok : true ,
0 commit comments