Scope of this document

This document outlines the current development status of the EUDIW Demo authentication functionalities, the current technical choices, limitations and future development. Readers are advised to note, that project is under heavy development and technical decisions may change during implementation.

Upcoming changes

Standards and supported versions

StandardAcronym(s)VersionReference
OpenID for Verifiable PresentationsOpenID4VPdraft 20https://openid.net/specs/openid-4-verifiable-presentations-1_0-20.html
Presentation Exchange
2.0.0https://identity.foundation/presentation-exchange/spec/v2.0.0/
Did:web method

https://w3c-ccg.github.io/did-method-web/
JWT Secured Authorization Response Mode for OAuth 2.0JARM
https://openid.net/specs/oauth-v2-jarm-final.html
Selective Disclosure for JWTsSD-JWTdraft 05https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-05.html
Self-Issued OpenID Provider v2SIOPv2Not supportedhttps://openid.net/specs/openid-connect-self-issued-v2-1_0-12.html

Implementation profile

This section provides an overview of the EUDIW Demo implementation profile, detailing the technical choices that have been selected and incorporated into the implementation and addresses the optional requirements specified in the OpenID4VP specification

  • authorization_endpoint is openid4vp://
  • client_id_scheme MUST be used in Wallet Invocation URL and Authorization Request (JAR)
  • client_id_scheme value MUST be did
  • client_id value MUST be a valid did:web identifier
  • Authorization Request MUST be sent using the request_uri parameter as defined in JWT-Secured Authorization Request (JAR)
    • request parameter is not supported
  • JAR header MUST contain kid parameter
  • client_metadata MUST be defined in JAR
    • client_metadata_uri parameter is not supported
  • client_metadata.jwks MUST be defined
  • client_metadata.vp_formats MUST be compatible with credential formats that EUDIW Demo supports
  • response_type MUST be vp_token
    • id_token is not supported
  • presentation_definition parameter MUST be used to send the Presentation Definition 
    • presentation_definition_uri parameter is not supported
    • scope parameter is not supported
  • response_mode value MUST be direct_post.jwt
    • other response_mode values are not supported
  • response_uri parameter MUST be used
    • redirect_uri parameter MUST NOT be used in Authorization Request with response_mode direct_post.jwt
  • Verifier MAY return redirect_uri from Response Endpoint (response_uri)

Trust model

Trust model is incomplete and currently not aligned with ARF. 

Requirements for Verifier

did:web client_id

In order to authenticate the requests made by the Verifier, EUDIW Demo requires the use of did client_id_scheme, with the additional requirement that the client_id MUST be a did:web identifier.

In order to have a did:web identifier, the Verifier should

  1. have a domain name & website, that can be represented as a did:web identifier
  2. have a cryptographic private key for signing Authorization Request
  3. host a valid DID document, containing the corresponding public key for private key used to sign Authorization Requests. The public key should be implemented as publicKeyJwk, and contained within authentication verification relationship. 

In summary, when the client_id is resolved using read operation, it should produce a valid DID document.

Example did:web identifiers
https://example.com 		=>		did:web:example.com
https://example.com/auth 	=>		did:web:example.com:auth
Example URIs for did:web read operation
did:web:example.com         =>		https://example.com/.well-known/did.json
did:web:example.com:auth    =>		https://example.com/auth/did.json

Example DID document (JSON)
{
  "id": "<value of client_id parameter, example did:web:example.com>",
  "verificationMethod": [
    {
      "id": "<DID URI that identifies this verificationMethod, the fragment is a JWK Thumbprint of the key in publicKeyJwk, example did:web:example.com#_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A>",
      "type": "JsonWebKey2020",
      "controller": "<DID identifier of the DID document, example did:web:example.com>",
      "publicKeyJwk": {
        "kid": "<JWK Thumbprint of this key, example _Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A>",
        "kty": "EC",
        "crv": "P-384",
        "x": "<base64url-encoded public key x-coordinate>",
        "y": "<base64url-encoded public key y-coordinate>",
        "x5c": ["<RP's X.509 certificate>"]
      }
    }
  ],
  "authentication": [
    "id": "<DID fragment that identifies a verificationMethod, example did:web:example.com#_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A>"
  ]
}

request_uri endpoint

Verifier should have a HTTPS endpoint that provides JWT-Secured Authorization Requests (JAR) using HTTP GET method.

See JWT-SecuredAuthorizationRequest(JAR).

response_uri endpoint

