From 179dc306bbf6583ea6d56a8e765bc4259769c14b Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Mon, 9 Mar 2026 13:16:45 +0200 Subject: [PATCH] fix(auth): replace client-side signin page with server-side route handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The client page rendered inside AppShell layout, causing a flash of the full app UI before redirecting to Authentik. The new route handler initiates the OAuth flow server-side (CSRF token + POST to NextAuth provider signin) and redirects instantly — no visible page. Co-Authored-By: Claude Opus 4.6 --- src/app/auth/signin/page.tsx | 29 -------------- src/app/auth/signin/route.ts | 74 ++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 29 deletions(-) delete mode 100644 src/app/auth/signin/page.tsx create mode 100644 src/app/auth/signin/route.ts diff --git a/src/app/auth/signin/page.tsx b/src/app/auth/signin/page.tsx deleted file mode 100644 index a505ba7..0000000 --- a/src/app/auth/signin/page.tsx +++ /dev/null @@ -1,29 +0,0 @@ -"use client"; - -import { signIn } from "next-auth/react"; -import { useSearchParams } from "next/navigation"; -import { useEffect } from "react"; - -/** - * Custom sign-in page that auto-redirects to Authentik. - * Skips the default NextAuth provider chooser (no "Sign in with Authentik" button). - */ -export default function SignInPage() { - const searchParams = useSearchParams(); - const callbackUrl = searchParams.get("callbackUrl") || "/"; - - useEffect(() => { - void signIn("authentik", { callbackUrl }); - }, [callbackUrl]); - - return ( -
-
-
-

- Se redirecționează către autentificare... -

-
-
- ); -} diff --git a/src/app/auth/signin/route.ts b/src/app/auth/signin/route.ts new file mode 100644 index 0000000..ad58334 --- /dev/null +++ b/src/app/auth/signin/route.ts @@ -0,0 +1,74 @@ +import { NextRequest, NextResponse } from "next/server"; + +/** + * Server-side signin route that initiates OAuth flow with Authentik. + * Fetches CSRF token from NextAuth, POSTs to provider signin, + * and redirects to Authentik's authorize URL — no visible page. + */ +export async function GET(request: NextRequest) { + const callbackUrl = + request.nextUrl.searchParams.get("callbackUrl") || "/"; + const baseUrl = process.env.NEXTAUTH_URL || "https://tools.beletage.ro"; + + try { + // Use internal URL for server-to-server calls (avoid external roundtrip) + const internalBase = `http://127.0.0.1:${process.env.PORT || "3000"}`; + + // Step 1: Get CSRF token from NextAuth + const csrfRes = await fetch(`${internalBase}/api/auth/csrf`, { + headers: { cookie: request.headers.get("cookie") || "" }, + }); + const csrfData = (await csrfRes.json()) as { csrfToken: string }; + const csrfToken = csrfData.csrfToken; + + // Merge request cookies with new CSRF cookies + const csrfSetCookies = csrfRes.headers.getSetCookie(); + const existingCookies = request.headers.get("cookie") || ""; + const newCookiePairs = csrfSetCookies + .map((c) => c.split(";")[0]) + .filter(Boolean); + const mergedCookie = [existingCookies, ...newCookiePairs] + .filter(Boolean) + .join("; "); + + // Step 2: POST to NextAuth's provider-specific signin + const signinRes = await fetch( + `${internalBase}/api/auth/signin/authentik`, + { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + cookie: mergedCookie, + }, + body: new URLSearchParams({ csrfToken, callbackUrl }).toString(), + redirect: "manual", + }, + ); + + // Step 3: Get the redirect URL (Authentik's authorize endpoint) + const location = signinRes.headers.get("location"); + if (location) { + // Build absolute URL if relative + const redirectUrl = location.startsWith("http") + ? location + : `${baseUrl}${location}`; + const response = NextResponse.redirect(redirectUrl); + + // Forward all set-cookie headers to browser (CSRF token, state, etc.) + for (const cookie of csrfSetCookies) { + response.headers.append("set-cookie", cookie); + } + for (const cookie of signinRes.headers.getSetCookie()) { + response.headers.append("set-cookie", cookie); + } + return response; + } + } catch (error) { + console.error("[auth/signin] Server-side redirect failed:", error); + } + + // Fallback: redirect to NextAuth's built-in signin page + return NextResponse.redirect( + `${baseUrl}/api/auth/signin?callbackUrl=${encodeURIComponent(callbackUrl)}`, + ); +}