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
Standard | Acronym(s) | Version | Reference |
---|---|---|---|
OpenID for Verifiable Presentations | OpenID4VP | draft 20 | https://openid.net/specs/openid-4-verifiable-presentations-1_0-20.html |
Presentation Exchange | 2.0.0 | https://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.0 | JARM | https://openid.net/specs/oauth-v2-jarm-final.html | |
Selective Disclosure for JWTs | SD-JWT | draft 05 | https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-05.html |
Self-Issued OpenID Provider v2 | SIOPv2 | Not supported | https://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
isopenid4vp://
client_id_scheme
MUST be used in Wallet Invocation URL and Authorization Request (JAR)client_id_scheme
value MUST bedid
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 JARclient_metadata_uri
parameter is not supported
client_metadata.jwks
MUST be definedjwks_uri
is not supported- See JWT Secured Authorization Request (JAR)
client_metadata.vp_formats
MUST be compatible with credential formats that EUDIW Demo supportsresponse_type
MUST bevp_token
id_token
is not supported
presentation_definition
parameter MUST be used to send the Presentation Definitionpresentation_definition_uri
parameter is not supportedscope
parameter is not supported
response_mode
value MUST bedirect_post.jwt
- other
response_mode
values are not supported
- other
response_uri
parameter MUST be usedredirect_uri
parameter MUST NOT be used in Authorization Request withresponse_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
- have a domain name & website, that can be represented as a did:web identifier
- have a cryptographic private key for signing Authorization Request
- 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.
https://example.com => did:web:example.com https://example.com/auth => did:web:example.com:auth
did:web:example.com => https://example.com/.well-known/did.json did:web:example.com:auth => https://example.com/auth/did.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.
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)
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
{ // 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.
{ "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.
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
- alg: ECDH-ES (https://datatracker.ietf.org/doc/html/rfc7518#section-4.6).
- enc: A256CBC-HS512 (https://datatracker.ietf.org/doc/html/rfc7518#section-5.1)
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.
{ // 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:
{ "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:
{ "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).
<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.
{ "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.
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.
# | Step | Example | |
---|---|---|---|
1 | User initiates authentication sequence from the Verifier web site. | ||
2 | Verifier starts the authentication and creates:
| Example Wallet Invocation URL | |
3 | Verifier forwards the authentication request for EUDIW Demo application by
| ||
4 | EUDIW Demo application receives the Wallet Invocation
| ||
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 | |
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
EUDIW Demo application creates Authorization Response (JARM payload):
| 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. | ||
16 | Verifier validates the received response. | ||
17 | Verifier responds with redirect_uri containing a response_code generated by the verifier. | ||
18 | EUDIW Demo application opens the received redirect_uri in a new browser session. | ||
19 | Redirect_uri opened in the browser contains a confirmation request. User is requested to verify the session to mitigate possible session fixation attacks. | ||
20 | After receiving user confirmation, the response_code is posted from the browser to the verifier. | ||
21 | Verifier 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 schemesrequest_object_signing_alg_values_supported
: an array containing supported algorithms for signing JARresponse_types_supported
: an array containing supported values for JAR.payload.response_typeresponse_modes_supported
: an array containing supported values for JAR.payload.response_modevp_formats_supported
: an object containing supported fields and values for JAR.payload.client_metadata.vp_formatsvp_formats_supported.sd_jwt.alg_values_supported
: an array containing supported algorithms for signing SD-JWTvp_formats_supported.kb_jwt.alg_values_supported
: an array containing supported algorithms for signing KB-JWTauthorization_encryption_alg_values_supported
: an array containing the method to generate key for decrypting JARM contained by the authentication responseauthorization_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).
{ "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
Version | Date | Changes |
---|---|---|
1 | 2023-10-18 | First published version |
2 | 2024-04-05 | Document updated to follow OpenID4VP draft 20 implementation. Notable changes in implementation:
|