Files
2026FIFAWorldCup/platform/web/lib/auth.ts

85 lines
2.0 KiB
TypeScript

import NextAuth, { type DefaultSession } from 'next-auth';
import Credentials from 'next-auth/providers/credentials';
import { PrismaAdapter } from '@auth/prisma-adapter';
import { prisma } from './db';
export const AUTH_ROLE_CLAIM = 'role';
declare module 'next-auth' {
interface User {
role: string;
}
interface Session {
user: DefaultSession['user'] & {
role: string;
};
}
}
const handlers = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
Credentials({
name: 'Email',
credentials: {
email: { label: 'Email', type: 'email', placeholder: 'user@example.com' },
password: { label: 'Password', type: 'password' },
},
authorize: async (credentials) => {
const email = String(credentials?.email || '').trim().toLowerCase();
const password = String(credentials?.password || '');
if (!email || !password) return null;
const user = await prisma.user.findUnique({ where: { email } });
if (!user) return null;
if (user.passwordHash && user.passwordHash !== password) {
return null;
}
return {
id: user.id,
name: user.name,
email: user.email,
role: user.role,
};
},
}),
],
callbacks: {
async session({ session, user, token }) {
if (user) {
session.user = {
...session.user,
role: user.role,
};
}
if (token) {
session.user = {
...session.user,
role: String(token[AUTH_ROLE_CLAIM] || 'FREE'),
};
}
return session;
},
async jwt({ token, user }) {
if (user?.role) {
token[AUTH_ROLE_CLAIM] = user.role;
}
return token;
},
},
session: {
strategy: 'jwt',
maxAge: 60 * 60 * 24 * 14,
},
pages: {
signIn: '/paywall',
},
secret: process.env.NEXTAUTH_SECRET,
});
export const { auth, signIn, signOut, handlers } = handlers;