update nextauth

This commit is contained in:
Elias Bennour 2025-05-25 15:23:03 +02:00
parent abded046a1
commit b1c92b41cf

View File

@ -1,15 +1,12 @@
// Datei: pages/api/auth/[...nextauth].ts
import NextAuth, {AuthOptions} from "next-auth";
import NextAuth, { AuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import KeycloakProvider, { KeycloakProfile } from "next-auth/providers/keycloak";
// Falls 'next-auth/jwt' nicht funktioniert, versuche 'next-auth/core/types'
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import prisma from "../../../lib/prisma";
import bcrypt from "bcryptjs";
// User-Typ aus deinen globalen NextAuth-Typen (next-auth.d.ts)
// wird für den Rückgabetyp des profile-Callbacks benötigt.
import type { User } from "next-auth";
export const authOptions: AuthOptions = {
@ -22,30 +19,29 @@ export const authOptions: AuthOptions = {
clientId: process.env.KEYCLOAK_CLIENT_ID as string,
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET as string,
issuer: process.env.KEYCLOAK_ISSUER as string,
allowDangerousEmailAccountLinking: true,
profile(profile: KeycloakProfile): User | Promise<User> {
// profile: Das von Keycloak zurückgegebene Benutzerprofil.
// tokens: Enthält access_token, id_token etc. und entspricht dem TokenSet-Typ.
let userRole = 'user'; // Standardrolle
// Beispiel für Rollenextraktion (passe dies an deine Keycloak-Konfiguration an):
// Oft sind Rollen in 'realm_access.roles' oder 'resource_access.[client-id].roles'
// im dekodierten Access Token oder ID Token.
// Oder Keycloak Mappers können Rollen direkt ins Profil-Objekt legen.
let userRole = 'user';
if (profile.realm_access?.roles && Array.isArray(profile.realm_access.roles) && profile.realm_access.roles.includes('admin')) {
userRole = 'admin';
} else if (profile.roles && Array.isArray(profile.roles) && profile.roles.includes('admin')) { // Falls 'roles' direkt im Profil ist
} else if (profile.roles && Array.isArray(profile.roles) && profile.roles.includes('admin')) {
userRole = 'admin';
}
// Wenn ein bestehender Benutzer mit derselben E-Mail gefunden wird,
// wird der Adapter versuchen, dieses Keycloak-Konto mit dem bestehenden Benutzer zu verknüpfen.
// Die hier zurückgegebenen Daten können verwendet werden, um den bestehenden Benutzer zu aktualisieren.
return {
id: profile.sub,
name: profile.name || profile.preferred_username,
email: profile.email,
image: profile.picture,
role: userRole,
isApproved: true,
// emailVerified wird vom PrismaAdapter erwartet (kann null sein).
// Mappe es, wenn Keycloak 'email_verified: true' sendet.
isApproved: true, // Annahme: OIDC-Benutzer sind standardmäßig freigegeben
// Wenn ein lokales Konto existiert, wird dessen isApproved-Status
// möglicherweise durch die Adapterlogik beibehalten oder aktualisiert.
// Dies hängt vom genauen Verhalten des Adapters beim Verknüpfen ab.
...(profile.email_verified && { emailVerified: new Date() }),
};
},
@ -85,6 +81,31 @@ export const authOptions: AuthOptions = {
}),
],
callbacks: {
// Der signIn Callback kann für komplexere Verknüpfungslogik oder Prüfungen verwendet werden.
// Mit `allowDangerousEmailAccountLinking: true` ist er für das reine Verknüpfen oft nicht nötig.
/*
async signIn({ user, account, profile, email, credentials }) {
if (account?.provider === "keycloak" && profile?.email) {
const existingUser = await prisma.user.findUnique({
where: { email: profile.email.toLowerCase() },
include: { accounts: true } // Um zu prüfen, ob bereits ein Keycloak-Konto verknüpft ist
});
if (existingUser) {
// Benutzer existiert. Prüfe, ob das Keycloak-Konto bereits verknüpft ist.
const isProviderAccountLinked = existingUser.accounts.some(
acc => acc.provider === account.provider && acc.providerAccountId === account.providerAccountId
);
if (!isProviderAccountLinked) {
// Hier würde die Verknüpfung durch den Adapter stattfinden,
// wenn allowDangerousEmailAccountLinking true ist.
// Du könntest hier zusätzliche Logik einbauen, z.B. den Benutzer benachrichtigen.
}
}
}
return true; // Erlaube den Anmeldevorgang
},
*/
async jwt({ token, user, account }) {
if (account && user) {
token.id = user.id;