Safeguard
Application Security•

ASVS 5.0 V7.6.1: Make RP and IdP Sessions Behave as Documented

ASVS V7.6.1 requires session lifetime and termination between relying parties and identity providers to match the docs, with reauthentication when needed.

Safeguard Security Team
4 min read

ASVS 5.0 V7.6.1 (Level 2) requires that session lifetime and termination between relying parties (RPs) and identity providers (IdPs) behave as you documented them, and that reauthentication is forced when needed, for example when the maximum time between IdP authentication events is reached.

Why it matters

Federation multiplies sessions. A user has one at the IdP and one per application. Each has its own timers. If the application keeps its own session regardless of what the IdP says, then disabling a user centrally, or reaching the IdP's maximum age, changes nothing where it counts.

V7.1.3 asks you to write down the design. This requirement asks you to prove the running system matches it.

How to implement it

Treat the IdP's authentication time as an input to the application session, not a one off event.

With OpenID Connect, request and verify the authentication time:

// when starting login, ask for a fresh enough authentication
const url = client.authorizationUrl({
  scope: "openid profile",
  max_age: 28800,         // 8 hours: IdP authentication must be no older
  state, nonce,
});

// after the callback, verify the ID token claims
const claims = tokenSet.claims();
if (Date.now() / 1000 - claims.auth_time > 28800) {
  throw new Error("IdP authentication too old");
}

Then on each request, or at least periodically, compare session age to the policy. If the policy says reauthenticate with the IdP after 8 hours, redirect the user to the IdP with a prompt for fresh authentication when the limit hits.

Handle termination in both directions:

  • IdP to RP: implement back channel logout so that when the IdP session ends, the RP receives a signed logout token and revokes the matching local session.
  • RP to IdP: decide whether local logout also ends the IdP session, and implement RP initiated logout if so.
# back channel logout endpoint (sketch)
@app.post("/oidc/backchannel-logout")
def backchannel_logout(logout_token: str = Form(...)):
    claims = verify_logout_token(logout_token)   # signature, iss, aud, events claim
    db.execute("UPDATE sessions SET revoked = 1 WHERE idp_sid = ? OR user_sub = ?",
               (claims.get("sid"), claims.get("sub")))
    return Response(status_code=200)

Store the IdP session id (the sid claim) when you create the local session so logout can find it. For SAML, use the equivalent single logout and session index values.

How to test it

Use the table from your V7.1.3 documentation as the test plan. For each row:

  1. Sign in through the IdP and note the times.
  2. End the IdP session in the IdP's console and check how fast the application rejects the user. Compare with the documented behavior.
  3. Let the IdP maximum age pass while the user stays active in the application. Confirm a redirect for fresh authentication.
  4. Log out in the application and check whether the IdP session ends, as documented.
  5. Disable the user at the IdP and check the application.

Capture the results with timestamps and keep them as evidence.

Common mistakes

  • Verifying the ID token once and never looking at auth_time again.
  • Back channel logout configured at the IdP but the endpoint is not registered or fails signature checks silently.
  • Applications that mint their own long session and ignore the IdP policy.
  • Documentation that says "single logout" when only front channel logout exists, which fails when the browser tab is closed.
  • No monitoring of logout endpoint failures.

Quick check

What if the IdP does not support back channel logout?

Document the gap, shorten the application session lifetime, and check the IdP session state periodically with silent checks or token introspection where available.

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.