Separate Admin JWT Secret
Admin routes use a completely separate ADMIN_JWT_SECRET from user JWTs. Even if a user token is compromised, it cannot be used to access admin endpoints.
# .env — use a strong, unique secret (minimum 64 characters)
ADMIN_JWT_SECRET=$(openssl rand -hex 32)
ADMIN_SEED_EMAIL=admin@yourcompany.com
ADMIN_SEED_PASSWORD=use-a-very-strong-password-here
IP Allowlisting via Nginx
location /api/admin/ {
allow 203.0.113.10; # your office IP
allow 198.51.100.5; # your home IP
deny all;
proxy_pass http://localhost:3002;
}
Admin Panel (port 5101) Firewall
# Only expose admin panel to your VPN or trusted IPs
ufw allow from 203.0.113.0/24 to any port 5101
ufw deny 5101
Audit Logging
Every admin action (fee change, RPC update, withdrawal approval) should be logged with timestamp, admin ID, and action details. Consider adding an admin_audit_log table to the migration set.
Session Expiry
Admin JWT tokens should have short expiry (2–4 hours). Implement token refresh to maintain session without re-login, but require re-authentication for sensitive operations like adding withdrawal wallets.
2FA Recommendation
The current codebase does not include TOTP 2FA out of the box. For production, add TOTP via the otplib package. Require 2FA for all admin logins — a compromised admin account gives access to all merchant data.