import type { GetServerSidePropsContext, NextApiRequest, NextApiResponse, } from "next"; import { NextAuthOptions, getServerSession as internalGetServerSession, } from "next-auth"; import Google from "next-auth/providers/google"; import Credentials from "next-auth/providers/credentials"; import Apple from "next-auth/providers/apple"; import { Redis } from "ioredis"; import AzureADProvider from "next-auth/providers/azure-ad"; const headers = { Authorization: `Token ${process.env.ZAMMAD_API_TOKEN}` }; const fetchRoles = async () => { const url = `${process.env.ZAMMAD_URL}/api/v1/roles`; const res = await fetch(url, { headers }); const roles = await res.json(); const formattedRoles = roles.reduce((acc: any, role: any) => { acc[role.id] = role.name; return acc; }, {}); return formattedRoles; }; const fetchUser = async (email: string) => { const url = `${process.env.ZAMMAD_URL}/api/v1/users/search?query=login:${email}&limit=1`; const res = await fetch(url, { headers }); const users = await res.json(); const user = users?.[0]; return user; }; const getUserRoles = async (email: string) => { try { const user = await fetchUser(email); if (!user) { return []; } const allRoles = await fetchRoles(); const roles = user.role_ids.map((roleID: number) => { const role = allRoles[roleID]; return role ? role.toLowerCase().replace(" ", "_") : null; }); return roles.filter((role: string) => role !== null); } catch (e) { console.error({ e }); return []; } }; const login = async (email: string, password: string) => { const url = `${process.env.ZAMMAD_URL}/api/v1/users/me`; const authorization = "Basic " + Buffer.from(email + ":" + password).toString("base64"); const res = await fetch(url, { headers: { authorization, }, }); const user = await res.json(); if (user && !user.error && user.id) { return user; } else { return null; } }; const providers = []; if (process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET) { providers.push( Google({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }), ); } else if (process.env.APPLE_CLIENT_ID && process.env.APPLE_CLIENT_SECRET) { providers.push( Apple({ clientId: process.env.APPLE_CLIENT_ID, clientSecret: process.env.APPLE_CLIENT_SECRET, }), ); } else if ( process.env.AZURE_AD_CLIENT_ID && process.env.AZURE_AD_CLIENT_SECRET && process.env.AZURE_AD_TENANT_ID ) { providers.push( AzureADProvider({ clientId: process.env.AZURE_AD_CLIENT_ID, clientSecret: process.env.AZURE_AD_CLIENT_SECRET, tenantId: process.env.AZURE_AD_TENANT_ID, }), ); } else { providers.push( Credentials({ name: "Zammad", credentials: { email: { label: "Email", type: "text" }, password: { label: "Password", type: "password" }, }, async authorize(credentials) { const user = await login(credentials.email, credentials.password); if (user) { return user; } else { return null; } }, }), ); } export const authOptions: NextAuthOptions = { pages: { signIn: "/login", error: "/login", signOut: "/logout", }, providers, session: { maxAge: 3 * 24 * 60 * 60, }, secret: process.env.NEXTAUTH_SECRET, callbacks: { signIn: async ({ user }) => { const roles = (await getUserRoles(user.email)) ?? []; return roles.includes("admin") || roles.includes("agent"); }, session: async ({ session, token }) => { // const redis = new Redis(process.env.REDIS_URL); // const isInvalidated = await redis.get(`invalidated:${token.sub}`); // if (isInvalidated) { // return null; // } // @ts-ignore session.user.roles = token.roles ?? []; // @ts-ignore session.user.zammadCsrfToken = token.zammadCsrfToken; return session; }, jwt: async ({ token, user, trigger, session }) => { if (user) { token.roles = (await getUserRoles(user.email)) ?? []; } if (session && trigger === "update") { token.zammadCsrfToken = session.zammadCsrfToken; } return token; }, }, }; export const getServerSession = ( ...args: | [GetServerSidePropsContext["req"], GetServerSidePropsContext["res"]] | [NextApiRequest, NextApiResponse] | [] ) => internalGetServerSession(...args, authOptions);