Verifier should have a HTTPS endpoint that receives & processes Authorization Response (or Error Response) in JWT-Secured Authorization Response Mode using HTTP POST.

See AuthorizationResponse.

Authorization Request data model

Authorization Request data model consists of two parts:

  • Wallet Invocation
  • JWT-Secured Authentication Request (JAR)

Verifier invokes the EUDIW Demo app by passing client_id (to fetch DID document) and request_uri (to fetch the JAR) using custom URL scheme.

Wallet Invocation

Wallet Invocation is presented in URI-form containing following information:

  • authorization_endpoint: openid4vp:// (Custom URL scheme)
  • client_id: Verifier's did:web identifier (must resolve to URI for fetching DID document by EUDIW Demo application)
  • client_id_scheme: did
  • request_uri: an URI corresponding the authentication transaction that can be used by EUDIW Demo application to fetch JWT-Secured Authorization Request (JAR)

Example Wallet Invocation URI
openid4vp://?client_id=did%3Aweb%3Aexample.com&client_id_scheme=did&request_uri=https%3A%2F%2Fexample.com%2Fauth%2Frequest%2F123

Verifier can invoke the app by 

  • redirecting the browser to the Wallet Invocation URI
  • rendering the Wallet Invocation URI as a QR code & requesting the user to scan it using device camera, or the QR code reader embedded in EUDIW Demo app

JWT-Secured Authorization Request (JAR)

Wallet resolves JWT-Secured Authorization Request (JAR) by performing a HTTP GET to request_uri.

JAR is a JWT containing the actual Authorization Request data in the payload.

JAR Authentication

EUDIW Demo application interprets the client_id in Wallet Invocation as a did:web identifier and then performs a read operation to resolve Verifier's DID document. If DID document resolution fails, Wallet Invocation is rejected. 

Once the DID document has been resolved, EUDIW Demo application fetches JAR from the URI presented by request_uri of the Wallet Invocation. JAR must be cryptographically signed with private key that corresponds the public key in DID document (publicKeyJwk) and this signature must be verified successfully by the EUDIW Demo application. The key identifier (kid) in JAR header must be set to a key identifier that is found in the did.json for authentication verification relationship.

If publicKeyJwk cannot be located via authentication verification relationship by using kid, or signature cannot be verified, EUDIW Demo rejects the JAR and authentication flow is interrupted.

JAR Contents

Example JAR
{ // JWS Protected Header
  "alg": "<algorithm that is listed in ASM.request_object_signing_alg_values_supported array and which matches with the key referenced in JAR.header.kid>",
  "kid": "<key identifier that maps to DID document's authentication[] → verificationMethod[].id relation, example did:web:example.com#_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A>"
}
.
{ // JWS Payload
  "aud": "https://self-issued.me/v2",
  "nbf": "<timestamp now>",
  "exp": "<timestamp now + 5 minutes>",
  "client_id": "<did:web identifier, must match client_id in Wallet Invocation, example did:web:example.com>",
  "client_id_scheme": "did",
  "client_metadata": {
    "jwks": {
      "keys": [
        { // Ephemeral public EC key for encryption of JARM response.
          "kty": "EC",
          "use": "keyAgreement",
          "kid": "<UUIDv4>",
          "crv": "<P-521 or P-384>",
          "x": "<base64url-encoded public key x-coordinate>",
          "y": "<base64url-encoded public key y-coordinate>"
        }
      ]
    },
    "vp_formats": {
      "sd_jwt": {
        "alg": ["ES384"]
      },
      "kb_jwt": {
        "alg": ["ES256"]
      }
    }
  },
  "presentation_definition": <Presentation Definition object as defined in Presentation Exchange specification>,
  "response_type": "vp_token",
  "response_mode": "direct_post.jwt",
  "response_uri": "<HTTPS URL, example https://example.com/auth/response>",
  "nonce": "<single use cryptographically secure random value>",    
  "state": "<rp-defined value for optional state management>"
}
.
<RP's signature (JWS Signature)>


EUDIW Demo solution extends the vp_formats in client_metadata with it's own claim format designation for sd_jwt & kb_jwt:

  • sd_jwt should list the supported signature algorithms for the SD-JWT (ES384)
  • kb_jwt should list the supported signature algorithms for the KB-JWT in the SD-JWT presentation (ES256)

See WalletMetadata(AuthorizationServerMetadata) for static wallet metadata describing all supported formats & parameter values.

Presentation Definition

JAR.payload.presentation_definition contains Presentation Definition. Presentation Definition is specified by Presentation Exchange.

