← back to Dw Boardroom Governance
src/api/middleware/auth.ts
41 lines
import { Request, Response, NextFunction } from 'express';
import { timingSafeEqual } from 'crypto';
function safeEqual(a: string, b: string): boolean {
const bufA = Buffer.from(a);
const bufB = Buffer.from(b);
// timingSafeEqual requires equal-length buffers; bail early on mismatch.
if (bufA.length !== bufB.length) return false;
return timingSafeEqual(bufA, bufB);
}
export function authMiddleware(req: Request, res: Response, next: NextFunction): void {
const auth = req.headers.authorization;
if (!auth || !auth.startsWith('Basic ')) {
res.setHeader('WWW-Authenticate', 'Basic realm="DW Governance"');
res.status(401).json({ error: 'Authentication required' });
return;
}
const token = auth.split(' ')[1] || '';
const decoded = Buffer.from(token, 'base64').toString();
// Split on the first colon only — passwords may legitimately contain colons.
const sep = decoded.indexOf(':');
const user = sep >= 0 ? decoded.slice(0, sep) : '';
const pass = sep >= 0 ? decoded.slice(sep + 1) : '';
const expectedUser = process.env.AUTH_USER;
const expectedPass = process.env.AUTH_PASS;
// Fail closed if server credentials are not configured.
if (expectedUser && expectedPass &&
safeEqual(user, expectedUser) && safeEqual(pass, expectedPass)) {
next();
return;
}
res.setHeader('WWW-Authenticate', 'Basic realm="DW Governance"');
res.status(401).json({ error: 'Invalid credentials' });
}