43 lines
1.3 KiB
TypeScript
43 lines
1.3 KiB
TypeScript
import { Request, Response, NextFunction } from "express";
|
|
import jwt from "jsonwebtoken";
|
|
|
|
const JWT_SECRET = process.env.JWT_SECRET || "pettalk-dev-secret-change-in-production";
|
|
|
|
// Public routes that don't require authentication
|
|
const PUBLIC_ROUTES = [
|
|
{ method: "POST", path: "/api/register" },
|
|
{ method: "POST", path: "/api/login" },
|
|
{ method: "GET", path: "/api/health" },
|
|
];
|
|
|
|
export function authMiddleware(req: Request, res: Response, next: NextFunction) {
|
|
// Skip auth for public routes
|
|
const isPublic = PUBLIC_ROUTES.some(
|
|
(r) => r.method === req.method && req.path === r.path
|
|
);
|
|
if (isPublic) {
|
|
return next();
|
|
}
|
|
|
|
// Also skip non-API routes (static files, SPA routes)
|
|
if (!req.path.startsWith("/api/")) {
|
|
return next();
|
|
}
|
|
|
|
const authHeader = req.headers.authorization;
|
|
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
return res.status(401).json({ error: "Authentication required." });
|
|
}
|
|
|
|
const token = authHeader.split(" ")[1];
|
|
|
|
try {
|
|
const decoded = jwt.verify(token, JWT_SECRET) as { userId: number; email: string };
|
|
(req as any).userId = decoded.userId;
|
|
(req as any).userEmail = decoded.email;
|
|
next();
|
|
} catch (err) {
|
|
return res.status(401).json({ error: "Invalid or expired token." });
|
|
}
|
|
}
|