Although OpenID4VP describes multiple mechanisms for delivering the Presentation Definition, EUDIW Demo requires the Presentation Definition to be passed by value in the JAR.

EUDIW Demo solution extends the vp_formats with it's own claim format designation for sd_jwt.

Example Presentation Definition (JSON)
{
  "id": "<rp-defined value>",
  "format": {
    "sd_jwt": {
      "alg": ["ES384"]
    }
  },
  "input_descriptors": [
    {
      "id": "<rp-defined value>",
      "constraints": {
        "fields": [
          {
            "path": [
              "$.credentialSubject.<attribute_name>"
            ],
            "filter": <optional JSON Schema object>
          }
        ]
      }
    }
  ]
}

For successful selective disclosure, each requested Test PID attribute should be specified within it's own Input Descriptor Object.

Authorization Response

Currently, response_mode direct_post.jwt (https://openid.net/specs/openid-4-verifiable-presentations-1_0-20.html#section-6.3.1) is the only supported response_mode.

EUDIW Demo implements JARM (see below) in encrypted but not signed mode (https://openid.net/specs/openid-4-verifiable-presentations-1_0-20.html#section-6.3-3).

Thus, when EUDIW Demo delivers Authorization Response or Error Response, it's sent as JWE, as specified in https://openid.net/specs/openid-4-verifiable-presentations-1_0-20.html#section-6.3.1.

Example Authorization Response sent using Direct Post
POST /post HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

response=<JARM>
state=<value of JAR.payload.state, if present in JAR>

JWT Secured Authorization Response Mode for OAuth 2.0 (JARM)

EUDIW Demo uses JARM and sends Authorization Responses using "encrypted but not signed" method described in https://openid.net/specs/openid-4-verifiable-presentations-1_0-20.html#section-6.3-3.

Holder Key-Binding can be verified through SD-JWT in vp_token, so additional signatures in JARM are not used.

Authorization Response is encrypted as JWE using

Verifier encryption keys are obtained from JAR.payload.client_metadata.jwks.

EUDIW Demo uses ephemeral key pair & it's public key is included in the JWE header's epk field. Verifier's public key that was used in encryption is identified by the key identifier (kid) in the JWE header.

Example JARM (JWE)
{ // JWE Protected Header
  "alg": "ECDH-ES",
  "enc": "A256CBC-HS512",
  "epk": { // Ephemeral public key in JWK format as defined in RFC 7518 JWA section 4.6.1.1.
    "kty": "EC",
    "crv": "<EC curve value of the key that JARM.header.kid points to>",
    "x": "<base64url-encoded public key x-coordinate>",
    "y": "<base64url-encoded public key y-coordinate>"
  },
  "kid": "<kid of the ephemeral public EC key that was selected from JAR.payload.client_metadata.jwks.keys>"
}
.
// Normally this section would be the JWE Encrypted Key. However, because `"alg": "ECDH-ES"` the section is left as an empty string (so-called empty octet sequence).
.
<JWE Initialization Vector>
.
<encrypted payload (JWE Ciphertext)>
.
<JWE Authentication Tag>

Authorization Response

Once the JWE is decrypted using the private key corresponding to the kid header, the decrypted data contains the Authorization Response parameters as in https://openid.net/specs/openid-4-verifiable-presentations-1_0-20.html#name-response-parameters.

If the user approved the release of credentials, JWE payload contains Authorization Response parameters as specified in https://openid.net/specs/openid-4-verifiable-presentations-1_0-20.html#section-6.3 for encrypted but not signed Authorization Response:

Example Authorization Response (decrypted JWE payload, JSON)
{
  "vp_token": <vp token>,
  "presentation_submission": <presentation submission>,
  "state": <value of JAR.payload.state, if present in JAR>,
}

If there was an error processing the request, or user cancelled, JWE payload contains Error Response parameters, as in https://openid.net/specs/openid-4-verifiable-presentations-1_0-20.html#section-6.4:

Example Error Response (decrypted JWE payload, JSON)
{
  "error": <error code>,
  "error_description": <description provided by EUDIW Demo app>,
  "state": <value of JAR.payload.state, if present in JAR>
}

As seen in above examples, EUDIW Demo also adds the state parameter, if it was provided by the Verifier in JAR.

VP Token

vp_token in response object contains the presented credentials in SD-JWT presentation format.

SD-JWT is specified by Selective Disclosure for JWTs (SD-JWT)

Example VP Token (SD-JWT)
<base64url-encoded JWS Protected Header of JWT>
.
<base64url-encoded JWS Payload of JWT>
.
<base64url-encoded JWS Signature of JWT>
~
<base64url-encoded disclosure 1>
~
<base64url-encoded disclosure 2>
~
<base64url-encoded disclosure 3> // The number of disclosures varies from one to many.
~
<base64url-encoded JWS Protected Header of KB-JWT>
.
<base64url-encoded JWS Payload of KB-JWT>
.
<base64url-encoded JWS Signature of KB-JWT>

Verification and processing of SD-JWT must be done as speciefied in: https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-05.html#name-verification-and-processing. Signing certificate is received in x5c header and must be used to verify SD-JWT signature. Signing certificate itself must be verified using CA certificate found from the JWKS endpoint.

Presentation Submission

presentation_submission contains a Presentation Submission. Presentation Submission is specified by Presentation Exchange.

Example Presentation Submission (JSON)
{
  "definition_id": "<value of JAR.payload.presentation_definition.id>",
  "id": "<wallet-defined value>",
  "descriptor_map": [
    {
      "id": "<value of JAR.payload.presentation_definition.id>",
      "format": "sd_jwt",
      "path": "$"
    }
  ]
}

Response Mode direct_post.jwt & redirect_uri

In order to mitigate Session Fixation attacks, the Verifier is strongly recommended to implement a Session Fixation mitigation and returning a redirect_uri from the Response Endpoint (response_uri), as specified in https://openid.net/specs/openid-4-verifiable-presentations-1_0-20.html#section-6.2-21.

Example Response from response_uri, returning a redirect_uri
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
  "redirect_uri": "https://example.com/redirect#response_code=<Verifier defined response_code, used by Verier's front-end>"
}

Upon receiving a redirect_uri from response_uri, EUDIW Demo will prompt the user to continue interaction with the Verifier by letting the user to confirm navigation to redirect_uri. EUDIW Demo uses operating system's APIs to open the redirect_uri in a browser & does not interpret any parameters in the response_uri. It's the responsibility of the Verifier to implement the Session Fixation mitigation according to the best practices. See https://openid.net/specs/openid-4-verifiable-presentations-1_0-20.html#section-12.2 for further details about Session Fixation attack & mitigation.

Using redirect_uri Authorization Request parameter is not allowed, when response_mode is direct_post.jwt. Upon receiving such request, EUDIW Demo will respond with invalid_request Authorization Error, as described in https://openid.net/specs/openid-4-verifiable-presentations-1_0-20.html#section-6.2-7.2.

Authentication sequence

Sequence diagram below describes the cross-device flow between a browser and EUDIW Demo app on another device.

Same sequence should work when Browser performs URI redirection to EUDIW Demo app on same device.


#StepExample
1User initiates authentication sequence from the Verifier web site.
2

Verifier starts the authentication and creates:

  • an authentication transaction
  • an authentication request (Wallet Invocation URL) with openid4vp:// authorization endpoint containing following parameters:
    • client_id: Verifier's did:web identifier
    • client_id_scheme: did
    • request_uri: an URI corresponding the authentication transaction that can be used by EUDIW Demo application to fetch JWT-Secured Authorization Request (JAR)
Example Wallet Invocation URL
3

Verifier forwards the authentication request for EUDIW Demo application by

  • presenting Wallet Invocation URI as QR code to user, or
  • redirecting to Wallet Invocation URL


4

EUDIW Demo application receives the Wallet Invocation

  • by receiving URL redirection from scanning the QR code with device camera
  • by redirection from the browser
  • by scanning the QR code with in-app QR code scanner

5

EUDIW Demo application receives the Wallet Invocation and reads it's parameters


6

EUDIW Demo application performs did:web read -operation for the client_id -parameter and receives the DID document from the Verifier.

client_id: did:web:example.com => GET https://example.com/.well-known/did.json

Example DID document

7

EUDIW Demo application validates the DID document. The id of the DID document must correspond with the client_id of the Wallet Invocation.


8

EUDIW Demo application sends HTTP GET -request to URI addressed by the request_uri to fetch a JWT-Secured Authorization Request (JAR). Verifier responds with JWT-Secured Authorization Request (JAR).

Example JWT-Secured Authorization Request (JAR)
9

EUDIW Demo application verifies JAR signature.


10

EUDIW Demo application presents authentication request with details and Verifier info to user. User accepts the authentication request.


11

EUDIW Demo application evaluates presentation_definition and creates a presentation of user's credentials to form a vp_token.

If presentation_definition is unsatisfiable, authentication flow ends in an error indicating that the credentials are insufficient.


12

EUDIW Demo application presents requested credentials to user. User accepts sending the credentials.


13

EUDIW Demo application creates

  • vp_token, a SD-JWT presentation with matched disclosures & KB-JWT, that is signed using holder's key
  • presentation_submission, containing mapping of the presentation_definition's input descriptors to the vp_token

EUDIW Demo application creates Authorization Response (JARM payload):

  • vp_token
  • presentation_submission
  • state
Example Authorization Response
14

EUDIW Demo application creates the encrypted Authorization Response (JWE).

Example JWE


15

EUDIW Demo application sends authentication response to Verifier as defined in JAR.payload.response_mode.

Currently, only direct_post.jwt is supported, so response is sent as HTTPS POST to response_uri.


16Verifier validates the received response.
17Verifier responds with redirect_uri containing a response_code generated by the verifier.
18EUDIW Demo application opens the received redirect_uri in a new browser session. 
19Redirect_uri opened in the browser contains a confirmation request. User is requested to verify the session to mitigate possible session fixation attacks.
20After receiving user confirmation, the response_code is posted from the browser to the verifier.
21Verifier validates the received response_code.
22

Verifier performs custom authentication functionalities as needed.


Wallet Metadata (Authorization Server Metadata, ASM)

Verifier can determine the supported formats & other configuration using the static metadata provided below.

Configuration values (and their definitions) are as follows:

  • authorization_endpoint: "openid4vp://" (Custom URL Scheme)
  • client_id_schemes_supported: an array containing supported client identifier schemes
  • request_object_signing_alg_values_supported: an array containing supported algorithms for signing JAR
  • response_types_supported: an array containing supported values for JAR.payload.response_type
  • response_modes_supported: an array containing supported values for JAR.payload.response_mode
  • vp_formats_supported : an object containing supported fields and values for JAR.payload.client_metadata.vp_formats
  • vp_formats_supported.sd_jwt.alg_values_supported: an array containing supported algorithms for signing SD-JWT
  • vp_formats_supported.kb_jwt.alg_values_supported: an array containing supported algorithms for signing KB-JWT
  • authorization_encryption_alg_values_supported: an array containing the method to generate key  for decrypting JARM contained by the authentication response
  • authorization_encryption_enc_values_supported: an array containing the algorithm used to encrypt JARM contained by the authentication response (corresponds to the value provided in the enc-header)

Static configuration in ASM format (OAuth 2.0 Authorization Server Metadata) with extensions based on OpenID4VP standard (8.1. Additional Wallet Metadata parameters) and JARM standard (4. Authorization Server Metadata).

Static OAuth 2.0 Authorization Server Metadata (JSON)
{
  "authorization_endpoint": "openid4vp://",
  "client_id_schemes_supported": [
	"did"
  ],
  "request_object_signing_alg_values_supported": [
    "ES384",
    "ES256",
    "PS512",
    "PS384",
    "PS256"
  ],
  "response_types_supported": [
    "vp_token",
  ],
  "response_modes_supported": [
    "direct_post.jwt"
  ],
  "scopes_supported": [
    "openid" // unused, reserved for SIOPv2 
  ],
  "presentation_definition_uri_supported": false,
  "vp_formats_supported": {
    "sd_jwt": {
      "alg_values_supported": [
        "ES384"
      ]
    },
    "kb_jwt": {
      "alg_values_supported": [
        "ES256"
      ]
    }
  },
  "authorization_signing_alg_values_supported": [], // JARM is not signed. It is only encrypted.
  "authorization_encryption_alg_values_supported": [
    "ECDH-ES"
  ],
  "authorization_encryption_enc_values_supported": [
    "A256CBC-HS512"
  ]
}


Changelog

VersionDateChanges
12023-10-18First published version
22024-04-05

Document updated to follow OpenID4VP draft 20 implementation.

Notable changes in implementation:

  • Added requirement for client_id_scheme parameter & it's value
  • Changed to use response_uri parameter
  • Use of redirect_uri Authorization Request parameter with response_mode direct_post.jwt is now forbidden
  • Changed format of Presentation Submission descriptor_map[].path values to $
  • Verifier may return redirect_uri from response_uri  to mitigate session fixation attacks. Upon receiving redirect_uri from response_uri, EUDIW Demo applications will redirect to browser using platform APIs.  


  • No labels