enzostvs HF Staff commited on
Commit
cbc1bda
·
1 Parent(s): 9c17740

test login

Browse files
app/api/auth/login-url/route.ts ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { NextRequest, NextResponse } from "next/server";
2
+
3
+ export async function GET(req: NextRequest) {
4
+ const host = req.headers.get("host") ?? "localhost:3000";
5
+ const url = host.includes("/spaces/enzostvs")
6
+ ? "enzostvs-deepsite.hf.space"
7
+ : host;
8
+ const redirect_uri =
9
+ `${host.includes("localhost") ? "http://" : "https://"}` +
10
+ url +
11
+ "/auth/callback";
12
+
13
+ const loginRedirectUrl = `https://huggingface.co/oauth/authorize?client_id=${process.env.OAUTH_CLIENT_ID}&redirect_uri=${redirect_uri}&response_type=code&scope=openid%20profile%20write-repos%20manage-repos%20inference-api&prompt=consent&state=1234567890`;
14
+
15
+ return NextResponse.json({ loginUrl: loginRedirectUrl });
16
+ }
app/auth/callback/page.tsx CHANGED
@@ -6,18 +6,42 @@ import { useMount, useTimeoutFn } from "react-use";
6
 
7
  import { Button } from "@/components/ui/button";
8
  import { AnimatedBlobs } from "@/components/animated-blobs";
 
9
  export default function AuthCallback({
10
  searchParams,
11
  }: {
12
  searchParams: Promise<{ code: string }>;
13
  }) {
14
  const [showButton, setShowButton] = useState(false);
 
15
  const { code } = use(searchParams);
16
  const { loginFromCode } = useUser();
 
17
 
18
  useMount(async () => {
19
  if (code) {
20
- await loginFromCode(code);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  }
22
  });
23
 
@@ -41,10 +65,14 @@ export default function AuthCallback({
41
  </div>
42
  </div>
43
  <p className="text-xl font-semibold text-neutral-950">
44
- Login In Progress...
 
 
45
  </p>
46
  <p className="text-sm text-neutral-500 mt-1.5">
47
- Wait a moment while we log you in with your code.
 
 
48
  </p>
49
  </header>
50
  <main className="space-y-4 p-6">
 
6
 
7
  import { Button } from "@/components/ui/button";
8
  import { AnimatedBlobs } from "@/components/animated-blobs";
9
+ import { useBroadcastChannel } from "@/lib/useBroadcastChannel";
10
  export default function AuthCallback({
11
  searchParams,
12
  }: {
13
  searchParams: Promise<{ code: string }>;
14
  }) {
15
  const [showButton, setShowButton] = useState(false);
16
+ const [isPopupAuth, setIsPopupAuth] = useState(false);
17
  const { code } = use(searchParams);
18
  const { loginFromCode } = useUser();
19
+ const { postMessage } = useBroadcastChannel("auth", () => {});
20
 
21
  useMount(async () => {
22
  if (code) {
23
+ // Check if this is a popup window opened for authentication
24
+ // by checking if window.opener exists or if we can communicate with parent
25
+ const isPopup = window.opener || window.parent !== window;
26
+ setIsPopupAuth(isPopup);
27
+
28
+ if (isPopup) {
29
+ // Broadcast the auth code to the parent window/iframe
30
+ postMessage({
31
+ type: "user-oauth",
32
+ code: code,
33
+ });
34
+
35
+ // Close this popup/tab after a short delay
36
+ setTimeout(() => {
37
+ if (window.opener) {
38
+ window.close();
39
+ }
40
+ }, 1000);
41
+ } else {
42
+ // Normal flow for direct navigation to callback
43
+ await loginFromCode(code);
44
+ }
45
  }
46
  });
47
 
 
65
  </div>
66
  </div>
67
  <p className="text-xl font-semibold text-neutral-950">
68
+ {isPopupAuth
69
+ ? "Authentication Complete!"
70
+ : "Login In Progress..."}
71
  </p>
72
  <p className="text-sm text-neutral-500 mt-1.5">
73
+ {isPopupAuth
74
+ ? "You can now close this tab and return to the previous page."
75
+ : "Wait a moment while we log you in with your code."}
76
  </p>
77
  </header>
78
  <main className="space-y-4 p-6">
hooks/useUser.ts CHANGED
@@ -11,7 +11,8 @@ import {
11
  storeAuthDataFallback,
12
  getAuthDataFallback,
13
  clearAuthDataFallback,
14
- isInIframe
 
15
  } from "@/lib/iframe-storage";
16
 
17
 
@@ -59,6 +60,26 @@ export const useUser = (initialData?: {
59
 
60
  const openLoginWindow = async () => {
61
  setCurrentRoute(window.location.pathname);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  return router.push("/auth");
63
  };
64
 
 
11
  storeAuthDataFallback,
12
  getAuthDataFallback,
13
  clearAuthDataFallback,
14
+ isInIframe,
15
+ isMobileDevice
16
  } from "@/lib/iframe-storage";
17
 
18
 
 
60
 
61
  const openLoginWindow = async () => {
62
  setCurrentRoute(window.location.pathname);
63
+
64
+ // If we're in an iframe and on mobile, open login in a new tab
65
+ if (isInIframe() && isMobileDevice()) {
66
+ try {
67
+ // Get the login URL from the server
68
+ const response = await api.get("/auth/login-url");
69
+ const { loginUrl } = response.data;
70
+
71
+ // Open in new tab for mobile iframe users
72
+ window.open(loginUrl, "_blank", "noopener,noreferrer");
73
+
74
+ toast.info("Login opened in new tab. Please complete authentication and return to this page.");
75
+ return;
76
+ } catch (error) {
77
+ console.error("Failed to open login in new tab:", error);
78
+ // Fall back to normal flow if opening new tab fails
79
+ }
80
+ }
81
+
82
+ // Normal login flow for non-iframe or non-mobile users
83
  return router.push("/auth");
84
  };
85
 
lib/iframe-storage.ts CHANGED
@@ -11,6 +11,20 @@ export const isInIframe = (): boolean => {
11
  }
12
  };
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  export const STORAGE_KEYS = {
15
  ACCESS_TOKEN: "deepsite-auth-token-fallback",
16
  USER_DATA: "deepsite-user-data-fallback",
 
11
  }
12
  };
13
 
14
+ export const isMobileDevice = (): boolean => {
15
+ if (typeof window === 'undefined') return false;
16
+
17
+ // Check user agent for mobile patterns
18
+ const userAgent = window.navigator.userAgent;
19
+ const mobilePattern = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile|CriOS/i;
20
+
21
+ // Also check for touch capability and screen size
22
+ const hasTouchScreen = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
23
+ const hasSmallScreen = window.innerWidth <= 768; // Common mobile breakpoint
24
+
25
+ return mobilePattern.test(userAgent) || (hasTouchScreen && hasSmallScreen);
26
+ };
27
+
28
  export const STORAGE_KEYS = {
29
  ACCESS_TOKEN: "deepsite-auth-token-fallback",
30
  USER_DATA: "deepsite-user-data-fallback",