fix: correct Theia ForwardAuth redirect loop

Two issues:
1. ForwardAuth redirect used x-forwarded-host which Traefik sets to
   vibnai.com (the auth service host), not theia.vibnai.com. Now
   hardcodes THEIA_URL as the callbackUrl destination.
2. /auth page ignored callbackUrl and always sent users to
   /marks-account/projects. Now follows callbackUrl when it points
   to theia.vibnai.com, so users land in the IDE after login.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-02-18 18:17:16 -08:00
parent 8e0d9090be
commit 1146d8d129
2 changed files with 14 additions and 13 deletions

View File

@@ -78,14 +78,9 @@ export async function GET(request: NextRequest) {
} }
function redirectToLogin(request: NextRequest): NextResponse { function redirectToLogin(request: NextRequest): NextResponse {
const forwardedHost = request.headers.get('x-forwarded-host'); // Traefik ForwardAuth sets X-Forwarded-Host to the auth service's host (vibnai.com),
const forwardedProto = request.headers.get('x-forwarded-proto') ?? 'https'; // not the original request host (theia.vibnai.com). Use THEIA_URL directly as the
const forwardedUri = request.headers.get('x-forwarded-uri') ?? '/'; // destination so the user returns to Theia after logging in.
const loginUrl = `${APP_URL}/auth?callbackUrl=${encodeURIComponent(THEIA_URL)}`;
const destination = forwardedHost
? `${forwardedProto}://${forwardedHost}${forwardedUri}`
: THEIA_URL;
const loginUrl = `${APP_URL}/auth?callbackUrl=${encodeURIComponent(destination)}`;
return NextResponse.redirect(loginUrl, { status: 302 }); return NextResponse.redirect(loginUrl, { status: 302 });
} }

View File

@@ -1,20 +1,26 @@
"use client"; "use client";
import { useSession } from "next-auth/react"; import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation"; import { useRouter, useSearchParams } from "next/navigation";
import { useEffect } from "react"; import { useEffect } from "react";
import NextAuthComponent from "@/app/components/NextAuthComponent"; import NextAuthComponent from "@/app/components/NextAuthComponent";
export default function AuthPage() { export default function AuthPage() {
const { data: session, status } = useSession(); const { data: session, status } = useSession();
const router = useRouter(); const router = useRouter();
const searchParams = useSearchParams();
useEffect(() => { useEffect(() => {
// Redirect if already authenticated
if (status === "authenticated") { if (status === "authenticated") {
router.push("/marks-account/projects"); const callbackUrl = searchParams.get("callbackUrl");
// Only follow external callbackUrls we control (Theia subdomain)
if (callbackUrl && callbackUrl.startsWith("https://theia.vibnai.com")) {
window.location.href = callbackUrl;
} else {
router.push("/marks-account/projects");
}
} }
}, [status, router]); }, [status, router, searchParams]);
if (status === "loading") { if (status === "loading") {
return ( return (