Skip to content

Standardizing issuer_state Handling to Link Credential Requests to Offers #62

@nanderstabel

Description

@nanderstabel

The current OpenID4VCI specification seems to leave a critical gap in the Authorization Code flow: there is no standardized mechanism for a Credential Issuer to link an incoming Credential Request to the specific Credential Offer it originated from. This ambiguity forces implementers to create custom solutions, hindering interoperability.

This proposal suggests that the DIIP specification should standardize the process by mandating the use of the issuer_state parameter and its propagation through a JWT-based Access Token, creating a reliable and interoperable link between the offer and the request.

The standard OpenID4VCI Authorization Code flow is as follows (simplified):

  1. A Credential Issuer provides a Credential Offer to the User's Wallet.
  2. The Wallet makes an Authorization Request to the Authorization Server.
  3. The User authenticates and provides consent.
  4. The AS issues an Access Token to the Wallet.
  5. The Wallet presents the Access Token in a Credential Request to the CI to receive the credential.

Problem:
At step 5, the CI receives the Access Token but has no standardized way to determine which of its potentially numerous Credential Offers this request corresponds to. The CI optionally can include the issuer_state parameter inside the Credential Offer. The Wallet can then include this parameter in its Authorization Request to the Authorization Server. It is also mentioned that:

This request parameter is used to pass the issuer_state value back to the Credential Issuer

However, the specification does not describe any mechanism as to how this is passed back to the Credential Issuer. This is not necessarily an issue in situations where the Credential Issuer and Authorization Server are the same entity (and therefore presumably may have some sort of a shared state), but in situations where a Credential Issuer wants to integrate with one or more external Authorization Servers this causes problems.

This problem has been discussed already in several OpenID4VCI GitHub issues:

[...] Would that be the recommended approach, putting issuer_state in the access token?

[...] and because it can be embedded in the access token it's then not required to be passed to the credential issuer [...]

[...] How the issuer_state is communicated to the credential issuer (by the authorization server) is out of scope for the spec, but to provide an example of the kind of flow that is intended: embedding issuer_state into the access token is one possible approach.

So there seems to be some sort of consensus that to solve the problem of passing back the issuer_state to the Credential Issuer is for the Authorization Server to sign the Access Token as a JWT (as described in RFC 9068: JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens) with the issuer_state embedded inside it as a custom claim. This indeed enables the Credential Issuer to obtain the issuer_state when it receives the Access Token from the wallet.

The current status quo seems to be that: "How the issuer_state is communicated to the credential issuer (by the authorization server) is out of scope for the spec", so I think in order to promote interoperability between Credential Issuers and (external) Authorization Servers we as DIIP community need to discuss whether:

  1. Do we agree that the solution proposed here (embedding issuer_state in an RFC 9068 JWT Access Token) is the correct approach for ensuring interoperability?
  2. Do we agree with this problem being 'out of scope' for the OpenID4VCI spec? If not, do we want to propose some changes or feedback to the OpenID4VCI spec?
  3. In the mean time, do we want to update our own DIIP standard, and if so which version (v4.1? v5?)

If we as DIIP community would want to standardize this then it could look something like this (I'd be more than happy to open a PR for this after we have agreed on the topics above):

  • Credential Issuer MUST embed the issuer_state in the Credential Offer (so change it from being Optional to Required)
  • The Authorization Server MUST sign the Access Token as a JWT (as standardized in rfc9068)
  • The Authorization Server MUST embed the issuer_state inside the Access Token JWT
  • The Credential Issuer validates the Access Token (as described in rfc9068) and obtains the original issuer_state

The Pre-Authorized Code flow introduces an additional challenge: the Authorization Server receives a pre-authorized_code at its Token Endpoint but has no standard method to validate its authenticity or origin. To address this and align it with the issuer_state solution, we could propose the following extension:

  1. Credential Issuer: When using the Pre-Authorized Code flow, the CI MUST construct the pre-authorized_code as a signed JWT. This JWT MUST contain the issuer_state as a claim.
  2. Authorization Server:
    • Upon receiving a token request with a pre-authorized_code, the AS MUST validate the code as a JWT (verifying the signature against the CI's public key).
    • After successful validation, the AS MUST extract the issuer_state claim from the pre-authorized_code JWT.
    • The AS then proceeds as described above: it embeds the extracted issuer_state into the RFC 9068 Access Token JWT that it issues.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions