|
1 | | -import { useCallback, useMemo } from "react"; |
| 1 | +import { useCallback, useMemo, useEffect } from "react"; |
2 | 2 | import { Button } from "@/components/ui/button"; |
3 | 3 | import { DebugInspectorOAuthClientProvider } from "../lib/auth"; |
4 | 4 | import { AlertCircle } from "lucide-react"; |
5 | | -import { AuthDebuggerState } from "../lib/auth-types"; |
| 5 | +import { AuthDebuggerState, EMPTY_DEBUGGER_STATE } from "../lib/auth-types"; |
6 | 6 | import { OAuthFlowProgress } from "./OAuthFlowProgress"; |
7 | 7 | import { OAuthStateMachine } from "../lib/oauth-state-machine"; |
| 8 | +import { SESSION_KEYS } from "../lib/constants"; |
8 | 9 |
|
9 | 10 | export interface AuthDebuggerProps { |
10 | 11 | serverUrl: string; |
@@ -59,6 +60,27 @@ const AuthDebugger = ({ |
59 | 60 | authState, |
60 | 61 | updateAuthState, |
61 | 62 | }: AuthDebuggerProps) => { |
| 63 | + // Check for existing tokens on mount |
| 64 | + useEffect(() => { |
| 65 | + if (serverUrl && !authState.oauthTokens) { |
| 66 | + const checkTokens = async () => { |
| 67 | + try { |
| 68 | + const provider = new DebugInspectorOAuthClientProvider(serverUrl); |
| 69 | + const existingTokens = await provider.tokens(); |
| 70 | + if (existingTokens) { |
| 71 | + updateAuthState({ |
| 72 | + oauthTokens: existingTokens, |
| 73 | + oauthStep: "complete", |
| 74 | + }); |
| 75 | + } |
| 76 | + } catch (error) { |
| 77 | + console.error("Failed to load existing OAuth tokens:", error); |
| 78 | + } |
| 79 | + }; |
| 80 | + checkTokens(); |
| 81 | + } |
| 82 | + }, [serverUrl, updateAuthState, authState.oauthTokens]); |
| 83 | + |
62 | 84 | const startOAuthFlow = useCallback(() => { |
63 | 85 | if (!serverUrl) { |
64 | 86 | updateAuthState({ |
@@ -141,6 +163,11 @@ const AuthDebugger = ({ |
141 | 163 | currentState.oauthStep === "authorization_code" && |
142 | 164 | currentState.authorizationUrl |
143 | 165 | ) { |
| 166 | + // Store the current auth state before redirecting |
| 167 | + sessionStorage.setItem( |
| 168 | + SESSION_KEYS.AUTH_DEBUGGER_STATE, |
| 169 | + JSON.stringify(currentState), |
| 170 | + ); |
144 | 171 | // Open the authorization URL automatically |
145 | 172 | window.location.href = currentState.authorizationUrl; |
146 | 173 | break; |
@@ -178,13 +205,7 @@ const AuthDebugger = ({ |
178 | 205 | ); |
179 | 206 | serverAuthProvider.clear(); |
180 | 207 | updateAuthState({ |
181 | | - oauthTokens: null, |
182 | | - oauthStep: "metadata_discovery", |
183 | | - latestError: null, |
184 | | - oauthClientInfo: null, |
185 | | - authorizationCode: "", |
186 | | - validationError: null, |
187 | | - oauthMetadata: null, |
| 208 | + ...EMPTY_DEBUGGER_STATE, |
188 | 209 | statusMessage: { |
189 | 210 | type: "success", |
190 | 211 | message: "OAuth tokens cleared successfully", |
@@ -224,52 +245,48 @@ const AuthDebugger = ({ |
224 | 245 | <StatusMessage message={authState.statusMessage} /> |
225 | 246 | )} |
226 | 247 |
|
227 | | - {authState.loading ? ( |
228 | | - <p>Loading authentication status...</p> |
229 | | - ) : ( |
230 | | - <div className="space-y-4"> |
231 | | - {authState.oauthTokens && ( |
232 | | - <div className="space-y-2"> |
233 | | - <p className="text-sm font-medium">Access Token:</p> |
234 | | - <div className="bg-muted p-2 rounded-md text-xs overflow-x-auto"> |
235 | | - {authState.oauthTokens.access_token.substring(0, 25)}... |
236 | | - </div> |
| 248 | + <div className="space-y-4"> |
| 249 | + {authState.oauthTokens && ( |
| 250 | + <div className="space-y-2"> |
| 251 | + <p className="text-sm font-medium">Access Token:</p> |
| 252 | + <div className="bg-muted p-2 rounded-md text-xs overflow-x-auto"> |
| 253 | + {authState.oauthTokens.access_token.substring(0, 25)}... |
237 | 254 | </div> |
238 | | - )} |
239 | | - |
240 | | - <div className="flex gap-4"> |
241 | | - <Button |
242 | | - variant="outline" |
243 | | - onClick={startOAuthFlow} |
244 | | - disabled={authState.isInitiatingAuth} |
245 | | - > |
246 | | - {authState.oauthTokens |
247 | | - ? "Guided Token Refresh" |
248 | | - : "Guided OAuth Flow"} |
249 | | - </Button> |
| 255 | + </div> |
| 256 | + )} |
250 | 257 |
|
251 | | - <Button |
252 | | - onClick={handleQuickOAuth} |
253 | | - disabled={authState.isInitiatingAuth} |
254 | | - > |
255 | | - {authState.isInitiatingAuth |
256 | | - ? "Initiating..." |
257 | | - : authState.oauthTokens |
258 | | - ? "Quick Refresh" |
259 | | - : "Quick OAuth Flow"} |
260 | | - </Button> |
| 258 | + <div className="flex gap-4"> |
| 259 | + <Button |
| 260 | + variant="outline" |
| 261 | + onClick={startOAuthFlow} |
| 262 | + disabled={authState.isInitiatingAuth} |
| 263 | + > |
| 264 | + {authState.oauthTokens |
| 265 | + ? "Guided Token Refresh" |
| 266 | + : "Guided OAuth Flow"} |
| 267 | + </Button> |
261 | 268 |
|
262 | | - <Button variant="outline" onClick={handleClearOAuth}> |
263 | | - Clear OAuth State |
264 | | - </Button> |
265 | | - </div> |
| 269 | + <Button |
| 270 | + onClick={handleQuickOAuth} |
| 271 | + disabled={authState.isInitiatingAuth} |
| 272 | + > |
| 273 | + {authState.isInitiatingAuth |
| 274 | + ? "Initiating..." |
| 275 | + : authState.oauthTokens |
| 276 | + ? "Quick Refresh" |
| 277 | + : "Quick OAuth Flow"} |
| 278 | + </Button> |
266 | 279 |
|
267 | | - <p className="text-xs text-muted-foreground"> |
268 | | - Choose "Guided" for step-by-step instructions or "Quick" for |
269 | | - the standard automatic flow. |
270 | | - </p> |
| 280 | + <Button variant="outline" onClick={handleClearOAuth}> |
| 281 | + Clear OAuth State |
| 282 | + </Button> |
271 | 283 | </div> |
272 | | - )} |
| 284 | + |
| 285 | + <p className="text-xs text-muted-foreground"> |
| 286 | + Choose "Guided" for step-by-step instructions or "Quick" for |
| 287 | + the standard automatic flow. |
| 288 | + </p> |
| 289 | + </div> |
273 | 290 | </div> |
274 | 291 |
|
275 | 292 | <OAuthFlowProgress |
|
0 commit comments