A mix-up attack tricks an OAuth client that uses several authorization servers into sending a code or token to the wrong one, controlled by an attacker. The defense is to check the iss parameter in the authorization response against the server you started the flow with, as RFC 9207 describes.
When you are exposed
Single provider apps are not exposed, but they become exposed the moment a second provider is added. That includes:
- an app with "sign in with" options from several providers
- a platform that lets customers connect their own identity provider
- a client that discovers servers dynamically, such as tools connecting to many remote services
The more servers your client can talk to, the more this matters.
How the attack works
The standard authorization response carries a code and a state but does not say which server sent it. An attacker who runs one of the supported servers can make the client believe the response from an honest server came from the attacker's. The client then redeems the honest server's code at the attacker's token endpoint, handing it over. RFC 9207 states that the client cannot tell the difference without more information.
The fix: the iss parameter
Servers that support RFC 9207 add an iss parameter with their issuer identifier to authorization responses, including error responses. The value is an https URL with no query or fragment.
Client rules:
- Store which issuer you started each request with.
- When the response arrives, extract
iss, URL decode it, and compare as a plain string against the stored issuer. - On mismatch, reject the response and stop the flow.
- If you work with both supporting and non supporting servers, track which is which. Reject a response lacking
issfrom a server that supports it. - If an ID token comes back from the authorization endpoint, its
issclaim must match as well. - Give each configured server a unique issuer identifier.
Servers advertise support in their metadata with authorization_response_iss_parameter_supported set to true. If the field is missing, it defaults to false.
Why the iss value does not need a signature
RFC 9207 notes that an attacker able to tamper with the response could already read the code, so the value does not need cryptographic protection. The check is about identifying the sender in an otherwise honest browser flow.
Alternatives
RFC 9700, the security best current practice, says clients with more than one server MUST have a mix-up defense and prefers the iss parameter. Where it is not available, a distinct redirect URI per issuer can work, but that is the fallback, not the preference. Returning the ID token from the authorization endpoint or using signed responses also carries the issuer.
Implementation checklist
- Persist issuer, state and PKCE verifier together per request.
- Never infer the server from the redirect URL alone.
- Fail closed on a missing or different
iss. - Test with a fake second server that returns a response for a request started at the first.
Quick check
Does PKCE stop a mix-up attack?
Not by itself. In the attack, the client sends its verifier to the wrong server, so PKCE does not help. Checking the issuer does.
Do I need this with only one identity provider?
Not today, but build the issuer check in if you may add providers later.
Sources
- RFC 9207, OAuth 2.0 Authorization Server Issuer Identification
- RFC 9700, Best Current Practice for OAuth 2.0 Security
Last reviewed: 19 October 2026.