syncova-policies/lib/auth.ts
Weapie 265ca8ac38
All checks were successful
Container-Image bauen und veröffentlichen / build-and-push (push) Successful in 5m15s
Improve accessibility and access controls; verify production and database recovery
2026-09-14 11:44:41 +02:00

109 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import NextAuth, { NextAuthConfig } from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
import { PrismaAdapter } from "@auth/prisma-adapter"
import bcrypt from "bcryptjs"
import { prisma } from "@/lib/prisma"
export const authConfig: NextAuthConfig = {
adapter: PrismaAdapter(prisma),
providers: [
CredentialsProvider({
name: "credentials",
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" }
},
async authorize(credentials) {
if (!credentials?.email || !credentials?.password) {
return null
}
const user = await prisma.user.findUnique({
where: {
email: credentials.email as string
}
})
if (!user || !user.isActive) {
return null
}
const isPasswordValid = await bcrypt.compare(
credentials.password as string,
user.password
)
if (!isPasswordValid) {
return null
}
return {
id: user.id.toString(),
email: user.email,
name: user.name,
role: user.role,
}
}
})
],
session: {
strategy: "jwt"
},
callbacks: {
async jwt({ token, user }) {
if (user) {
token.role = user.role
token.issuedAt = Date.now()
}
return token
},
async session({ session, token }) {
if (token) {
session.issuedAt = typeof token.issuedAt === "number" ? token.issuedAt : undefined
session.user.id = token.sub ?? ""
session.user.role = token.role as string
}
return session
}
},
pages: {
signIn: "/auth/signin",
},
// Selbst gehostet: Auth.js vertraut sonst nur Vercel-Hosts und lehnt
// Anfragen hinter Reverse-Proxy/Container mit UntrustedHost ab.
trustHost: true,
logger: {
error(error) {
// Im Produktions-Build ist der Klassenname minifiziert. Auth.js setzt
// zusätzlich ein `type`-Feld aus einem String-Literal, das erhalten
// bleibt; die Fehlermeldung verlinkt denselben Bezeichner.
const type = (error as { type?: string }).type || error.name
const isStaleSession =
type === "JWTSessionError" ||
/#jwtsessionerror/i.test(error.message || "")
// Ein Cookie, das mit einem anderen NEXTAUTH_SECRET verschlüsselt wurde,
// ist kein Serverfehler, sondern eine veraltete Sitzung. Die Middleware
// löscht das Cookie beim nächsten Aufruf; hier reicht eine knappe Zeile
// statt eines Stacktraces bei jedem einzelnen Request.
if (isStaleSession) {
console.warn(
"[auth] Veraltetes Sitzungs-Cookie verworfen (mit einem anderen NEXTAUTH_SECRET verschlüsselt) – wird beim nächsten Aufruf entfernt."
)
return
}
console.error(`[auth] ${type}: ${error.message}`)
},
warn(code) {
console.warn(`[auth] ${code}`)
},
debug() {},
},
// Kein Fallback-Secret: fehlt NEXTAUTH_SECRET, soll der Start fehlschlagen,
// statt still mit einem öffentlich bekannten Wert zu signieren.
secret: process.env.NEXTAUTH_SECRET!
}
export const { handlers, auth, signIn, signOut } = NextAuth(authConfig)