Initial commit for gscMy carved out as its own repo (was tracked
loosely under the monorepo's web/ which is gitignored).
What this contains:
- Auth: next-auth v5 via @gsc/web-kit createAuth (Keycloak only,
identity sourced from claims, no admin.users writes)
- Chrome: @gsc/web-kit AdminShell — replaces the legacy MyShell.
Sidebar JSON config carried over and mapped to DbMenuItem.
- Middleware: createAuthMiddleware. Public: /access-denied,
/auth/keycloak, /signed-out, /api/health, /api/pam/approve.
- RP-initiated signout at /api/auth/signout → Keycloak end_session →
/signed-out (mirrors gscAdmin).
- Phosphor-iconned access-denied + signed-out landing pages.
PAM/JIT request flow (ported from gscAdmin's pre-strip git history):
- /access page (Active + Eligible tables, request modal with
duration slider + justification + optional MFA)
- API: /api/pam/{eligible, active, audit, request, approve/:token,
revoke/:id}
- src/lib/{authz, pam, pam-mail, pam-mfa}.ts — same files as
gscAdmin had before the strip. PAM tables (admin.privilege_*)
are shared with gscAdmin; gscMy uses the same Prisma model defs.
- Top-bar widget shows active grants with countdown + revoke.
Build/Deploy: Dockerfile (monorepo-root context), k8s manifests for
my.gosec.internal, self-signed TLS placeholder, DNS A record.
Keycloak gsc-my client extended to include my.gosec.internal/* in
redirect_uris + web_origins.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
32 lines
1.1 KiB
TypeScript
32 lines
1.1 KiB
TypeScript
import { auth, signOut } from "@/auth";
|
|
|
|
// RP-initiated logout. Overrides NextAuth's default /api/auth/signout
|
|
// confirmation page: kills both the NextAuth cookie and the Keycloak
|
|
// SSO session, then bounces to /signed-out.
|
|
|
|
async function handleSignout(request: Request): Promise<Response> {
|
|
const session = await auth();
|
|
const idToken = (session?.user as { idToken?: string } | undefined)?.idToken;
|
|
|
|
await signOut({ redirect: false });
|
|
|
|
const issuer = process.env.AUTH_KEYCLOAK_ISSUER;
|
|
const origin = (
|
|
process.env.AUTH_URL ??
|
|
process.env.NEXTAUTH_URL ??
|
|
new URL(request.url).origin
|
|
).replace(/\/$/, "");
|
|
const postLogout = `${origin}/signed-out`;
|
|
|
|
if (!issuer) return Response.redirect(postLogout, 302);
|
|
|
|
const endSession = new URL(`${issuer}/protocol/openid-connect/logout`);
|
|
endSession.searchParams.set("post_logout_redirect_uri", postLogout);
|
|
if (idToken) endSession.searchParams.set("id_token_hint", idToken);
|
|
else endSession.searchParams.set("client_id", process.env.AUTH_KEYCLOAK_ID ?? "");
|
|
return Response.redirect(endSession.toString(), 302);
|
|
}
|
|
|
|
export const GET = handleSignout;
|
|
export const POST = handleSignout;
|