-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathadminApi.js
More file actions
82 lines (71 loc) · 2.46 KB
/
adminApi.js
File metadata and controls
82 lines (71 loc) · 2.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
* Admin API authentication middleware.
* Provides dual JWT and session-based authentication for admin API endpoints.
* Verifies that the authenticated user has admin role or admin scope.
*/
import jwt from 'jsonwebtoken';
import { isTokenRevoked } from './jwt.js';
import { getRow } from '../db/authDb.js';
import { JWT_SECRET } from '../config/index.js';
import { isAdmin } from './permissions.js';
import { throwUnauthorized, throwForbidden } from '../middleware/responseHelpers.js';
import logger from '../logging/logger.js';
/**
* Middleware for admin API endpoints that accepts JWT or session auth.
* Verifies the user has admin role or admin scope.
* Returns 401/403 for API calls, redirects for browser requests.
*/
export const authenticateAdminAPI = async (req, res, next) => {
let user = null;
// First try JWT authentication
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (token) {
try {
const payload = jwt.verify(token, JWT_SECRET);
if (payload && !isTokenRevoked(payload.jti)) {
user = payload;
}
} catch {
// JWT invalid or expired, continue to session check
}
}
// Fallback to session authentication
if (!user && req.session && req.session.user) {
const dbUser = await getRow('SELECT id, username, role, scopes FROM users WHERE id = ? AND is_active = TRUE', [req.session.user.id]);
if (dbUser) {
// Parse scopes
const scopes = dbUser.scopes ? dbUser.scopes.split(',').map(s => s.trim()).filter(Boolean) : ['api'];
user = {
user_id: dbUser.id,
username: dbUser.username,
role: dbUser.role || 'user',
scopes: scopes,
scope: dbUser.scopes || 'api',
};
}
}
// No authentication found
if (!user) {
// For API requests (JSON), return 401
if (req.headers.accept && req.headers.accept.includes('application/json')) {
throwUnauthorized('Authentication required');
}
// For browser requests, redirect to login
return res.redirect(`/login?return_to=${encodeURIComponent(req.originalUrl)}`);
}
// Verify admin access
if (!isAdmin(user)) {
logger.warn('Non-admin user attempted admin API access', {
username: user.username,
role: user.role,
scopes: user.scopes || user.scope,
ip: req.ip,
path: req.path,
});
throwForbidden('Admin access required');
}
// Attach user to request
req.user = user;
next();
};