@@ -2,8 +2,18 @@ import { useEffect, useRef } from "react";
2
2
import { InspectorOAuthClientProvider } from "../lib/auth" ;
3
3
import { SESSION_KEYS } from "../lib/constants" ;
4
4
import { auth } from "@modelcontextprotocol/sdk/client/auth.js" ;
5
+ import { useToast } from "@/hooks/use-toast.ts" ;
6
+ import {
7
+ generateOAuthErrorDescription ,
8
+ parseOAuthCallbackParams ,
9
+ } from "@/utils/oauthUtils.ts" ;
5
10
6
- const OAuthCallback = ( ) => {
11
+ interface OAuthCallbackProps {
12
+ onConnect : ( serverUrl : string ) => void ;
13
+ }
14
+
15
+ const OAuthCallback = ( { onConnect } : OAuthCallbackProps ) => {
16
+ const { toast } = useToast ( ) ;
7
17
const hasProcessedRef = useRef ( false ) ;
8
18
9
19
useEffect ( ( ) => {
@@ -14,40 +24,56 @@ const OAuthCallback = () => {
14
24
}
15
25
hasProcessedRef . current = true ;
16
26
17
- const params = new URLSearchParams ( window . location . search ) ;
18
- const code = params . get ( "code" ) ;
19
- const serverUrl = sessionStorage . getItem ( SESSION_KEYS . SERVER_URL ) ;
27
+ const notifyError = ( description : string ) =>
28
+ void toast ( {
29
+ title : "OAuth Authorization Error" ,
30
+ description,
31
+ variant : "destructive" ,
32
+ } ) ;
20
33
21
- if ( ! code || ! serverUrl ) {
22
- console . error ( "Missing code or server URL" ) ;
23
- window . location . href = "/" ;
24
- return ;
34
+ const params = parseOAuthCallbackParams ( window . location . search ) ;
35
+ if ( ! params . successful ) {
36
+ return notifyError ( generateOAuthErrorDescription ( params ) ) ;
37
+ }
38
+
39
+ const serverUrl = sessionStorage . getItem ( SESSION_KEYS . SERVER_URL ) ;
40
+ if ( ! serverUrl ) {
41
+ return notifyError ( "Missing Server URL" ) ;
25
42
}
26
43
44
+ let result ;
27
45
try {
28
46
// Create an auth provider with the current server URL
29
47
const serverAuthProvider = new InspectorOAuthClientProvider ( serverUrl ) ;
30
48
31
- const result = await auth ( serverAuthProvider , {
49
+ result = await auth ( serverAuthProvider , {
32
50
serverUrl,
33
- authorizationCode : code ,
51
+ authorizationCode : params . code ,
34
52
} ) ;
35
- if ( result !== "AUTHORIZED" ) {
36
- throw new Error (
37
- `Expected to be authorized after providing auth code, got: ${ result } ` ,
38
- ) ;
39
- }
40
-
41
- // Redirect back to the main app with server URL to trigger auto-connect
42
- window . location . href = `/?serverUrl=${ encodeURIComponent ( serverUrl ) } ` ;
43
53
} catch ( error ) {
44
54
console . error ( "OAuth callback error:" , error ) ;
45
- window . location . href = "/" ;
55
+ return notifyError ( `Unexpected error occurred: ${ error } ` ) ;
46
56
}
57
+
58
+ if ( result !== "AUTHORIZED" ) {
59
+ return notifyError (
60
+ `Expected to be authorized after providing auth code, got: ${ result } ` ,
61
+ ) ;
62
+ }
63
+
64
+ // Finally, trigger auto-connect
65
+ toast ( {
66
+ title : "Success" ,
67
+ description : "Successfully authenticated with OAuth" ,
68
+ variant : "default" ,
69
+ } ) ;
70
+ onConnect ( serverUrl ) ;
47
71
} ;
48
72
49
- void handleCallback ( ) ;
50
- } , [ ] ) ;
73
+ handleCallback ( ) . finally ( ( ) => {
74
+ window . history . replaceState ( { } , document . title , "/" ) ;
75
+ } ) ;
76
+ } , [ toast , onConnect ] ) ;
51
77
52
78
return (
53
79
< div className = "flex items-center justify-center h-screen" >
0 commit comments