wu981526092 commited on
Commit
77481d0
Β·
1 Parent(s): a093720

Fix: Frontend auth state detection for backend OAuth

Browse files

πŸ› Problem:
- Backend OAuth callback successful but frontend still shows login modal
- Frontend only checked localStorage, not backend session cookies
- User authenticated in backend but frontend remains in logged-out state

βœ… Solution:
- Added backend session status check to AuthContext.checkAuthStatus()
- Frontend now queries /auth/status API with credentials:include
- Converts backend user format to frontend OAuth format
- Synchronizes session data to localStorage for consistency

πŸ”§ Technical Changes:
Frontend AuthContext:
- Primary: Check backend session via /auth/status endpoint
- Secondary: Check localStorage for persisted auth state
- Fallback: Handle OAuth callback redirects
- Added proper TypeScript types (scope, emailVerified fields)

Backend Session Integration:
- Frontend reads session cookies from OAuth callback
- Converts backend user object to OAuthResult format
- Maintains token expiration and user info consistency

🎯 Flow Now:
1. User authorizes with HF β†’ backend saves to session
2. Frontend loads β†’ checks backend session first
3. If session exists β†’ sets frontend auth state
4. Modal closes β†’ user sees authenticated app

πŸ“‹ Expected Result:
- After OAuth redirect, frontend automatically detects login
- No more persistent login modal after successful auth
- Seamless transition from login to authenticated app

Files changed (1) hide show
  1. frontend/src/context/AuthContext.tsx +53 -28
frontend/src/context/AuthContext.tsx CHANGED
@@ -99,7 +99,47 @@ export function AuthProvider({ children }: { children: ReactNode }) {
99
  try {
100
  dispatch({ type: "SET_LOADING", payload: true });
101
 
102
- // First check localStorage for existing oauth data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  const stored = localStorage.getItem(STORAGE_KEY);
104
  if (stored) {
105
  try {
@@ -124,41 +164,26 @@ export function AuthProvider({ children }: { children: ReactNode }) {
124
  const state = urlParams.get("state");
125
  const storedState = localStorage.getItem("oauth_state");
126
 
127
- if (code && state && state === storedState) {
128
- console.log("πŸ” OAuth callback detected, exchanging code for token");
 
 
129
 
130
- // Clear OAuth state
131
  localStorage.removeItem("oauth_state");
132
 
133
- // For HF Spaces direct OAuth, we'll simulate a successful auth
134
- // In a real implementation, you'd exchange the code for a token
135
- const mockUserInfo: UserInfo = {
136
- id: "hf_user_" + Date.now(),
137
- name: "Hugging Face User",
138
- fullname: "HF User",
139
- email: "user@example.com",
140
- emailVerified: false,
141
- avatarUrl: undefined,
142
- isPro: false,
143
- orgs: [],
144
- };
145
-
146
- const normalizedResult: OAuthResult = {
147
- accessToken: `hf_mock_token_${Date.now()}`,
148
- accessTokenExpiresAt: new Date(Date.now() + 3600000).toISOString(), // 1 hour
149
- userInfo: mockUserInfo,
150
- scope: "openid profile read-repos",
151
- };
152
-
153
- localStorage.setItem(STORAGE_KEY, JSON.stringify(normalizedResult));
154
- dispatch({ type: "AUTH_SUCCESS", payload: normalizedResult });
155
-
156
- // Clean up URL
157
  window.history.replaceState(
158
  {},
159
  document.title,
160
  window.location.pathname
161
  );
 
 
 
 
 
 
162
  } else {
163
  // No OAuth redirect found, check if we need to show auth modal
164
 
 
99
  try {
100
  dispatch({ type: "SET_LOADING", payload: true });
101
 
102
+ // First check backend session for existing authentication
103
+ try {
104
+ const response = await fetch("/auth/status", {
105
+ credentials: "include", // Include session cookies
106
+ });
107
+
108
+ if (response.ok) {
109
+ const statusData = await response.json();
110
+ if (statusData.authenticated && statusData.user) {
111
+ console.log("πŸ”“ Found existing backend session authentication");
112
+
113
+ // Convert backend user format to our OAuth format
114
+ const oauthResult: OAuthResult = {
115
+ userInfo: {
116
+ id: statusData.user.id,
117
+ name: statusData.user.name || statusData.user.username,
118
+ fullname: statusData.user.name || statusData.user.username,
119
+ email: statusData.user.email,
120
+ emailVerified: false,
121
+ avatarUrl: statusData.user.avatar_url,
122
+ orgs: [],
123
+ isPro: false,
124
+ },
125
+ accessToken: statusData.user.access_token || "session_token",
126
+ accessTokenExpiresAt: new Date(
127
+ Date.now() + 24 * 60 * 60 * 1000
128
+ ).toISOString(), // 24 hours
129
+ scope: "openid profile read-repos", // Backend authenticated users have these scopes
130
+ };
131
+
132
+ dispatch({ type: "AUTH_SUCCESS", payload: oauthResult });
133
+ // Also save to localStorage for consistency
134
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(oauthResult));
135
+ return;
136
+ }
137
+ }
138
+ } catch (error) {
139
+ console.log("πŸ” No backend session found, checking localStorage");
140
+ }
141
+
142
+ // Second, check localStorage for existing oauth data
143
  const stored = localStorage.getItem(STORAGE_KEY);
144
  if (stored) {
145
  try {
 
164
  const state = urlParams.get("state");
165
  const storedState = localStorage.getItem("oauth_state");
166
 
167
+ if (code && state) {
168
+ console.log(
169
+ "πŸ” OAuth callback detected - backend should have handled this"
170
+ );
171
 
172
+ // Clear OAuth state from localStorage
173
  localStorage.removeItem("oauth_state");
174
 
175
+ // Clean up URL parameters since backend handled the OAuth
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  window.history.replaceState(
177
  {},
178
  document.title,
179
  window.location.pathname
180
  );
181
+
182
+ // Recheck auth status to pick up the backend session
183
+ setTimeout(() => {
184
+ checkAuthStatus();
185
+ }, 100);
186
+ return;
187
  } else {
188
  // No OAuth redirect found, check if we need to show auth modal
189