fix: use APP_URL for OAuth/verify redirects behind Dokploy proxy
Behind Traefik, request.url resolves to http://0.0.0.0:3000/... (the internal Docker address). Using that as the redirect base sent browsers to 0.0.0.0, causing ERR_SSL_PROTOCOL_ERROR. Switch all server-side redirects in the Google callback and verify-email routes to use NEXT_PUBLIC_APP_URL (with tia.manohargupta.com fallback). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6bdaade777
commit
b91595316d
2 changed files with 13 additions and 9 deletions
|
|
@ -6,6 +6,8 @@ import { logAudit } from "@/lib/audit";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
const APP_URL = process.env.NEXT_PUBLIC_APP_URL || "https://tia.manohargupta.com";
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
export async function GET(request: Request) {
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
const code = url.searchParams.get("code");
|
const code = url.searchParams.get("code");
|
||||||
|
|
@ -17,7 +19,7 @@ export async function GET(request: Request) {
|
||||||
|
|
||||||
// 1. CSRF / integrity check — returned state must match what we sent.
|
// 1. CSRF / integrity check — returned state must match what we sent.
|
||||||
if (!code || !state || !storedState || state !== storedState || !verifier) {
|
if (!code || !state || !storedState || state !== storedState || !verifier) {
|
||||||
return NextResponse.redirect(new URL("/login?error=oauth", request.url));
|
return NextResponse.redirect(new URL("/login?error=oauth", APP_URL));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -31,7 +33,7 @@ export async function GET(request: Request) {
|
||||||
{ headers: { Authorization: `Bearer ${tokens.accessToken()}` } },
|
{ headers: { Authorization: `Bearer ${tokens.accessToken()}` } },
|
||||||
);
|
);
|
||||||
if (!profileRes.ok) {
|
if (!profileRes.ok) {
|
||||||
return NextResponse.redirect(new URL("/login?error=oauth", request.url));
|
return NextResponse.redirect(new URL("/login?error=oauth", APP_URL));
|
||||||
}
|
}
|
||||||
const profile = (await profileRes.json()) as {
|
const profile = (await profileRes.json()) as {
|
||||||
sub: string; email: string; email_verified: boolean;
|
sub: string; email: string; email_verified: boolean;
|
||||||
|
|
@ -40,7 +42,7 @@ export async function GET(request: Request) {
|
||||||
|
|
||||||
// 4. HARD requirement: Google must confirm the email is verified.
|
// 4. HARD requirement: Google must confirm the email is verified.
|
||||||
if (!profile.email || !profile.email_verified) {
|
if (!profile.email || !profile.email_verified) {
|
||||||
return NextResponse.redirect(new URL("/login?error=unverified", request.url));
|
return NextResponse.redirect(new URL("/login?error=unverified", APP_URL));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Find or create the user.
|
// 5. Find or create the user.
|
||||||
|
|
@ -92,7 +94,7 @@ export async function GET(request: Request) {
|
||||||
await logAudit({ userId, action: "login", request, metadata: { method: "google" } });
|
await logAudit({ userId, action: "login", request, metadata: { method: "google" } });
|
||||||
|
|
||||||
const response = NextResponse.redirect(
|
const response = NextResponse.redirect(
|
||||||
new URL(isNewUser ? "/onboarding" : "/", request.url),
|
new URL(isNewUser ? "/onboarding" : "/", APP_URL),
|
||||||
);
|
);
|
||||||
response.cookies.set("tia_session", sessionToken, {
|
response.cookies.set("tia_session", sessionToken, {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
|
|
@ -106,6 +108,6 @@ export async function GET(request: Request) {
|
||||||
return response;
|
return response;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Google callback error:", e);
|
console.error("Google callback error:", e);
|
||||||
return NextResponse.redirect(new URL("/login?error=oauth", request.url));
|
return NextResponse.redirect(new URL("/login?error=oauth", APP_URL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,13 @@ import { logAudit } from "@/lib/audit";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
const APP_URL = process.env.NEXT_PUBLIC_APP_URL || "https://tia.manohargupta.com";
|
||||||
|
|
||||||
// GET — the link target from the verification email.
|
// GET — the link target from the verification email.
|
||||||
export async function GET(request: Request) {
|
export async function GET(request: Request) {
|
||||||
const token = new URL(request.url).searchParams.get("token");
|
const token = new URL(request.url).searchParams.get("token");
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return NextResponse.redirect(new URL("/login?error=verify", request.url));
|
return NextResponse.redirect(new URL("/login?error=verify", APP_URL));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -19,7 +21,7 @@ export async function GET(request: Request) {
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
`;
|
`;
|
||||||
if (rows.length === 0) {
|
if (rows.length === 0) {
|
||||||
return NextResponse.redirect(new URL("/login?error=verify", request.url));
|
return NextResponse.redirect(new URL("/login?error=verify", APP_URL));
|
||||||
}
|
}
|
||||||
|
|
||||||
const verifyId = rows[0].id;
|
const verifyId = rows[0].id;
|
||||||
|
|
@ -39,7 +41,7 @@ export async function GET(request: Request) {
|
||||||
`;
|
`;
|
||||||
await logAudit({ userId, action: "email_verified", request });
|
await logAudit({ userId, action: "email_verified", request });
|
||||||
|
|
||||||
const response = NextResponse.redirect(new URL("/onboarding", request.url));
|
const response = NextResponse.redirect(new URL("/onboarding", APP_URL));
|
||||||
response.cookies.set("tia_session", sessionToken, {
|
response.cookies.set("tia_session", sessionToken, {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: process.env.NODE_ENV === "production",
|
secure: process.env.NODE_ENV === "production",
|
||||||
|
|
@ -50,6 +52,6 @@ export async function GET(request: Request) {
|
||||||
return response;
|
return response;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Verify email error:", e);
|
console.error("Verify email error:", e);
|
||||||
return NextResponse.redirect(new URL("/login?error=verify", request.url));
|
return NextResponse.redirect(new URL("/login?error=verify", APP_URL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue