Safeguard
Security Guides•

OIDC ID token validation steps: a checklist for relying parties

What an app must check before trusting an OpenID Connect ID token: issuer, audience, signature, expiry, nonce and more, in the order the spec lists.

Safeguard Security Team
3 min read

Before trusting an ID token, an app must check that the issuer matches, the audience contains its own client ID, the signature verifies with the expected algorithm, the token has not expired, and the nonce matches the one it sent. Skipping any of these can let a token meant for someone else log a user in.

Checklist

These follow section 3.1.3.7 of OpenID Connect Core.

  1. Decrypt the token if it is encrypted.
  2. Issuer. The iss must exactly match the issuer you expect for this provider.
  3. Audience. aud must contain your client_id. Reject if your client is not listed, or if audiences you do not trust are present.
  4. Authorized party. If azp is present, it should equal your client_id.
  5. Signature. Verify the JWS using the issuer's keys. When the token arrives directly from the token endpoint over TLS, the spec allows TLS server validation to stand in for the signature check. Verifying anyway is safer and cheap.
  6. Algorithm. Expect RS256 or the algorithm your client registered. Do not accept whatever the token header claims.
  7. Expiry. The current time must be before exp.
  8. Issued at. Use iat to reject tokens issued too long ago. The acceptable window is up to you.
  9. Nonce. If you sent a nonce, the token must carry the same value. Check for replay.
  10. Authentication context. If you requested acr, confirm the value is appropriate.
  11. Auth time. If you requested auth_time or set max_age, check it, and ask the user to sign in again when too much time has passed.

Why each check exists

The iss check stops a token from a different provider being accepted. The aud check stops a token issued to another application, possibly one a user signed in to legitimately, from working on yours. The algorithm check blocks downgrade tricks, including the well known case where a token claims none or switches between asymmetric and symmetric algorithms.

The nonce binds the token to the browser session that started the login. It is required for the implicit flow and for hybrid flows that return an ID token from the authorization endpoint. Use it in the code flow too.

Use a library, then test it

Do not hand roll this. Use a maintained OIDC client library and configure it with the expected issuer, your client ID and a fixed algorithm list. Then write tests that feed it:

  • a token with the wrong issuer
  • a token with another client's audience
  • an expired token
  • an unsigned token
  • a token with a changed nonce

All of them must be rejected.

Keys and rotation

Fetch signing keys from the provider's published key set rather than hard coding them, cache with a sensible lifetime, and refresh when you see an unknown key ID. Rate limit refreshes so a flood of bad tokens cannot make you hammer the provider. For general JWT rules, see the RFC 8725 checklist.

Quick check

Is the access token validated the same way?

No. The ID token is for your app. The access token is for the API, and the API validates it, either locally or by asking the authorization server.

Do I need the nonce in the authorization code flow?

The spec requires it for implicit and some hybrid flows. It is still a good defense for the code flow, so most libraries send it.

Sources

Last reviewed: 19 October 2026.

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.