Require two-factor authentication for admins and supervisors

Admins and supervisors without 2FA are sent a code at their next login,
and verifying it turns 2FA on. They can change the channel but not turn
it off. Older sessions without 2FA are rejected with TWO_FACTOR_REQUIRED,
and promoting a user ends their sessions so they enrol at next login.
The requirement is skipped when no email or WhatsApp channel can deliver
a code, and TWO_FACTOR_REQUIRED_ROLES=false switches it off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-19 11:00:12 +02:00
co-authored by Claude Opus 5.5
parent 0306c4dcb1
commit c3012cb3f6
21 changed files with 356 additions and 55 deletions
@@ -172,7 +172,9 @@ const setupRegister = async (req, res) => {
},
});
const token = generateToken(user.id, user.role, user.tokenVersion ?? 0);
// Marked as a setup token so the 2FA requirement doesn't block the rest of the
// wizard; the admin enrols at their first normal login.
const token = generateToken(user.id, user.role, user.tokenVersion ?? 0, { setup: true });
res.json({ token, name: user.name, email: user.email });
} catch (e) {
res.status(res.statusCode === 200 ? 400 : res.statusCode).json({ message: safeErrorMessage(e) });