import type { Express } from "express";
import { authStorage } from "./storage";
import { isAuthenticated } from "./replitAuth";
import bcrypt from "bcryptjs";
import { z } from "zod";
const registerSchema = z.object({
email: z.string().email("Invalid email address"),
password: z.string().min(8, "Password must be at least 8 characters"),
firstName: z.string().min(1, "First name is required"),
lastName: z.string().min(1, "Last name is required"),
});
const loginSchema = z.object({
email: z.string().email("Invalid email address"),
password: z.string().min(1, "Password is required"),
});
export function registerAuthRoutes(app: Express): void {
app.post("/api/auth/register", async (req: any, res) => {
try {
const parsed = registerSchema.safeParse(req.body);
if (!parsed.success) {
return res.status(400).json({
message: "Validation failed",
errors: parsed.error.flatten().fieldErrors,
});
}
const { email, password, firstName, lastName } = parsed.data;
const existing = await authStorage.getUserByEmail(email);
if (existing) {
const cred = await authStorage.getCredential(existing.id, "local");
if (cred) {
return res.status(409).json({ message: "An account with this email already exists" });
}
}
const salt = await bcrypt.genSalt(12);
const passwordHash = await bcrypt.hash(password, salt);
let user;
if (existing) {
user = existing;
} else {
user = await authStorage.upsertUser({
email,
firstName,
lastName,
});
}
if (!user) {
console.error("User creation failed - upsertUser returned:", user);
return res.status(500).json({ message: "Failed to create user account" });
}
await authStorage.createCredential({
userId: user.id,
provider: "local",
passwordHash,
});
req.login(
{
claims: {
sub: user.id,
email: user.email,
first_name: user.firstName,
last_name: user.lastName,
},
expires_at: Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60,
},
(err: any) => {
if (err) {
console.error("Login after register failed:", err);
return res.status(500).json({ message: "Registration succeeded but login failed" });
}
return res.json({
id: user.id,
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
profileImageUrl: user.profileImageUrl,
createdAt: user.createdAt,
updatedAt: user.updatedAt,
});
}
);
} catch (error) {
console.error("Registration error:", error);
res.status(500).json({ message: "Registration failed" });
}
});
app.post("/api/auth/login", async (req: any, res) => {
try {
const parsed = loginSchema.safeParse(req.body);
if (!parsed.success) {
return res.status(400).json({
message: "Validation failed",
errors: parsed.error.flatten().fieldErrors,
});
}
const { email, password } = parsed.data;
const result = await authStorage.getCredentialByEmail(email, "local");
if (!result || !result.credential.passwordHash) {
return res.status(401).json({ message: "Invalid email or password" });
}
const isValid = await bcrypt.compare(password, result.credential.passwordHash);
if (!isValid) {
return res.status(401).json({ message: "Invalid email or password" });
}
const user = result.user;
req.login(
{
claims: {
sub: user.id,
email: user.email,
first_name: user.firstName,
last_name: user.lastName,
},
expires_at: Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60,
},
(err: any) => {
if (err) {
console.error("Login failed:", err);
return res.status(500).json({ message: "Login failed" });
}
return res.json({
id: user.id,
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
profileImageUrl: user.profileImageUrl,
createdAt: user.createdAt,
updatedAt: user.updatedAt,
});
}
);
} catch (error) {
console.error("Login error:", error);
res.status(500).json({ message: "Login failed" });
}
});
app.get("/api/auth/user", async (req: any, res) => {
try {
if (!req.isAuthenticated || !req.isAuthenticated() || !req.user?.claims?.sub) {
return res.status(401).json({ message: "Unauthorized" });
}
const userId = req.user.claims.sub;
const user = await authStorage.getUser(userId);
if (!user) {
return res.status(404).json({ message: "User not found" });
}
res.json(user);
} catch (error) {
console.error("Error fetching user:", error);
res.status(500).json({ message: "Failed to fetch user" });
}
});
app.get("/api/users", isAuthenticated, async (req: any, res) => {
try {
const users = await authStorage.getAllUsers();
res.json(users);
} catch (error) {
console.error("Error fetching users:", error);
res.status(500).json({ message: "Failed to fetch users" });
}
});
app.post("/api/auth/logout", (req: any, res) => {
req.logout(() => {
req.session.destroy((err: any) => {
if (err) {
console.error("Session destroy error:", err);
}
res.clearCookie("connect.sid");
res.json({ message: "Logged out successfully" });
});
});
});
}