@@ -20,6 +20,7 @@ import {
20
20
import { OAuthTokensSchema } from "@modelcontextprotocol/sdk/shared/auth.js" ;
21
21
import { SESSION_KEYS , getServerSpecificKey } from "./lib/constants" ;
22
22
import { AuthDebuggerState , EMPTY_DEBUGGER_STATE } from "./lib/auth-types" ;
23
+ import { OAuthStateMachine } from "./lib/oauth-state-machine" ;
23
24
import { cacheToolOutputSchemas } from "./utils/schemaUtils" ;
24
25
import React , {
25
26
Suspense ,
@@ -231,7 +232,7 @@ const App = () => {
231
232
232
233
// Update OAuth debug state during debug callback
233
234
const onOAuthDebugConnect = useCallback (
234
- ( {
235
+ async ( {
235
236
authorizationCode,
236
237
errorMsg,
237
238
restoredState,
@@ -241,29 +242,64 @@ const App = () => {
241
242
restoredState ?: AuthDebuggerState ;
242
243
} ) => {
243
244
setIsAuthDebuggerVisible ( true ) ;
244
-
245
- if ( restoredState ) {
246
- // Restore the previous auth state
245
+
246
+ if ( errorMsg ) {
247
247
updateAuthState ( {
248
- ...restoredState ,
249
- // Update with the new authorization code if provided
250
- authorizationCode : authorizationCode || restoredState . authorizationCode ,
251
- oauthStep : authorizationCode ? "token_request" : restoredState . oauthStep ,
252
- latestError : errorMsg ? new Error ( errorMsg ) : restoredState . latestError ,
248
+ latestError : new Error ( errorMsg ) ,
253
249
} ) ;
254
- } else {
255
- // Fallback to the original behavior if no state was restored
256
- if ( authorizationCode ) {
257
- updateAuthState ( {
258
- authorizationCode,
259
- oauthStep : "token_request" ,
250
+ return ;
251
+ }
252
+
253
+ if ( restoredState && authorizationCode ) {
254
+ // Restore the previous auth state and continue the OAuth flow
255
+ let currentState : AuthDebuggerState = {
256
+ ...restoredState ,
257
+ authorizationCode,
258
+ oauthStep : "token_request" ,
259
+ isInitiatingAuth : true ,
260
+ statusMessage : null ,
261
+ latestError : null ,
262
+ } ;
263
+
264
+ try {
265
+ // Create a new state machine instance to continue the flow
266
+ const stateMachine = new OAuthStateMachine ( sseUrl , ( updates ) => {
267
+ currentState = { ...currentState , ...updates } ;
260
268
} ) ;
261
- }
262
- if ( errorMsg ) {
269
+
270
+ // Continue stepping through the OAuth flow from where we left off
271
+ while ( currentState . oauthStep !== "complete" && currentState . oauthStep !== "authorization_code" ) {
272
+ await stateMachine . executeStep ( currentState ) ;
273
+ }
274
+
275
+ if ( currentState . oauthStep === "complete" ) {
276
+ // After the flow completes or reaches a user-input step, update the app state
277
+ updateAuthState ( {
278
+ ...currentState ,
279
+ statusMessage : {
280
+ type : "success" ,
281
+ message : "Authentication completed successfully" ,
282
+ } ,
283
+ isInitiatingAuth : false ,
284
+ } ) ;
285
+ }
286
+ } catch ( error ) {
287
+ console . error ( "OAuth continuation error:" , error ) ;
263
288
updateAuthState ( {
264
- latestError : new Error ( errorMsg ) ,
289
+ latestError : error instanceof Error ? error : new Error ( String ( error ) ) ,
290
+ statusMessage : {
291
+ type : "error" ,
292
+ message : `Failed to complete OAuth flow: ${ error instanceof Error ? error . message : String ( error ) } ` ,
293
+ } ,
294
+ isInitiatingAuth : false ,
265
295
} ) ;
266
296
}
297
+ } else if ( authorizationCode ) {
298
+ // Fallback to the original behavior if no state was restored
299
+ updateAuthState ( {
300
+ authorizationCode,
301
+ oauthStep : "token_request" ,
302
+ } ) ;
267
303
}
268
304
} ,
269
305
[ ] ,
0 commit comments