collab/auth.jsblame
View source
2a9592c1const jwt = require("jsonwebtoken");
2a9592c2const cookie = require("cookie");
2a9592c3
2a9592c4const JWT_SECRET = process.env.JWT_SECRET || "grove-dev-secret";
2a9592c5
2a9592c6function verifyToken(token) {
2a9592c7 return jwt.verify(token, JWT_SECRET);
2a9592c8}
2a9592c9
2a9592c10function extractToken(req) {
2a9592c11 // 1. Authorization header
2a9592c12 const authHeader = req.headers?.authorization;
2a9592c13 if (authHeader && authHeader.startsWith("Bearer ")) {
2a9592c14 return authHeader.slice(7);
2a9592c15 }
2a9592c16 // 2. Cookie
2a9592c17 const cookieHeader = req.headers?.cookie;
2a9592c18 if (cookieHeader) {
2a9592c19 const cookies = cookie.parse(cookieHeader);
2a9592c20 if (cookies.grove_hub_token) return cookies.grove_hub_token;
2a9592c21 }
2a9592c22 return null;
2a9592c23}
2a9592c24
2a9592c25// Express middleware
2a9592c26function requireAuth(req, res, next) {
2a9592c27 const token = extractToken(req);
2a9592c28 if (!token) return res.status(401).json({ error: "Unauthorized" });
2a9592c29 try {
2a9592c30 req.user = verifyToken(token);
2a9592c31 req.token = token;
2a9592c32 next();
2a9592c33 } catch {
2a9592c34 return res.status(401).json({ error: "Unauthorized" });
2a9592c35 }
2a9592c36}
2a9592c37
2a9592c38// Socket.IO middleware for /collab namespace
2a9592c39function socketAuth(socket, next) {
2a9592c40 // 1. Handshake auth (client passes { auth: { token } })
2a9592c41 let token = socket.handshake.auth?.token;
2a9592c42 // 2. Fallback to cookie
2a9592c43 if (!token) {
2a9592c44 const cookieHeader = socket.handshake.headers?.cookie;
2a9592c45 if (cookieHeader) {
2a9592c46 const cookies = cookie.parse(cookieHeader);
2a9592c47 token = cookies.grove_hub_token;
2a9592c48 }
2a9592c49 }
2a9592c50 if (!token) return next(new Error("unauthorized"));
2a9592c51 try {
2a9592c52 socket.user = verifyToken(token);
2a9592c53 socket.token = token;
2a9592c54 next();
2a9592c55 } catch {
2a9592c56 return next(new Error("unauthorized"));
2a9592c57 }
2a9592c58}
2a9592c59
515cc6860// Like requireAuth but does not reject — just attaches user/token if present.
515cc6861function optionalAuth(req, res, next) {
515cc6862 const token = extractToken(req);
515cc6863 if (token) {
515cc6864 try {
515cc6865 req.user = verifyToken(token);
515cc6866 req.token = token;
515cc6867 } catch {
515cc6868 // invalid token — treat as unauthenticated
515cc6869 }
515cc6870 }
515cc6871 next();
515cc6872}
515cc6873
515cc6874module.exports = { verifyToken, extractToken, requireAuth, optionalAuth, socketAuth };