From 035c5939997348344b2811098439f4aa36796fa6 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Tue, 10 Mar 2026 20:56:30 -0700 Subject: [PATCH] fix(security): remove accessToken from sessionStorage in OAuth flow state The LiteLLM API key was being serialised into sessionStorage as part of StoredFlowState. After the OAuth redirect the component re-mounts with the same accessToken prop, so it never needed to be stored. Read it from props in resumeOAuthFlow instead. --- ui/litellm-dashboard/src/hooks/useUserMcpOAuthFlow.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ui/litellm-dashboard/src/hooks/useUserMcpOAuthFlow.tsx b/ui/litellm-dashboard/src/hooks/useUserMcpOAuthFlow.tsx index ef9b6dedbed..80f042bbfe9 100644 --- a/ui/litellm-dashboard/src/hooks/useUserMcpOAuthFlow.tsx +++ b/ui/litellm-dashboard/src/hooks/useUserMcpOAuthFlow.tsx @@ -54,7 +54,6 @@ type StoredFlowState = { redirectUri: string; clientId?: string; clientSecret?: string; - accessToken: string; scopes?: string[]; }; @@ -175,7 +174,6 @@ export const useUserMcpOAuthFlow = ({ redirectUri, clientId, clientSecret, - accessToken, scopes, }; @@ -240,7 +238,8 @@ export const useUserMcpOAuthFlow = ({ }); // Persist the token for this user via the backend. - await storeMCPOAuthUserCredential(flowState.accessToken, flowState.serverId, { + // accessToken comes from props — it is never stored in sessionStorage. + await storeMCPOAuthUserCredential(accessToken, flowState.serverId, { access_token: token.access_token, refresh_token: token.refresh_token, expires_in: token.expires_in, @@ -260,7 +259,7 @@ export const useUserMcpOAuthFlow = ({ clearStorage(FLOW_STATE_KEY); setTimeout(() => { processingRef.current = false; }, 1000); } - }, [onSuccess]); + }, [accessToken, onSuccess]); useEffect(() => { resumeOAuthFlow();