tfrere HF Staff Cursor commited on
Commit
423399c
·
1 Parent(s): d08ce81

Fix OAuth in iframe: open login in new tab, check token before API call

Browse files
frontend/src/components/WelcomeScreen/WelcomeScreen.tsx CHANGED
@@ -9,6 +9,7 @@ import {
9
  import { useSessionStore } from '@/store/sessionStore';
10
  import { useAgentStore } from '@/store/agentStore';
11
  import { apiFetch } from '@/utils/api';
 
12
 
13
  /** HF brand orange */
14
  const HF_ORANGE = '#FF9D00';
@@ -21,17 +22,32 @@ export default function WelcomeScreen() {
21
 
22
  const handleStart = useCallback(async () => {
23
  if (isCreating) return;
 
 
 
 
 
 
 
 
 
 
 
24
  setIsCreating(true);
25
  setError(null);
26
 
27
  try {
28
- // apiFetch handles 401 → redirects to /auth/login automatically
29
  const response = await apiFetch('/api/session', { method: 'POST' });
30
  if (response.status === 503) {
31
  const data = await response.json();
32
  setError(data.detail || 'Server is at capacity. Please try again later.');
33
  return;
34
  }
 
 
 
 
 
35
  if (!response.ok) {
36
  setError('Failed to create session. Please try again.');
37
  return;
@@ -41,7 +57,7 @@ export default function WelcomeScreen() {
41
  setPlan([]);
42
  setPanelContent(null);
43
  } catch {
44
- // apiFetch throws on 401 redirect — don't show error in that case
45
  } finally {
46
  setIsCreating(false);
47
  }
 
9
  import { useSessionStore } from '@/store/sessionStore';
10
  import { useAgentStore } from '@/store/agentStore';
11
  import { apiFetch } from '@/utils/api';
12
+ import { getStoredToken, triggerLogin } from '@/hooks/useAuth';
13
 
14
  /** HF brand orange */
15
  const HF_ORANGE = '#FF9D00';
 
22
 
23
  const handleStart = useCallback(async () => {
24
  if (isCreating) return;
25
+
26
+ // If no token stored, trigger OAuth login first
27
+ if (!getStoredToken()) {
28
+ try {
29
+ await triggerLogin();
30
+ } catch {
31
+ setError('Could not open login page. Please try again.');
32
+ }
33
+ return;
34
+ }
35
+
36
  setIsCreating(true);
37
  setError(null);
38
 
39
  try {
 
40
  const response = await apiFetch('/api/session', { method: 'POST' });
41
  if (response.status === 503) {
42
  const data = await response.json();
43
  setError(data.detail || 'Server is at capacity. Please try again later.');
44
  return;
45
  }
46
+ if (response.status === 401) {
47
+ // Token expired — trigger re-login
48
+ await triggerLogin();
49
+ return;
50
+ }
51
  if (!response.ok) {
52
  setError('Failed to create session. Please try again.');
53
  return;
 
57
  setPlan([]);
58
  setPanelContent(null);
59
  } catch {
60
+ // triggerLogin throws if redirect happens — don't show error
61
  } finally {
62
  setIsCreating(false);
63
  }
frontend/src/hooks/useAuth.ts CHANGED
@@ -30,12 +30,25 @@ export function clearStoredToken(): void {
30
  }
31
  }
32
 
33
- /** Redirect to HF OAuth login. */
 
 
34
  export async function triggerLogin(): Promise<void> {
35
  const url = await oauthLoginUrl({
36
  scopes: 'openid profile read-repos write-repos manage-repos inference-api jobs',
37
  });
38
- window.location.href = url;
 
 
 
 
 
 
 
 
 
 
 
39
  }
40
 
41
  /**
 
30
  }
31
  }
32
 
33
+ /** Redirect to HF OAuth login.
34
+ * Uses window.open as fallback for iframe environments where
35
+ * top-level navigation is blocked by sandbox restrictions. */
36
  export async function triggerLogin(): Promise<void> {
37
  const url = await oauthLoginUrl({
38
  scopes: 'openid profile read-repos write-repos manage-repos inference-api jobs',
39
  });
40
+ // Try top-level navigation first; if we're in an iframe, open a new tab
41
+ try {
42
+ if (window.top !== window.self) {
43
+ // We're in an iframe — open in parent or new tab
44
+ window.open(url, '_blank');
45
+ } else {
46
+ window.location.href = url;
47
+ }
48
+ } catch {
49
+ // SecurityError from cross-origin iframe — open in new tab
50
+ window.open(url, '_blank');
51
+ }
52
  }
53
 
54
  /**