fix(confidence-engine): preserve external auth callback origin
This commit is contained in:
@@ -4,7 +4,22 @@ import { NextResponse } from "next/server";
|
|||||||
export async function GET(request) {
|
export async function GET(request) {
|
||||||
const requestUrl = new URL(request.url);
|
const requestUrl = new URL(request.url);
|
||||||
const code = requestUrl.searchParams.get("code");
|
const code = requestUrl.searchParams.get("code");
|
||||||
const response = NextResponse.redirect(new URL("/", requestUrl.origin));
|
|
||||||
|
// Derive redirect origin from proxy-forwarded headers when present,
|
||||||
|
// falling back to the direct request origin for local/direct access.
|
||||||
|
const forwardedHost = request.headers.get("x-forwarded-host");
|
||||||
|
const forwardedProto = request.headers.get("x-forwarded-proto");
|
||||||
|
let origin;
|
||||||
|
|
||||||
|
if (forwardedHost && forwardedProto) {
|
||||||
|
// Nginx Proxy Manager (and similar proxies) set these headers.
|
||||||
|
// x-forwarded-host may contain host:port or just hostname; use as-is.
|
||||||
|
origin = `${forwardedProto}://${forwardedHost}`;
|
||||||
|
} else {
|
||||||
|
origin = requestUrl.origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = NextResponse.redirect(new URL("/", origin));
|
||||||
|
|
||||||
if (code) {
|
if (code) {
|
||||||
const supabase = createServerClient(
|
const supabase = createServerClient(
|
||||||
|
|||||||
@@ -19,9 +19,47 @@ vi.mock("@/lib/config", () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("@supabase/ssr", () => ({
|
vi.mock("@supabase/ssr", () => ({
|
||||||
createServerClient: () => ({ auth: { getUser: () => mockGetUser() } }),
|
createServerClient: () => ({
|
||||||
|
auth: {
|
||||||
|
getUser: () => mockGetUser(),
|
||||||
|
exchangeCodeForSession: vi.fn().mockResolvedValue(undefined),
|
||||||
|
},
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
describe("auth callback redirect origin", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses forwarded host/proto for redirect when behind proxy", async () => {
|
||||||
|
const { GET } = await import("@/app/auth/callback/route.js");
|
||||||
|
|
||||||
|
const request = new Request("http://0.0.0.0:3000/auth/callback?code=abc123", {
|
||||||
|
headers: {
|
||||||
|
"x-forwarded-host": "confidence.rdbcloud.co.uk",
|
||||||
|
"x-forwarded-proto": "https",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await GET(request);
|
||||||
|
|
||||||
|
expect(response.status).toBe(307);
|
||||||
|
expect(response.headers.get("location")).toBe("https://confidence.rdbcloud.co.uk/");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("falls back to request origin when no forwarded headers", async () => {
|
||||||
|
const { GET } = await import("@/app/auth/callback/route.js");
|
||||||
|
|
||||||
|
const request = new Request("http://localhost:3000/auth/callback?code=xyz");
|
||||||
|
|
||||||
|
const response = await GET(request);
|
||||||
|
|
||||||
|
expect(response.status).toBe(307);
|
||||||
|
expect(response.headers.get("location")).toBe("http://localhost:3000/");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("authenticated product boundary", () => {
|
describe("authenticated product boundary", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
|||||||
Reference in New Issue
Block a user