Enable auth-service/api-gateway on production, build their images in CI
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import type { LoginResponse } from "@duoc-thu/shared-types";
|
||||
import { SESSION_COOKIE, SESSION_MAX_AGE_SECONDS } from "../session";
|
||||
|
||||
const GATEWAY_URL = process.env.API_GATEWAY_URL ?? "http://localhost:3000";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
let username: string;
|
||||
let password: string;
|
||||
try {
|
||||
const body = await request.json();
|
||||
username = typeof body?.username === "string" ? body.username : "";
|
||||
password = typeof body?.password === "string" ? body.password : "";
|
||||
} catch {
|
||||
return NextResponse.json({ error: "invalid_body" }, { status: 400 });
|
||||
}
|
||||
if (!username || !password) {
|
||||
return NextResponse.json({ error: "missing_credentials" }, { status: 400 });
|
||||
}
|
||||
|
||||
let upstream: Response;
|
||||
try {
|
||||
upstream = await fetch(`${GATEWAY_URL}/auth/login`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ username, password }),
|
||||
cache: "no-store",
|
||||
});
|
||||
} catch {
|
||||
return NextResponse.json({ error: "gateway_unreachable" }, { status: 502 });
|
||||
}
|
||||
|
||||
if (!upstream.ok) {
|
||||
return NextResponse.json(
|
||||
{ error: "invalid_credentials" },
|
||||
{ status: upstream.status === 401 ? 401 : 502 }
|
||||
);
|
||||
}
|
||||
|
||||
const data = (await upstream.json()) as LoginResponse;
|
||||
const response = NextResponse.json({ user: data.user });
|
||||
// httpOnly: never readable by client-side JS (XSS can't exfiltrate it).
|
||||
// `secure` only outside local dev — Compose/k3s both terminate TLS in
|
||||
// front of `web`, so the cookie is only ever sent in the clear on
|
||||
// localhost, matching how every other secret in this repo treats
|
||||
// local vs. deployed differently.
|
||||
response.cookies.set(SESSION_COOKIE, data.token, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
sameSite: "lax",
|
||||
path: "/",
|
||||
maxAge: SESSION_MAX_AGE_SECONDS,
|
||||
});
|
||||
return response;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { SESSION_COOKIE } from "../session";
|
||||
|
||||
export async function POST() {
|
||||
const response = NextResponse.json({ ok: true });
|
||||
response.cookies.delete(SESSION_COOKIE);
|
||||
return response;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { cookies } from "next/headers";
|
||||
import type { AuthUser } from "@duoc-thu/shared-types";
|
||||
import { SESSION_COOKIE } from "../session";
|
||||
|
||||
const GATEWAY_URL = process.env.API_GATEWAY_URL ?? "http://localhost:3000";
|
||||
|
||||
export async function GET() {
|
||||
const token = cookies().get(SESSION_COOKIE)?.value;
|
||||
if (!token) {
|
||||
return NextResponse.json({ error: "not_authenticated" }, { status: 401 });
|
||||
}
|
||||
|
||||
let upstream: Response;
|
||||
try {
|
||||
upstream = await fetch(`${GATEWAY_URL}/auth/me`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
cache: "no-store",
|
||||
});
|
||||
} catch {
|
||||
return NextResponse.json({ error: "gateway_unreachable" }, { status: 502 });
|
||||
}
|
||||
|
||||
if (!upstream.ok) {
|
||||
return NextResponse.json({ error: "not_authenticated" }, { status: 401 });
|
||||
}
|
||||
|
||||
const user = (await upstream.json()) as AuthUser;
|
||||
return NextResponse.json(user);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/** Shared between the login/logout/me route handlers and `middleware.ts` —
|
||||
* kept dependency-free (no Node-only imports) so `middleware.ts` can import
|
||||
* it too; Next's Edge runtime middleware can't use arbitrary Node APIs. */
|
||||
export const SESSION_COOKIE = "dt_session";
|
||||
export const SESSION_MAX_AGE_SECONDS = 12 * 60 * 60; // matches auth-service's default JWT_EXPIRES_IN
|
||||
Reference in New Issue
Block a user