fix(auth): stabilize cookie domain handling behind proxy and add auth debug logs
Some checks failed
CI - Production Readiness / Verify (push) Has been cancelled
Some checks failed
CI - Production Readiness / Verify (push) Has been cancelled
This commit is contained in:
@ -38,6 +38,39 @@ function resolveNumber(raw: string | undefined, fallback: number) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const AUTH_DEBUG = process.env.AUTH_DEBUG === "true" || process.env.AUTH_DEBUG === "1";
|
||||
|
||||
function maskEmail(email: string) {
|
||||
if (!email) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const [name, domain] = email.split("@");
|
||||
if (!domain) {
|
||||
return "*****";
|
||||
}
|
||||
|
||||
if (name.length <= 2) {
|
||||
return `${name[0]}***@${domain}`;
|
||||
}
|
||||
|
||||
return `${name.slice(0, 2)}***@${domain}`;
|
||||
}
|
||||
|
||||
function shouldUseSecureCookies(request: NextRequest) {
|
||||
const explicit = process.env.COOKIE_SECURE?.toLowerCase() ?? "";
|
||||
if (explicit === "true" || explicit === "1") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (explicit === "false" || explicit === "0") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const forwardedProto = request.headers.get("x-forwarded-proto");
|
||||
return request.nextUrl.protocol === "https:" || (forwardedProto?.split(",")[0]?.toLowerCase() === "https");
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const { ipAddress, userAgent } = await getRequestAuditContext();
|
||||
const baseUrl = getRequestBaseUrl(request);
|
||||
@ -66,6 +99,15 @@ export async function POST(request: NextRequest) {
|
||||
const next = getSafePath(typeof rawNext === "string" ? rawNext : null);
|
||||
const email = typeof rawEmail === "string" ? rawEmail.trim() : "";
|
||||
const password = typeof rawPassword === "string" ? rawPassword : "";
|
||||
if (AUTH_DEBUG) {
|
||||
console.warn("[AUTH] login_attempt", {
|
||||
email: maskEmail(email),
|
||||
hasPassword: password.length > 0,
|
||||
next,
|
||||
ipAddress,
|
||||
userAgent
|
||||
});
|
||||
}
|
||||
|
||||
if (!email || !password) {
|
||||
const loginUrl = new URL("/login", baseUrl);
|
||||
@ -107,6 +149,14 @@ export async function POST(request: NextRequest) {
|
||||
loginUrl.searchParams.set("next", next);
|
||||
}
|
||||
|
||||
if (AUTH_DEBUG) {
|
||||
console.warn("[AUTH] login_failed", {
|
||||
email: maskEmail(email),
|
||||
ipAddress,
|
||||
userAgent
|
||||
});
|
||||
}
|
||||
|
||||
return NextResponse.redirect(loginUrl);
|
||||
}
|
||||
|
||||
@ -133,14 +183,42 @@ export async function POST(request: NextRequest) {
|
||||
destination && canAccessPath(session.role as UserRole, destination)
|
||||
? destination
|
||||
: getDefaultPathForRole(session.role as UserRole);
|
||||
const sessionMaxAgeSeconds = Math.max(
|
||||
60,
|
||||
Math.floor(session.expiresAt - Math.floor(Date.now() / 1000))
|
||||
);
|
||||
const response = NextResponse.redirect(new URL(safeDestination, baseUrl));
|
||||
response.cookies.set(SESSION_COOKIE, await serializeSession(session), {
|
||||
httpOnly: true,
|
||||
sameSite: "lax",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
secure: shouldUseSecureCookies(request),
|
||||
path: "/",
|
||||
maxAge: Math.max(1, Math.floor(session.expiresAt - Date.now() / 1000))
|
||||
maxAge: sessionMaxAgeSeconds
|
||||
});
|
||||
if (AUTH_DEBUG) {
|
||||
console.warn("[AUTH] session_cookie_issued", {
|
||||
userId: session.userId,
|
||||
role: session.role,
|
||||
sessionExpiresAt: session.expiresAt,
|
||||
maxAge: sessionMaxAgeSeconds,
|
||||
host: request.headers.get("host") || "unknown",
|
||||
protocol: request.nextUrl.protocol,
|
||||
forwardedProto: request.headers.get("x-forwarded-proto") || "unknown",
|
||||
secureCookies: shouldUseSecureCookies(request)
|
||||
});
|
||||
console.warn("[AUTH] login_success_redirect", {
|
||||
userId: session.userId,
|
||||
destination: safeDestination,
|
||||
setCookie: response.headers.get("set-cookie")
|
||||
});
|
||||
}
|
||||
|
||||
response.headers.set("X-Auth-Session", "issued");
|
||||
response.headers.set("X-Auth-Session-User", session.userId);
|
||||
response.headers.set("X-Auth-Session-Role", session.role);
|
||||
response.headers.set("X-Auth-Session-Base-Url", baseUrl.toString());
|
||||
response.headers.set("X-Auth-Session-Max-Age", String(sessionMaxAgeSeconds));
|
||||
response.headers.set("X-Auth-Session-Secure", String(shouldUseSecureCookies(request)));
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user