ASVS 5.0 V10.2.2 applies when an OAuth client can interact with more than one authorization server. It must defend against mix-up attacks, for example by requiring the server to return the iss parameter and validating it in the authorization response and the token response. It is a Level 2 requirement.
Why it matters
In a mix-up attack, a malicious authorization server tricks the client into sending a code obtained from an honest server to the attacker's token endpoint. The attacker then redeems it at the honest server. The client lost track of which server a response came from.
How to implement it
Remember which server each flow targets, and check the answer against it. RFC 9207 defines the iss parameter in authorization responses.
app.get("/callback", async (req, res) => {
const flow = req.session.oauth; // saved at /login
if (!flow) return res.sendStatus(400);
if (req.query.iss !== flow.expectedIssuer) return res.sendStatus(400);
// exchange the code only at flow.tokenEndpoint, then
// check the iss claim of the ID token equals flow.expectedIssuer
});
Also use a distinct redirect URI per authorization server, which removes ambiguity entirely.
How to test it
Configure a second, test authorization server. Start a flow with server A, then return a response carrying server B's iss. Expect rejection. Strip iss from a server that advertises support and expect rejection.
Common mistakes
- Choosing the token endpoint from data in the callback.
- One shared redirect URI for all servers and no issuer check.
- Not storing the expected issuer per transaction.
Quick check
Does a client with a single authorization server need this?
The requirement targets clients that use more than one. A single server removes the confusion, though checking iss costs little.