mirror of
https://github.com/kjanat/livedash-node.git
synced 2026-01-16 08:52:10 +01:00
- Fix cookie isolation between regular and platform authentication systems - Add custom cookie names for regular auth (app-auth.session-token) vs platform auth (platform-auth.session-token) - Remove restrictive cookie path from platform auth to allow proper session access - Create custom usePlatformSession hook to bypass NextAuth useSession routing issues - Fix platform dashboard authentication and eliminate redirect loops - Add proper NEXTAUTH_SECRET configuration - Enhance platform login with autocomplete attributes - Update TODO with PR #20 feedback actions and mark platform features complete The platform management dashboard now has fully functional authentication with proper session isolation between regular users and platform admins.
117 lines
2.6 KiB
TypeScript
117 lines
2.6 KiB
TypeScript
import { NextAuthOptions } from "next-auth";
|
|
import CredentialsProvider from "next-auth/providers/credentials";
|
|
import { prisma } from "./prisma";
|
|
import bcrypt from "bcryptjs";
|
|
|
|
// Define the shape of the JWT token
|
|
declare module "next-auth/jwt" {
|
|
interface JWT {
|
|
companyId: string;
|
|
role: string;
|
|
}
|
|
}
|
|
|
|
// Define the shape of the session object
|
|
declare module "next-auth" {
|
|
interface Session {
|
|
user: {
|
|
id?: string;
|
|
name?: string;
|
|
email?: string;
|
|
companyId?: string;
|
|
role?: string;
|
|
};
|
|
}
|
|
|
|
interface User {
|
|
id: string;
|
|
email: string;
|
|
name?: string;
|
|
companyId: string;
|
|
role: string;
|
|
}
|
|
}
|
|
|
|
export const authOptions: NextAuthOptions = {
|
|
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 },
|
|
include: { company: true },
|
|
});
|
|
|
|
if (!user || !user.hashedPassword) {
|
|
return null;
|
|
}
|
|
|
|
const isPasswordValid = await bcrypt.compare(
|
|
credentials.password,
|
|
user.hashedPassword
|
|
);
|
|
|
|
if (!isPasswordValid) {
|
|
return null;
|
|
}
|
|
|
|
// Check if company is active
|
|
if (user.company.status !== "ACTIVE") {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
id: user.id,
|
|
email: user.email,
|
|
name: user.name,
|
|
companyId: user.companyId,
|
|
role: user.role,
|
|
};
|
|
},
|
|
}),
|
|
],
|
|
session: {
|
|
strategy: "jwt",
|
|
maxAge: 24 * 60 * 60, // 24 hours for regular users
|
|
},
|
|
cookies: {
|
|
sessionToken: {
|
|
name: `app-auth.session-token`,
|
|
options: {
|
|
httpOnly: true,
|
|
sameSite: "lax",
|
|
path: "/",
|
|
secure: process.env.NODE_ENV === "production",
|
|
},
|
|
},
|
|
},
|
|
callbacks: {
|
|
async jwt({ token, user }) {
|
|
if (user) {
|
|
token.companyId = user.companyId;
|
|
token.role = user.role;
|
|
}
|
|
return token;
|
|
},
|
|
async session({ session, token }) {
|
|
if (token && session.user) {
|
|
session.user.companyId = token.companyId;
|
|
session.user.role = token.role;
|
|
}
|
|
return session;
|
|
},
|
|
},
|
|
pages: {
|
|
signIn: "/login",
|
|
},
|
|
secret: process.env.NEXTAUTH_SECRET,
|
|
debug: process.env.NODE_ENV === "development",
|
|
}; |