Force MFA enrollment for specific roles
Require certain users to enroll MFA before they can complete login
Admin accounts and high-privilege users should be required to use MFA. Out of the box, Olympus makes MFA optional. This recipe makes it mandatory for users with a specific role.
Approach
After login, check: does the user's role trait require MFA? Are they enrolled?
If required but not enrolled → redirect to enrollment.
Configuration
In kratos.yml
selfservice:
flows:
login:
after:
password:
hooks:
- hook: web_hook
config:
url: https://your-backend/internal/check-mfa-required
method: POST
body: file:///etc/config/kratos/hooks/check-mfa.jsonnet
response:
ignore: false
parse: truehooks/check-mfa.jsonnet:
local identity = std.extVar('identity');
local flow = std.extVar('flow');
{
identity_id: identity.id,
role: identity.traits.role,
has_totp: 'totp' in (identity.credentials | default { }),
has_webauthn: 'webauthn' in (identity.credentials | default { }),
}Your backend
// POST /internal/check-mfa-required
export async function POST(request: Request) {
const { identity_id, role, has_totp, has_webauthn } = await request.json();
const mfaRequiredRoles = ["admin", "operator", "support"];
if (!mfaRequiredRoles.includes(role)) {
return Response.json({ allowed: true });
}
if (has_totp || has_webauthn) {
return Response.json({ allowed: true });
}
// Force redirect to settings → enroll MFA
return Response.json({
allowed: false,
redirect_to: `https://iam.your-domain/settings?force_mfa=true`,
});
}The Kratos hook with response.parse: true lets your webhook redirect the flow.
Alternative: enforce in your app
If you don't want to maintain a Kratos webhook, do it in your app:
// app/layout.tsx or middleware
export async function middleware(req: Request) {
const session = await getSession(req);
if (!session) return; // not logged in; let normal flow handle
const requiresMfa = ["admin", "operator"].includes(session.role);
if (requiresMfa && !session.has_mfa) {
return Response.redirect(`/settings?force_mfa=true`);
}
}Simpler but means each app must check. The webhook approach centralizes in Kratos.
Grace period
Hard-forcing on first login frustrates users who didn't expect it. Add a grace period:
- Allow N days from role assignment to enroll.
- Send daily reminder emails during the grace period.
- After N days, block login until enrolled.
Track in a settings vault entry: mfa.grace_period_days, mfa.enforcement_date.