1 import passport from "passport";
2 import { Strategy as LocalStrategy } from "passport-local";
3 import { Express, RequestHandler } from "express";
4 import session from "express-session";
5 import bcrypt from "bcrypt";
6 import { storage } from "./storage";
7 import { User as SelectUser } from "@shared/schema";
8
9 declare global {
10 namespace Express {
11 interface User extends SelectUser {}
12 }
13 }
14
15 export const isAuthenticated: RequestHandler = (req, res, next) => {
16 if (req.isAuthenticated()) return next();
17 res.status(401).json({ message: "Unauthorized" });
18 };
19
20 export function setupAuth(app: Express) {
21 const sessionSettings: session.SessionOptions = {
22 secret: process.env.SESSION_SECRET || "jcrguru-secret-key",
23 resave: false,
24 saveUninitialized: false,
25 cookie: {
26 secure: process.env.NODE_ENV === "production",
27 maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days
28 },
29 };
30
31 app.set("trust proxy", 1);
32 app.use(session(sessionSettings));
33 app.use(passport.initialize());
34 app.use(passport.session());
35
36 passport.use(
37 new LocalStrategy({ usernameField: "email" }, async (email, password, done) => {
38 try {
39 const user = await storage.getUserByEmail(email);
40 if (!user) {
41 return done(null, false, { message: "Invalid email or password." });
42 }
43
44 const isMatch = await bcrypt.compare(password, user.password);
45 if (!isMatch) {
46 return done(null, false, { message: "Invalid email or password." });
47 }
48
49 return done(null, user);
50 } catch (err) {
51 return done(err);
52 }
53 }),
54 );
55
56 passport.serializeUser((user, done) => {
57 done(null, user.id);
58 });
59
60 passport.deserializeUser(async (id: string, done) => {
61 try {
62 const user = await storage.getUser(id);
63 done(null, user);
64 } catch (err) {
65 done(err);
66 }
67 });
68
69 app.post("/api/register", async (req, res, next) => {
70 try {
71 const { email, password, firstName, lastName } = req.body;
72
73 const existingUser = await storage.getUserByEmail(email);
74 if (existingUser) {
75 return res.status(400).json({ message: "User already exists." });
76 }
77
78 const hashedPassword = await bcrypt.hash(password, 10);
79 const user = await storage.createUser({
80 email,
81 password: hashedPassword,
82 firstName,
83 lastName,
84 role: "user",
85 });
86
87 req.login(user, (err) => {
88 if (err) return next(err);
89 res.status(201).json(user);
90 });
91 } catch (err) {
92 next(err);
93 }
94 });
95
96 app.post("/api/login", passport.authenticate("local"), (req, res) => {
97 res.json(req.user);
98 });
99
100 app.post("/api/logout", (req, res, next) => {
101 req.logout((err) => {
102 if (err) return next(err);
103 res.sendStatus(200);
104 });
105 });
106
107 app.get("/api/user", (req, res) => {
108 if (!req.isAuthenticated()) {
109 return res.status(401).json({ message: "Not authenticated" });
110 }
111 res.json(req.user);
112 });
113 }