Mix-up attacks and failure cases
With the issuer check in place, the mix-up ends at the printer's callback. The photo service's response names https://auth.photos.example, the pending transaction expects https://auth.pixelvault.example, and the printer rejects the response before making any token request, so the code never reaches Pixel Vault.
Knowing exactly why that works also shows where it stops helping.
What the issuer check covers
Look at which server made the defense work. It was the photo service, the honest server, that put its name in the response. The attacker controls Pixel Vault's configuration, including whether Pixel Vault claims to send iss. If the photo service did not send the parameter, its response would arrive without one, the attacker would make sure Pixel Vault also claimed not to send it, and the printer would see nothing unusual. The check reliably protects codes from servers that send iss. A server that does not send it needs another defense for its own codes.
Several things lie outside the check altogether.
The response's integrity. The iss parameter is unsigned text, and that is acceptable for this purpose. In a mix-up, the response travels from the honest server through your browser without the attacker touching it. An attacker who could rewrite it in transit would already have the code and would not need a mix-up at all. Signing the whole response, as JARM does, serves other goals, and its iss claim is compared under the same rules as the parameter.
Whose code it is. The parameter says which server issued a code, not which account or browser session it belongs to. An attacker's own genuine photo service code carries exactly the right iss. Injected codes and forged callbacks are stopped by state and PKCE, as the Code interception and injection and the Request correlation and CSRF lessons described.
The printer's own records. The comparison is only as good as the expected value. Checking the response issuer explained why two configured servers must never share an issuer identifier. Metadata needs the same care: if the printer accepted a document in which Pixel Vault claimed the photo service's identifier, the check would pass for the wrong server. Metadata validation prevents that, because a metadata document's issuer must equal the identifier used to locate it.
Servers without issuer identification
Pixel Vault does not send iss, so its codes need protection that does not depend on the parameter. Two signed alternatives carry an issuer inside the response: a JARM response, and in OpenID Connect sign-in flows, an ID token returned from the authorization endpoint. Either is checked the same way as the parameter. Where neither is available, the fallback is a distinct return address for each server, which Authorization server mix-up compared with the other defenses. Because an attacker who can register the same address at the honest server defeats it, current guidance says it should be used only when the issuer-based options are not available.
The printer does not have to pick one defense for every server. It keeps the issuer check for the photo service, which sends iss, and gives Pixel Vault an address of its own. All domains in these examples are fictional:
Photo service
Issuer: https://auth.photos.example
Callback: https://printer.example/oauth/callback
Defense: iss must be present and match
Pixel Vault
Issuer: https://auth.pixelvault.example
Callback: https://printer.example/oauth/callback/pixelvault
Defense: response must arrive at this callback
Each pending transaction records the expected issuer, and through it the callback that belongs to that issuer. A response has to pass whichever check applies to its server. Suppose an attacker controlled the photo service and used it to steal a Pixel Vault code. The genuine Pixel Vault code would return to /oauth/callback/pixelvault while the printer was expecting a photo service response at /oauth/callback, and the printer would stop. The reverse attack, through a compromised Pixel Vault, is the one the iss check already stops.
The arrangement should not outlive its reason. When Pixel Vault adopts the parameter and says so in its metadata, the printer updates its record and starts requiring iss from Pixel Vault too.
When a legitimate response fails the check
Most issuer rejections in practice involve no attacker at all. They come from configuration that has drifted away from what a server actually sends:
| Situation | What the printer sees |
|---|---|
| A typing error in a manually configured issuer, such as a trailing slash | Every response from that server fails with an issuer mismatch. |
| The test website configured with the production issuer, or the reverse | Mismatches only in one environment. |
A server begins sending iss after the printer last read its metadata | Responses carrying an iss the printer did not expect, which its strict check rejects. |
| A server moves to a new issuer identifier | Every response fails until the printer's configuration changes. |
The fix in each case is to correct the configuration: refresh metadata on a schedule, compare configured issuers with each server's published issuer value when deploying, and keep test and production records apart. A change of issuer identifier is a migration that a server must announce to its clients, because the identifier is meant to be stable.
What the printer must not do is loosen the check to make the errors go away, by accepting any issuer for a while, normalizing values until they match, or adopting whatever issuer a response presents. A mismatch means either an attack or a mistake, and from inside one callback the two look identical. In both cases the safe outcome is the same: the code goes unused, you are asked to try again, and someone fixes whatever made the values differ.