import { Router, Request, Response, NextFunction } from 'express'; import jwt from 'jsonwebtoken'; import { AppError, ok } from '../types/index'; import { authMiddleware } from '../middleware/authMiddleware'; export const authRouter = Router(); // secure:true requires HTTPS — for plain-HTTP homelab installs (Unraid, etc.) // this must be false so the browser actually sends the cookie back. // Set COOKIE_SECURE=true in your env only if you're behind an HTTPS reverse proxy. const COOKIE_OPTS = { httpOnly: true, sameSite: 'strict' as const, secure: process.env.COOKIE_SECURE === 'true', path: '/', }; authRouter.post('/login', (req: Request, res: Response, next: NextFunction) => { try { const { username, password } = req.body as { username?: string; password?: string }; if (!username || !password) { throw new AppError('Username and password are required', 400, 'MISSING_FIELDS'); } const adminUsername = process.env.ADMIN_USERNAME; const adminPassword = process.env.ADMIN_PASSWORD; if (!adminUsername || !adminPassword) { throw new AppError('Server not configured: admin credentials missing', 500, 'CONFIG_ERROR'); } if (username !== adminUsername || password !== adminPassword) { throw new AppError('Invalid username or password', 401, 'INVALID_CREDENTIALS'); } const secret = process.env.JWT_SECRET; if (!secret) throw new AppError('Server not configured: JWT_SECRET missing', 500, 'CONFIG_ERROR'); const token = jwt.sign({ sub: 'admin' }, secret, { expiresIn: (process.env.JWT_EXPIRY ?? '8h') as jwt.SignOptions['expiresIn'], }); res.cookie('token', token, COOKIE_OPTS); res.json(ok({ success: true })); } catch (e) { next(e); } }); authRouter.post('/logout', (_req: Request, res: Response) => { res.clearCookie('token', COOKIE_OPTS); res.json(ok({ success: true })); }); authRouter.get('/me', authMiddleware, (_req: Request, res: Response) => { res.json(ok({ authenticated: true })); });