Policy rules · Policy rules
MFA required for privileged actions
ALLOW only if MFA was completed in the current session AND the OIDC `acr` value indicates a sufficient assurance level. Use it as a step-up gate before any high-risk action.
- gate
- step-up
- mfa
Tested against:policyEngine: 1.0.0
Use case
A privileged action — admin user creation, key rotation, money transfer — must require fresh MFA, not just a valid session. The OIDC acr (Authentication Context Class Reference) carries the assurance level; combine it with a fresh-MFA flag from your session table.
Rule
{
"all": [
{ "fact": "mfa_completed", "operator": "equal", "value": true },
{ "fact": "acr", "operator": "in", "value": ["urn:mace:incommon:iap:silver", "urn:mace:incommon:iap:gold", "loa3", "loa4"] }
]
}Facts shape
data class StepUpFacts(
val mfa_completed: Boolean, // from your session table — true if MFA in last N min
val acr: String, // from the OIDC ID token
)Composition
Wrap this rule around any privileged action:
fun handlePrivilegedAction(ctx: RequestContext): Response {
val decision = policyEngine.evaluate(stepUpRule, ctx.facts())
if (decision != Decision.ALLOW) return Response.stepUpRequired(decision.reason)
// … proceed with the privileged action
}Trace — DENY (MFA stale)
{
"decision": "DENY",
"reason": "mfa_completed expected true, got false (stale: 47 minutes since last MFA)",
"trace": [
{ "all": [
{ "fact": "mfa_completed", "operator": "equal", "value": true, "actual": false, "result": "fail" }
],
"result": "fail"
}
]
}When to use
- High-risk actions inside an authenticated session
- Compliance regimes requiring step-up for specific operations (PSD2, regulated-finance equivalents)
When not to use
- All requests across a surface — that's session-level, not per-action
- Pure account login — handle MFA at the IdP layer, not Policy Engine