debug(pam): add /api/pam/whoami to inspect session roles
Temporary endpoint to verify what `realm_access.roles` Keycloak puts into the access token vs. what NextAuth lands in session.user.roles. Remove once the eligibility plumbing is confirmed working. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,7 +31,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: my-ui
|
- name: my-ui
|
||||||
image: registry.gosec.internal/gsc-my/ui:v0.1.1
|
image: registry.gosec.internal/gsc-my/ui:v0.1.2
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 3000
|
- containerPort: 3000
|
||||||
|
|||||||
49
src/app/api/pam/whoami/route.ts
Normal file
49
src/app/api/pam/whoami/route.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// Debug endpoint — returns the session shape as the server sees it.
|
||||||
|
// Safe to call by the user themselves; reveals nothing about anyone
|
||||||
|
// else. Remove once eligibility plumbing is verified working.
|
||||||
|
|
||||||
|
import { auth } from "@/auth";
|
||||||
|
|
||||||
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
const session = await auth();
|
||||||
|
const u = session?.user as
|
||||||
|
| {
|
||||||
|
id?: string;
|
||||||
|
keycloakId?: string;
|
||||||
|
tenantId?: string;
|
||||||
|
customerId?: string;
|
||||||
|
email?: string;
|
||||||
|
roles?: string[];
|
||||||
|
accessToken?: string;
|
||||||
|
}
|
||||||
|
| undefined;
|
||||||
|
if (!u?.id) return Response.json({ error: "unauthorized" }, { status: 401 });
|
||||||
|
|
||||||
|
// Re-decode the access token here so we can compare what NextAuth
|
||||||
|
// wrote into session.user.roles vs. what's currently in realm_access.
|
||||||
|
let accessTokenRoles: string[] = [];
|
||||||
|
try {
|
||||||
|
const payload = u.accessToken?.split(".")[1];
|
||||||
|
if (payload) {
|
||||||
|
const padded = payload + "=".repeat((4 - (payload.length % 4)) % 4);
|
||||||
|
const decoded = Buffer.from(padded, "base64").toString("utf8");
|
||||||
|
const json = JSON.parse(decoded) as { realm_access?: { roles?: string[] } };
|
||||||
|
accessTokenRoles = json.realm_access?.roles ?? [];
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.json({
|
||||||
|
id: u.id,
|
||||||
|
keycloakId: u.keycloakId,
|
||||||
|
tenantId: u.tenantId,
|
||||||
|
customerId: u.customerId,
|
||||||
|
email: u.email,
|
||||||
|
sessionRoles: u.roles ?? [],
|
||||||
|
accessTokenRoles,
|
||||||
|
eligibleSuffixMatches: (u.roles ?? []).filter((r) => r.endsWith("_eligible")),
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user