46 lines
1.3 KiB
JavaScript
46 lines
1.3 KiB
JavaScript
import { AppError } from '../lib/errors.js';
|
|
import { can } from '../services/policy.js';
|
|
import { verifyFirebaseToken } from '../services/firebase-auth.js';
|
|
|
|
function getBearerToken(header) {
|
|
if (!header) return null;
|
|
const [scheme, token] = header.split(' ');
|
|
if (!scheme || scheme.toLowerCase() !== 'bearer' || !token) return null;
|
|
return token;
|
|
}
|
|
|
|
export async function requireAuth(req, _res, next) {
|
|
try {
|
|
const token = getBearerToken(req.get('Authorization'));
|
|
if (!token) {
|
|
throw new AppError('UNAUTHENTICATED', 'Missing bearer token', 401);
|
|
}
|
|
|
|
if (process.env.AUTH_BYPASS === 'true') {
|
|
req.actor = { uid: 'test-user', email: 'test@krow.local', role: 'TEST' };
|
|
return next();
|
|
}
|
|
|
|
const decoded = await verifyFirebaseToken(token);
|
|
req.actor = {
|
|
uid: decoded.uid,
|
|
email: decoded.email || null,
|
|
role: decoded.role || null,
|
|
};
|
|
|
|
return next();
|
|
} catch (error) {
|
|
if (error instanceof AppError) return next(error);
|
|
return next(new AppError('UNAUTHENTICATED', 'Token verification failed', 401));
|
|
}
|
|
}
|
|
|
|
export function requirePolicy(action, resource) {
|
|
return (req, _res, next) => {
|
|
if (!can(action, resource, req.actor)) {
|
|
return next(new AppError('FORBIDDEN', 'Not allowed to perform this action', 403));
|
|
}
|
|
return next();
|
|
};
|
|
}
|