ASVS 5.0 V10.5.4 (Level 2) requires the client to confirm that the ID Token was meant for it, by checking that the aud claim equals the client's own client_id.
Why it matters
A provider signs tokens for many applications. A token issued for app A is validly signed, but it must not be accepted by app B. Without the audience check, a malicious app can take a user's token from a login to it and replay it against your app to sign in as that user.
How to implement it
Most libraries take the audience as a validation option. Always set it.
import jwt # PyJWT
claims = jwt.decode(
id_token,
key=signing_key,
algorithms=["RS256"],
audience=CLIENT_ID,
issuer=EXPECTED_ISSUER,
)
If aud is a list, the client ID must be among the values. When there are several audiences, also check azp equals your client ID, as the OIDC spec directs.
How to test it
Mint a token with a valid signature but a different aud using a test provider and send it to the callback. Expect rejection. Do the same with a missing aud. Add a test where aud is a list that includes your ID, which should pass.
Related checks
The audience check is one of several. Verify the signature using the provider's published keys, check that the issuer equals your pinned value, check expiry, and validate the nonce. A token that passes only some of these can still be abused. Write a single validation function used by every login path, so no route skips a step.
Common mistakes
verify_aud=Falsecopied from a tutorial.- Checking the issuer and signature but never the audience.
- Using the API's audience value for the ID Token.
Quick check
What if aud holds several values?
Your client ID must be one of them, and the azp claim should name your client.