Skip to main content

Session Binding

Session binding ties a presentation to this specific OpenID4VP exchange: the one your backend is waiting on right now, not a copy of an exchange from any other point in time or sent to any other verifier.

Why you need it

A Presentation Response (the Verifiable Presentation the wallet posts back to you) is signed data, and signed data can be copied and resent without invalidating any signature it carries. An attacker who intercepts network traffic, gains access to log files, or compromises a downstream system can capture a genuine response and replay it later: against your own endpoint a second time, forwarded to a different Relying Party, or credited to the wrong session. The replayed response is not forged: it is the same valid data, submitted again. Detecting this requires a mechanism that verifies which exchange a response was produced for, not merely whether the response itself is valid.

How it works

This is where nonce and state, introduced above, get checked:

  • The wallet's signature over the response covers your nonce. Comparing the nonce inside that signed response against the value you stored for this request confirms the response is fresh: produced for this exchange, not recycled from another one.
  • The wallet returns your state unchanged in the response envelope. Comparing it against the session it was issued to tells you which session should receive the result.

Both checks run independently: a valid nonce tells you nothing about which session to hand the result to, and a valid state tells you nothing about whether the signed response is fresh.

Note the asymmetry

The presentation replayed against Relying Party B is not forged in any way. Every signature it carries is completely genuine. The only thing that flags it is the mismatch between the nonce it carries and the nonce Relying Party B is able to resolve for its own session. Without that check, a perfectly valid, perfectly genuine presentation would be accepted for an exchange it was never made for.

Linking the Exchange to Your Own Session

state is not limited to one request/response cycle the way nonce is. You are free to reuse it, or a value derived from it, as the identifier for a broader user session or business process: an account-opening flow, a checkout, or any other multi-step journey your application already tracks. It does not need to be a separate, purpose-built concept: state can be an on-demand identifier you generate solely for this exchange, or it can be identical to, or simply correlated with, a session attribute your application already maintains elsewhere.

What OpenID4VP requires of you is only this: generate the value, keep a record of what it refers to, and validate that record when the wallet's response comes back. A state you cannot look up in your own records should never be treated as authoritative.

nonce and state are the two protocol-level parameters that plug into whatever session or process architecture you already have.


Further Reading

DocumentationRead this, when ...
OpenID4VP: Terminology... you want the formal spec definitions behind binding