Skip to content

(Q)EAA Presentation with OpenID4VC

Basic Idea

The Q(EAA) Provider issues signed credentials to the Wallet, which are stored for a longer period. The Wallet can then present the credentials (including a proof of possession by signing over a wallet-held key) to the Relying Party.

Cryptographic Formats

Long-Term keys:

  • (Q)EAA Provider has long-term key pair \((ep\_pub, ep\_priv)\) that is used to sign SD-JWT
  • RP has long-term key pair \((rp\_pub, rp\_priv)\) that is used to sign OpenID4VP Authorization Request
  • Wallet app has device key pair \((device\_pub, device\_priv)\) that is attested by the EAA Provider are used to sign KB-JWT

Transaction-specific keys:

  • RP has ephemeral key pair \((rp\_eph\_pub, rp\_eph\_priv)\) that is used to encrypt the response

Artifacts:

  • \(kb\_jwt := \text{sign}(nonce, audience, \text{hash}(sd\_jwt, disclosures))_{device\_priv}\)
  • \(device\_Auth\) for mdoc

Dependencies

TODO: May want to expand to include metadata.

G cluster_eaa_provider (Q)EAA Provider cluster_wallet Wallet ep 🗝 (ep_priv, ep_pub) user_data attestation data ep->user_data sign (SD-JWT/ mdoc issuerAuth) device_key 🗝 (device_priv, device_pub) ep->device_key sign (SD-JWT/ mdoc issuerAuth) nonce_audience nonce, audience device_key->nonce_audience sign (KB-JWT/ mdoc deviceAuth)

Note: Wallet attestation not shown in this chart.

Sequence Diagram for Same Device Flow

User Journey: (Q)EAA Presentation - Same Device

(Q)EAA presentation over OpenID4VP (same device)UserOpenID HolderUserOpenID HolderBrowser App(same device)Browser App(same device)Relying PartyLong-term Key: (rp_pub,rp_priv)Relying PartyLong-term Key: (rp_pub,rp_priv)User's EUDI Wallet InstanceDevice binding Key: (device_pub,device_priv)User's EUDI Wallet InstanceDevice binding Key: (device_pub,device_priv)(001)browse to applicationScreen: same_device_relying_party_start(002)[TLS] HTTP GET <rp-website>(003)generate new browser sessionwith session_id(004)generate ephemeral key pair(rp_eph_pub, rp_eph_priv)rp_eph_pub is only used for responseencryption(005)create OpenID4VPAuthorization Request, sign with rp_priv, store under <request_uri>,bind everything to session_idAuthorization Request includes:- presentation_definition- purpose- state- nonce(006)[TLS] HTTP 200 HTMLcontaining wallet-linkopenid4vp://authorize?")client_id=..&request_uri=<request_uri>Set-Cookie: sid=session_id(007)action to start flow/launchwallet(008)launch with wallet-linkopenid4vp://Screen: launch_wallet(009)unlock walletScreen: unlock_wallet(010)[TLS] HTTP GET<request_uri>(011)[TLS] HTTP 200 <JWT-SecuredAuthorizationRequest(presentation_definition,nonce, state)>(012)validate AuthorizationRequest JWT using rp_pub(013)user consent for presentingthe (Q)EAAScreen: consent_present_credentialalt[SD-JWT (Q)EAA](014)generate KB-JWT by signingover nonce, audience withdevice_privScreen: device_authenticator(015)generate SD-JWT presentationaccording to<presentation_definition> byremoving unnecessaryDisclosures and attachingKB-JWT[mdoc (Q)EAA](016)generate deviceAuth bysigning over SessionTranscriptwith device_privScreen: device_authenticator(017)generate issuerAuthaccording to<presentation_definition> byremoving unnecessaryReleases and attachingdeviceAuth(018)create vp_token andpresentation_submission(019)[TLS] HTTP POST<AuthorizationResponse(presentation_submission,vp_token, state)> (optionallyencrypted to rp_eph_pub)(020)optionally decryptAuthorization Response withrp_eph_pub(021)look up state in existingsessionscreate & store response_codefor session(022)[TLS] HTTP 200 <redirect_uriincl. response_code>(023)launch browser with<redirect_uri withresponse_code>Screen: success_redirect(024)[TLS] HTTP GET <redirect_uriwith response_code>Cookie: sid=session_id(025)look up session withsession_id and matchresponse_codealt[SD-JWT (Q)EAA](026)verify contents of<vp_token>:- SD-JWT signature from(Q)EAA Provider- KB-JWT with kb_eph_pubfrom SD-JWT- nonce and audience fromKB-JWT[mdoc (Q)EAA](027)verify contents of<vp_token>:- mdoc signature from (Q)EAAProvider- deviceAuth with kb_eph_pubfrom SD-JWT- nonce and audience fromSessionTranscript(028)[TLS] HTTP 200 <HTML withcontinued UX flow>Screen: same_device_relying_party_identified

Step-by-Step Description

Note: While certain assumptions about session management of the Relaying Party are made here, the concrete implementation is considered out of scope for this document. The usual security considerations for web session management apply.

  1. User browses to Relying Party (RP) website
  2. Browser app on the user's device opens the RP website
  3. The RP generates a new browser session, depicted session_id
  4. RP generates a key pair to be used for ECDH key agreement for response encryption
  5. RP generates an OpenID4VP Authorization Request, binding it internally to the session_id and stores it under a request_uri (e.g., https://rp.example.com/oidc/request/1234);
  6. The request is bound to the user's browser session
  7. It is signed using a key bound to the RP's metadata that can be retrieved using the RP's client_id
  8. It contains the presentation_definition containing the information about the requested (Q)EAAs
  9. It contains RP's nonce and state
  10. It contains the purpose given by the RP
  11. RP returns a HTML page to the browser containing a link to the wallet app (e.g., openid4vp://authorize?client_id=..&request_uri=https://rp.example.com/oidc/request/1234). It also sets a Cookie with the session_id.
  12. The user clicks on the link
  13. The wallet app is launched with the custom URI scheme
  14. The user unlocks the wallet app (see notes below)
  15. The wallet app retrieves the Authorization Request from the RP website (e.g., https://rp.example.com/oidc/request/1234)
  16. The wallet app receives the Authorization Request
  17. The wallet app validates the Authorization Request using the RP's public key
    • Was the signature valid and the key bound to the RP's metadata?
    • Security: This ensures that the Authorization Request was not tampered with; it does not ensure that the party that sent the Authorization Request is the RP.
  18. The Wallet displays information about the identity of the Relying Party and the purpose, the user gives consent to present the (Q)EAA.
  19. (SD-JWT (Q)EAA) The Wallet generates a KB-JWT by signing over nonce and audience with device_priv
  20. (SD-JWT (Q)EAA) The Wallet creates the presentation according to presentation_definition by cutting out the unnecessary Disclosures and appending the KB-JWT
  21. (mdoc (Q)EAA) The Wallet generates an mdoc deviceAuth by signing over SessionTranscript with device_priv
  22. (mdoc (Q)EAA) The Wallet creates the presentation according to presentation_definition by cutting out the unnecessary Releases assembling the issuerAuth with deviceAuth
  23. The wallet app creates a VP token and a presentation submission
  24. The wallet app sends the VP token and presentation submission to the RP (encrypted to the RP's public key rp_eph_pub).
  25. The RP optionally decrypts the Authorization Response with rp_eph_pub received in the Authorization Request.
  26. The RP finds a session with the state, generates a response_code and stores the received vp_token
  27. The RP responds with a redirect inluding the generated response_code.
  28. The wallet launches the browser with the redirect_uri and response_code.
  29. The browser receives the redirect_uri and response_code and sends an HTTP GET request to the RP frontend, this request contains the Cookie set in the beginning of the protocol.
  30. The RP matches the session_id from the Cookie and matches the response_code to find the received vp_token.
  31. (SD-JWT (Q)EAA) The RP verifies the content of the vp_token. In case of SD-JWT it validates the Issuer signature from the (Q)EAA Provider, verifies the KB-JWT matching to the cnf claim and validates that the KB-JWT is fresh and matches to its own client_id and nonce.
  32. (mdoc (Q)EAA) The RP verifies the content of the vp_token. In case of mdoc it validates the Issuer signature from the (Q)EAA Provider, verifies the deviceAuth matching to the deviceKey and validates that the SessionTranscript is fresh and matches to its own client_id and nonce.
  33. The RP considers the user to be identified in the session context and continues the UX flow.

Sequence Diagram for Cross Device Flow

User Journey: (Q)EAA Presentation - Cross Device

(Q)EAA presentation over OpenID4VP (cross device)UserOpenID HolderUserOpenID HolderBrowser App(other device)Browser App(other device)Relying PartyLong-term Key: (rp_pub,rp_priv)Relying PartyLong-term Key: (rp_pub,rp_priv)User's EUDI Wallet InstanceDevice binding Key: (device_pub,device_priv)User's EUDI Wallet InstanceDevice binding Key: (device_pub,device_priv)(001)browse to applicationScreen: cross_device_relying_party_start(002)[TLS] HTTP GET <rp-website>(003)generate new browser sessionwith session_id(004)generate ephemeral key pair(rp_eph_pub, rp_eph_priv)rp_eph_pub is only used for responseencryption(005)create OpenID4VPAuthorization Request, sign with rp_priv, store under <request_uri>,bind everything to session_idAuthorization Request includes:- presentation_definition- purpose- state- nonce(006)[TLS] HTTP 200 HTMLcontaining wallet-linkopenid4vp://authorize?")client_id=..&request_uri=<request_uri>Set-Cookie: sid=session_id(007)launch walletScreen: launch_wallet(008)unlock walletScreen: unlock_wallet(009)scan QR-Code with"openid4vp://..."Screen: device_camera(010)[TLS] HTTP GET<request_uri>(011)[TLS] HTTP 200 <JWT-SecuredAuthorizationRequest(presentation_definition,nonce, state)>(012)validate AuthorizationRequest JWT using rp_pub(013)user consent for presentingthe (Q)EAAScreen: consent_present_credentialalt[SD-JWT (Q)EAA](014)generate KB-JWT by signingover nonce, audience, andhash of SD-JWT and selecteddisclosures with device_privScreen: device_authenticator(015)generate SD-JWT presentationaccording to<presentation_definition> byremoving unnecessaryDisclosures and attachingKB-JWT[mdoc (Q)EAA](016)generate deviceAuth bysigning over SessionTranscriptwith device_privScreen: device_authenticator(017)generate issuerAuthaccording to<presentation_definition> byremoving unnecessaryReleases and attachingdeviceAuth(018)create vp_token andpresentation_submission(019)[TLS] HTTP POST<AuthorizationResponse(presentation_submission,vp_token, state)> (optionallyencrypted to rp_eph_pub)(020)optionally decryptAuthorization Response withrp_eph_pub(021)look up state in existingsessions and match sessionalt[SD-JWT (Q)EAA](022)verify contents of<vp_token>:- SD-JWT signature from(Q)EAA Provider- KB-JWT with kb_eph_pubfrom SD-JWT- nonce and audience fromKB-JWT[mdoc (Q)EAA](023)verify contents of<vp_token>:- mdoc signature from (Q)EAAProvider- deviceAuth with kb_eph_pubfrom SD-JWT- nonce and audience fromSessionTranscript(024)[TLS] HTTP 200in cross device flow the redirect is omittedhereScreen: successThe Browser may refresh the RP website withpolling or the RP website may send a signal,e.g. with previuosly established websocket(025)[TLS] HTTP GET <rp-website>Cookie: sid=session_id(026)look up session withsession_id and matchverification result(027)[TLS] HTTP 200 <HTML withcontinued UX flow>Screen: cross_device_relying_party_identified

Step-by-Step Description

Note: While certain assumptions about session management of the Relaying Party are made here, the concrete implementation is considered out of scope for this document. The usual security considerations for web session management apply.

  1. User browses to Relying Party (RP) website
  2. Browser app on the user's device opens the RP website
  3. The RP generates a new browser session, depicted session_id
  4. RP generates a key pair to be used for ECDH key agreement for response encryption
  5. RP generates an OpenID4VP Authorization Request, binding it internally to the session_id and stores it under a request_uri (e.g., https://rp.example.com/oidc/request/1234);
  6. The request is bound to the user's browser session
  7. It is signed using a key bound to the RP's metadata that can be retrieved using the RP's client_id
  8. It contains the presentation_definition containing the information about the requested (Q)EAAs
  9. It contains RP's nonce and state
  10. It contains the purpose given by the RP
  11. RP returns a HTML page to the browser containing a QR-Code to the wallet app (e.g., openid4vp://authorize?client_id=..&request_uri=https://rp.example.com/oidc/request/1234). It also sets a Cookie with the session_id.
  12. The user launches his wallet and hits a button to scan QR-Code from the RP's website.
  13. The wallet decodes the Authorization Request from the QR-Code and starts the OpenID4VP Flow.
  14. The user unlocks the wallet app (see notes below)
  15. The wallet app retrieves the Authorization Request from the RP website (e.g., https://rp.example.com/oidc/request/1234)
  16. The wallet app receives the Authorization Request
  17. The wallet app validates the Authorization Request using the RP's public key
    • Was the signature valid and the key bound to the RP's metadata?
    • Security: This ensures that the Authorization Request was not tampered with; it does not ensure that the party that sent the Authorization Request is the RP.
  18. The Wallet displays information about the identity of the Relying Party and the purpose, the user gives consent to present the (Q)EAA.
  19. (SD-JWT (Q)EAA) The Wallet generates a KB-JWT by signing over nonce, audience, and hash of SD-JWT and selected disclosures with device_priv
  20. (SD-JWT (Q)EAA) The Wallet creates the presentation according to presentation_definition by cutting out the unnecessary Disclosures and appending the KB-JWT
  21. (mdoc (Q)EAA) The Wallet generates an mdoc deviceAuth by signing over SessionTranscript with device_priv
  22. (mdoc (Q)EAA) The Wallet creates the presentation according to presentation_definition by cutting out the unnecessary Releases assembling the issuerAuth with deviceAuth
  23. The wallet app creates a VP token and a presentation submission
  24. The wallet app sends the VP token and presentation submission to the RP (encrypted to the RP's public key rp_eph_pub).
  25. The RP optionally decrypts the Authorization Response with rp_eph_pub received in the Authorization Request.
  26. The RP matches the browser session with the state parameter.
  27. (SD-JWT (Q)EAA) The RP verifies the content of the vp_token. In case of SD-JWT it validates the Issuer signature from the (Q)EAA Provider, verifies the KB-JWT matching to the cnf claim and validates that the KB-JWT is fresh and matches to its own client_id and nonce.
  28. (mdoc (Q)EAA) The RP verifies the content of the vp_token. In case of mdoc it validates the Issuer signature from the (Q)EAA Provider, verifies the deviceAuth matching to the deviceKey and validates that the SessionTranscript is fresh and matches to its own client_id and nonce.
  29. The RP responds with HTTP 200 and acknowledges the received vp_token.
  30. The browser refreshes the RP's website, either by polling regularly or by receiving a signal from the RP, e.g. through websockets. It sends a HTTP GET request using the Cookie set in the beginning of the protocol.
  31. The RP matches the session_id from the Cookie and matches this with the verification result.
  32. The RP considers the user to be identified in the session context and continues the UX flow.

Usability Considerations

Common Considerations

  • Relying Party should inform users in advance of what is required for the process to be completed successfully and what steps to follow
  • For reasons of transparency and to increase trust, Relying Parties should provide sufficient information (metadata) for the consent screen. This allows users to learn everything relevant e.g. about the relying party itself, privacy and data retention
  • The user's data values for the requested attributes can be displayed on the consent screen
  • The user only needs to confirm the (Q)EAA presentation with the Device Authenticator

Same Device Considerations

  • It needs to be clarified whether the wallet app needs to be unlocked in this flow, as the device authenticator is requested again directly after the consent screen. This might create friction and feel redundant to users
  • It must be ensured that users are returned to the correct tab in the correct browser in order to continue the process or users know how to get there manually, if necessary (especially for iOS devices, if the process was not started in the default browser)

Cross Device Considerations

  • It needs to be clarified whether the wallet app needs to be unlocked in this flow and how this should be implemented.
  • User can then continue with the process on the RP page on the second device (page must be updated accordingly by the RP)

Privacy Considerations

  • Selective Disclosure is achieved by ensuring that the presentation contains only those data items (claims) that are requested by the RP. The selective disclosure features of SD-JWT are used to this end.
  • Unlinkability has to be achieved with batch issuance
  • In Presentation Step 5, a malicious app may spoof the wallet app; an attacker may
  • on his own device: Capture the request and replay it to a victim on another device, thus having the victim identify itself in a context of the attacker (Relaying Attack breaking Identification Context); or
  • on the victim's device: Capture the request and spoof the whole identification process or parts of it (Wallet App Spoofing).
  • In Presentation Step 5: An attacker acting as an RP can forward a request from a different RP.
  • As long as the request remains unchanged, we're in the Relaying Attack breaking Identification Context
  • If the attacker changes anything in the request, this will break the signature. The attacker could otherwise attempt to
    • insert his own ephemeral key, leading to an SD-JWT artifact that could be used in a different flow between the attacker and some other RP.
    • modify state or nonce or other data. Q: Any useful attacks resulting from this?
  • In Presentation Step 14: The RP must not consider the user identified at this point; it is important to have the browser redirect in the later steps.

Security Considerations

TBD