ASVS 5.0 V9.2.4 applies to token issuers. If you use the same private key to issue tokens for different audiences, each token must carry an audience restriction that uniquely identifies its target. If audience values are provisioned dynamically, the issuer must validate them to prevent audience impersonation. It is a Level 2 requirement.
Why it matters
One signing key across many services means a token for any of them verifies at all of them. The audience claim is the only thing separating one service from another. If a client can register or request any audience string it likes, it can ask for a token naming a service it should never reach.
How to implement it
- Always set
audwhen issuing. Never emit a token without it. - Keep a registry of valid audiences and the clients allowed to request each one. Reject unknown or unauthorized values.
- Use full, unique identifiers such as URLs you own, not short names like
api. - Consider separate signing keys per sensitive audience.
function issue(client, requestedAudience) {
const allowed = registry.audiencesFor(client.id);
if (!allowed.includes(requestedAudience)) throw new Error("invalid_target");
return signJwt({ aud: requestedAudience, sub: client.userId, iss: ISSUER });
}
How to test it
Request a token as client X for an audience you did not register. Expect an error. Request one with an audience that differs by case or trailing slash and confirm it is rejected, not normalized into a match.
Common mistakes
- Issuing tokens without
aud. - Echoing any audience a client sends.
- Short, collidable audience names across tenants.
Quick check
Why must dynamic audiences be validated?
Otherwise a client can name a service it is not entitled to reach and receive a token that service will trust.