mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
155 lines
4.5 KiB
TypeScript
155 lines
4.5 KiB
TypeScript
import NextAuth, { NextAuthOptions } from "next-auth";
|
|
import GoogleProvider from "next-auth/providers/google";
|
|
import AzureADB2CProvider from "next-auth/providers/azure-ad-b2c";
|
|
import CredentialsProvider from "next-auth/providers/credentials";
|
|
|
|
import { db } from "@/app/db/db";
|
|
import { user as userTable, User } from "@/app/db/schema/users";
|
|
import { eq } from "drizzle-orm";
|
|
|
|
const { GOOGLE_CLIENT_ID = "", GOOGLE_CLIENT_SECRET = "" } = process.env;
|
|
const {
|
|
AZURE_AD_B2C_TENANT_NAME = "",
|
|
AZURE_AD_B2C_CLIENT_ID = "",
|
|
AZURE_AD_B2C_CLIENT_SECRET = "",
|
|
AZURE_AD_B2C_PRIMARY_USER_FLOW = "",
|
|
} = process.env;
|
|
|
|
type OauthProvider = "google";
|
|
|
|
// TODO: handle token expiration
|
|
// https://next-auth.js.org/v3/tutorials/refresh-token-rotation
|
|
// propertly set options too
|
|
// https://next-auth.js.org/configuration/options
|
|
|
|
export const AuthOptions: NextAuthOptions = {
|
|
providers: [
|
|
GoogleProvider({
|
|
clientId: GOOGLE_CLIENT_ID,
|
|
clientSecret: GOOGLE_CLIENT_SECRET,
|
|
authorization: {
|
|
params: {
|
|
access_type: "offline",
|
|
prompt: "consent",
|
|
response_type: "code",
|
|
},
|
|
},
|
|
}),
|
|
AzureADB2CProvider({
|
|
tenantId: AZURE_AD_B2C_TENANT_NAME,
|
|
clientId: AZURE_AD_B2C_CLIENT_ID,
|
|
clientSecret: AZURE_AD_B2C_CLIENT_SECRET,
|
|
primaryUserFlow: AZURE_AD_B2C_PRIMARY_USER_FLOW,
|
|
authorization: {
|
|
params: {
|
|
scope: "openid profile offline_access",
|
|
prompt: "login",
|
|
},
|
|
},
|
|
}),
|
|
CredentialsProvider({
|
|
name: "Email Login",
|
|
credentials: {
|
|
email: {
|
|
label: "Email",
|
|
type: "email",
|
|
},
|
|
},
|
|
async authorize(credentials, req) {
|
|
if (!credentials || !credentials.email) {
|
|
throw new Error("Email is required");
|
|
}
|
|
|
|
const { email } = credentials;
|
|
|
|
// Query the database to find the user by email
|
|
const dbUser = await db
|
|
.select()
|
|
.from(userTable)
|
|
.where(eq(userTable.email, email));
|
|
|
|
// If the email exists, return the user object (no password check)
|
|
if (dbUser.length === 1) {
|
|
return {
|
|
id: dbUser[0].id.toString(), // Convert bigint to string to avoid serialization issues
|
|
email: dbUser[0].email,
|
|
dbId: dbUser[0].id.toString(), // Ensure dbId is added and is a string
|
|
};
|
|
}
|
|
|
|
return null;
|
|
},
|
|
}),
|
|
],
|
|
pages: {
|
|
signIn: "/",
|
|
},
|
|
callbacks: {
|
|
async signIn({ user, account }) {
|
|
try {
|
|
if (user === null || user.email === null) {
|
|
return "/beta";
|
|
}
|
|
const dbUser: User[] = await db
|
|
.select()
|
|
.from(userTable)
|
|
.where(eq(userTable.email, String(user.email)));
|
|
|
|
if (dbUser.length > 1) {
|
|
console.error(`Multiple users found with email ${user.email}`);
|
|
return false;
|
|
}
|
|
|
|
if (dbUser.length === 0 || account === null) {
|
|
return "/beta";
|
|
}
|
|
|
|
if (!dbUser[0].oauthId) {
|
|
// We make a second query to populate the oauthId and oauthProvider
|
|
console.log("Updating user with oauthId and oauthProvider");
|
|
const provider = account.provider as OauthProvider;
|
|
|
|
await db
|
|
.update(userTable)
|
|
.set({ oauthId: user.id, oauthProvider: provider })
|
|
.where(eq(userTable.email, String(user.email)));
|
|
|
|
console.log("Updated oauthId and oauthProvider");
|
|
}
|
|
|
|
// Set the user's ID from your database
|
|
// Because bigint isn't serializable, we need to convert it to a string
|
|
user.dbId = dbUser[0].id.toString();
|
|
return true;
|
|
} catch (error) {
|
|
console.error("Error during sign-in: ", error);
|
|
return false;
|
|
}
|
|
},
|
|
async jwt({ token, user }) {
|
|
// This is executed whenever a JWT is created or refreshed.
|
|
// `user` is the object returned from `signIn` callback and
|
|
// is only available during sign in, which is why we need to
|
|
// store the id in the token and then read it back into the session.
|
|
if (user?.dbId) {
|
|
token.dbId = user.dbId;
|
|
}
|
|
return token;
|
|
},
|
|
async session({ session, token }) {
|
|
if (session?.user) {
|
|
session.user.dbId = token.dbId;
|
|
}
|
|
|
|
return session;
|
|
},
|
|
async redirect({ baseUrl }) {
|
|
const redirectUrl = baseUrl + "/home";
|
|
return redirectUrl;
|
|
},
|
|
},
|
|
};
|
|
|
|
const handler = NextAuth(AuthOptions);
|
|
|
|
export { handler as GET, handler as POST };
|