Safeguard
Application Security•

ASVS 5.0 V6.8.4: Verify Authentication Strength From the IdP

When a function needs strong or recent authentication, check acr, amr and auth_time from the IdP, or document a fallback that assumes the weakest method. Level 2.

Safeguard Security Team
3 min read

ASVS 5.0 V6.8.4 says that if your application uses a separate identity provider and expects a certain authentication strength, method or recentness for specific functions, it must verify that using information returned by the IdP. With OIDC that means claims such as acr, amr and auth_time. If the IdP does not provide this data, you need a documented fallback that assumes the minimum strength method was used. It is a Level 2 requirement.

Why it matters

A valid login does not mean a strong login. A user may have signed in with a password this morning, while changing a payout account needs MFA from the last few minutes. If the app trusts "the user is authenticated" for everything, an attacker with a stolen session or a weak sign in reaches the sensitive actions.

How to implement it

Decide per function what you require, ask the IdP for it, then check the returned token.

  1. Request it. Send acr_values and max_age in the authorization request for sensitive operations.
  2. Verify it. After validating the ID token signature (V6.8.2), read the claims and compare.
  3. Step up. If the claims fall short, send the user back to the IdP.
REQUIRED = {
    "change_payout": {"acr": {"urn:mfa"}, "max_age": 300},
    "view_profile":  {"acr": None,        "max_age": None},
}

def authorize(action, claims):
    need = REQUIRED[action]
    if need["acr"] and claims.get("acr") not in need["acr"]:
        return step_up(action, acr_values=" ".join(need["acr"]))
    if need["max_age"]:
        auth_time = claims.get("auth_time")
        if auth_time is None or time.time() - auth_time > need["max_age"]:
            return step_up(action, max_age=need["max_age"])
    return allow()

Be careful with amr: it lists methods used, such as pwd or otp. Check for the combination you need and do not treat it as proof when the IdP is not trusted to set it.

If the IdP gives no acr, amr or auth_time, document the fallback and implement it. For example, assume single factor password and require your own step up before the sensitive action. Write that decision in the design notes so reviewers can confirm it.

How to test it

  1. Sign in with a password only user and call a protected function that needs MFA. You should be sent to step up.
  2. Sign in with MFA, wait beyond max_age, and try again.
  3. Alter the token claims and confirm signature validation fails first.
  4. Point the app at a test IdP that omits the claims and confirm the fallback applies.

Common mistakes

  • Trusting a login without checking its strength.
  • Reading acr from an unverified token.
  • Missing auth_time treated as fresh.
  • Hard coding an ACR string the IdP never sends, so the check always fails open or closed without notice.

Quick check

The IdP returns no acr claim. Is the user considered MFA authenticated?

No. Without evidence, assume the weakest method and step up in your app.

What does auth_time tell you?

When the user last actively authenticated at the IdP, which lets you require recent sign in for risky actions.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.