Correlating requests and responses
The printer's callback endpoint is an address on the web. Someone can send a request to it without first selecting Connect. You could also have two tabs open, each connecting a different photo account.
The client needs more context than "a code arrived." It must know which attempt the response belongs to, which browser session started it, and which authorization server it expected to answer.
Keeping a pending transaction
When the printer starts the connection, it creates a record similar to this simplified example:
Pending attempt: demo-attempt-7
Initiating session: the current printer session
Expected issuer: https://auth.photos.example
Redirect URI: https://printer.example/oauth/callback
PKCE verifier: held privately on the backend
Return destination: a validated local photo-book page
Status: pending, with a limited lifetime
The actual state value should be fresh and unpredictable. The readable value here only helps us follow the example.
On return, the printer uses state to locate the pending attempt and verifies its binding to the current session. A matching value in a global list is not enough if the response can be attached to a different person's session.
The attempt must still be valid and available for processing. The application should coordinate processing so two callbacks cannot both complete the same pending attempt. Separate records for separate attempts avoid overwriting one tab's verifier with another tab's value.
If the original session has expired, the printer should not guess which local account should receive the connection. It can explain that the attempt expired and let the person start again from an appropriate session.
Checking who answered
An application that connects to multiple authorization servers must also prevent responses from one server being confused with responses from another. This class of problem is called authorization server mix-up.
Our photo service supports the iss response parameter. The printer compares it exactly with the issuer saved for this attempt. If the expected parameter is missing or the issuer differs, the printer stops. It does not use an unexpected issuer value to select a new token endpoint and send the code there.
Issuer identification is one mix-up defense. Other deployments may use a different supported design, such as distinct redirect URIs per issuer. Advanced OAuth and the security lessons will examine the choices and their validation rules.
Keeping the protections distinct
In this example, state correlates the browser response with a session-bound transaction, PKCE binds code redemption to the verifier prepared for that transaction, and the issuer check verifies which authorization server answered.
Properly implemented PKCE can also provide CSRF protection under the conditions described by modern OAuth guidance. We retain explicit state in this teaching flow to make transaction handling clear. That does not mean state, PKCE, and issuer validation are interchangeable.
Finally, keep secrets and arbitrary return URLs out of state. An opaque random reference to server-side context is easier to control. Before returning the user to a page after connection, validate that destination independently so the callback cannot become an open redirect.