update nextauth

This commit is contained in:
Elias Bennour 2025-05-25 16:01:03 +02:00
parent c8a5f9e04d
commit 0fd0cda405
2 changed files with 29 additions and 19 deletions

View File

@ -12,24 +12,24 @@ datasource db {
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
type String // z.B. "oauth", "oidc"
provider String // z.B. "keycloak", "credentials"
providerAccountId String // Die ID des Benutzers beim Provider (z.B. Keycloak 'sub')
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int? // Üblicherweise für access_token Ablauf (in Sekunden seit Unix-Epoche)
token_type String?
expires_at Int? // Unix-Timestamp (in Sekunden) für den Ablauf des access_token
token_type String? // z.B. "Bearer"
scope String?
id_token String? @db.Text
session_state String?
refresh_expires_in Int? // NEU: Lebensdauer des Refresh Tokens in Sekunden
not_before_policy Int? // NEU: Keycloak "Not Before Policy" Wert (Unix-Timestamp)
refresh_expires_in Int? // Lebensdauer des Refresh Tokens in Sekunden
not_before_policy Int? // NEU: Keycloak "Not Before Policy" Wert (oft ein Timestamp)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
@@index([userId]) // Index für userId hinzugefügt für bessere Abfrageleistung
@@index([userId])
}
model Session {

View File

@ -7,15 +7,14 @@ import { PrismaAdapter } from "@next-auth/prisma-adapter";
import prisma from "../../../lib/prisma";
import bcrypt from "bcryptjs";
import type { User } from "next-auth";
import type { User, Account } from "next-auth"; // Account importieren für den signIn Callback
export const authOptions: AuthOptions = {
adapter: PrismaAdapter(prisma),
session: {
strategy: "jwt",
},
// Debug-Modus für ausführlichere Logs von NextAuth.js aktivieren
debug: true, // process.env.NODE_ENV === 'development',
debug: process.env.NODE_ENV === 'development',
providers: [
KeycloakProvider({
clientId: process.env.KEYCLOAK_CLIENT_ID as string,
@ -23,14 +22,11 @@ export const authOptions: AuthOptions = {
issuer: process.env.KEYCLOAK_ISSUER as string,
allowDangerousEmailAccountLinking: true,
profile(profile: KeycloakProfile, tokens: TokenSet): User | Promise<User> {
// Detailliertes Logging des empfangenen Keycloak-Profils und der Tokens
console.log("[NextAuth.js] Keycloak Profile Received:", JSON.stringify(profile, null, 2));
// Vorsicht beim Loggen von Tokens in der Produktion, hier nur ein Snippet des ID-Tokens
if (tokens.id_token) {
console.log("[NextAuth.js] Keycloak ID Token Snippet:", tokens.id_token.substring(0, 50) + "...");
}
let userRole = 'user';
if (profile.realm_access?.roles && Array.isArray(profile.realm_access.roles) && profile.realm_access.roles.includes('admin')) {
userRole = 'admin';
@ -38,22 +34,20 @@ export const authOptions: AuthOptions = {
userRole = 'admin';
}
const emailFromProvider = profile.email?.toLowerCase(); // E-Mail normalisieren (zu Kleinbuchstaben)
const emailFromProvider = profile.email?.toLowerCase();
if (!emailFromProvider) {
console.error("[NextAuth.js] Email not provided by Keycloak profile. Profile data:", profile);
// Du könntest hier entscheiden, einen Fehler zu werfen oder einen Fallback zu implementieren,
// aber für die Kontoverknüpfung ist eine E-Mail essentiell.
throw new Error("E-Mail wurde nicht vom Identitätsprovider (Keycloak) bereitgestellt.");
}
const userToReturn: User = {
id: profile.sub,
name: profile.name || profile.preferred_username,
email: emailFromProvider, // Normalisierte E-Mail verwenden
email: emailFromProvider,
image: profile.picture,
role: userRole,
isApproved: true, // Annahme: OIDC-Benutzer sind standardmäßig freigegeben
isApproved: true,
};
console.log("[NextAuth.js] User object to be processed by adapter/callbacks:", JSON.stringify(userToReturn, null, 2));
@ -95,6 +89,22 @@ export const authOptions: AuthOptions = {
}),
],
callbacks: {
// NEU: signIn Callback, um Account-Daten vor dem Speichern anzupassen
async signIn({account}) {
if (account && account.provider === "keycloak") {
// Prüfe, ob 'not-before-policy' im Account-Objekt von Keycloak vorhanden ist
// und benenne es in 'not_before_policy' um, damit es zum Prisma-Schema passt.
// Das account-Objekt hier enthält die rohen Daten vom Token-Endpunkt.
const keycloakAccount = account as Account & { 'not-before-policy'?: any, 'not_before_policy'?: any };
if (keycloakAccount['not-before-policy'] !== undefined) {
console.log(`[NextAuth.js] signIn callback: Renaming 'not-before-policy' to 'not_before_policy' for account: ${account.providerAccountId}`);
keycloakAccount.not_before_policy = keycloakAccount['not-before-policy'];
delete keycloakAccount['not-before-policy'];
}
}
return true; // Erlaube den Anmeldevorgang
},
async jwt({ token, user, account }) {
if (account && user) {
token.id = user.id;