satupeta-main/auth.ts
2026-02-23 12:21:05 +07:00

133 lines
3.6 KiB
TypeScript
Executable File

/* eslint-disable @typescript-eslint/no-explicit-any */
import NextAuth from "next-auth";
import Credentials from "next-auth/providers/credentials";
import { AdapterUser } from "next-auth/adapters";
interface LoginResponse {
access_token: string;
refresh_token: string;
expires_at: number;
error?: Record<string, unknown>;
message?: string;
}
export const { auth, handlers, signIn, signOut } = NextAuth({
basePath: "/auth",
providers: [
Credentials({
name: "credentials",
credentials: {
username: { label: "Username", type: "text" },
password: { label: "Password", type: "password" },
},
async authorize(credentials) {
try {
const formData = new FormData();
formData.append("username", credentials?.username as string);
formData.append("password", credentials?.password as string);
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/auth/login`,
{
method: "POST",
body: formData,
}
);
const data = (await response.json()) as LoginResponse;
if (!response.ok || data.error) {
throw new Error(data.message ?? "Authentication failed");
}
const userResponse = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/me`,
{
headers: {
Authorization: `Bearer ${data.access_token}`,
},
}
);
const userData = await userResponse.json();
if (!userResponse.ok) {
throw new Error("Failed to fetch user data");
}
return {
id: String(userData.id),
name: userData.name,
email: userData.email,
image: userData.profile_picture,
username: userData.username,
role: userData.role,
organizationId: userData.organization?.id ?? null, // Only store organization ID
access_token: data.access_token,
refresh_token: data.refresh_token,
accessTokenExpires: data.expires_at * 1000,
};
} catch (error) {
console.error("Authentication error:", error);
return null;
}
},
}),
],
callbacks: {
jwt: async ({ token, user }) => {
if (user) {
return {
access_token: user.access_token,
refresh_token: user.refresh_token,
accessTokenExpires: user.accessTokenExpires,
refreshAttempts: 0,
user: {
id: user.id,
name: user.name,
email: user.email,
image: user.image,
username: user.username,
role: user.role,
organizationId: user.organizationId,
},
};
}
if (
typeof token.accessTokenExpires === "number" &&
Date.now() < token.accessTokenExpires
) {
return token;
}
return token;
},
session: async ({ session, token }) => {
session.access_token = token.access_token as string;
session.refresh_token = token.refresh_token as string;
session.error = token.error as string;
session.user = token.user as AdapterUser & {
id: string;
name?: string | null;
email?: string | null;
image?: string | null;
username: string;
role: string;
organizationId?: string | null;
};
return session;
},
},
session: {
strategy: "jwt",
maxAge: 30 * 24 * 60 * 60, // 30 days
},
pages: {
signIn: "admin/login",
error: "admin/login/error",
},
});