The remote flow has two forms. In the Same Device flow the user-agent and the Wallet Instance are on the same device. In the Cross Device flow they are on different devices. The normative invocation rules are specified in Steps 4-7.
A High-Level description of the remote flow, from the User's perspective, is given below and shown in High Level Remote Protocol Flow.:
Authorization Request: the Wallet Instance obtains a URL in the Same Device flow or a QR Code in the Cross Device flow. The URL contains client_id and request_uri. The normative URL content is specified in Steps 4-7.
Request URI Request: the Wallet Instance reads client_id, request_uri, and optional request_uri_method from the outer Authorization Request before retrieving the Request Object. Retrieval is specified in Steps 9-11.
Request URI Response: the Relying Party returns a signed Request Object to the Wallet Instance.
WI Checks: the Wallet Instance selects exactly one trust path from the client_id prefix and verifies the Request Object under that path, as specified in Selection at Presentation and in Steps 12-15.
Authorization Response: the Wallet Instance presents the requested information using direct_post.jwt.
RP Checks: The Relying Party validates the encrypted response and presented Credentials. Trust in each presented Credential follows Trust Framework Selection and is independent of the Relying Party's Trust Framework.
Relying Party Response: the Wallet Instance informs the User about the successful authentication with the Relying Party, and the User continues the navigation.
Below is a sequence diagram that details the interactions between all the involved parties.
The details of each step shown in the previous picture are described below.
Steps 1-2: The User requests to access to a protected resource of the Relying Party.
Step 3: The Relying Party creates a fresh, cryptographically random state value with sufficient entropy, binds it to the user-agent session (e.g., using an HTTP secured cookie), and stores it server-side with a short expiration time. It then inspects the user-agent to determine whether the flow occurs on the same device as the user-agent.
Steps 4-7 (Authorization Request): The Relying Party invokes the Wallet Instance and passes the Authorization Request by reference.
The Relying Party MUST support both of the following remote flows (RPR-84):
Same Device: the Relying Party MUST provide the Wallet Instance with an HTTP URL using a redirect (302) or an HTML href (RPR-01).
Cross Device: the Relying Party MUST provide a QRCode which the User frames with the device camera or with the Wallet Instance (RPR-03).
The Relying Party SHOULD invoke the Wallet Instance of the Wallet Solution that the User chooses.
The User SHOULD indicate the Wallet Solution on the Selection Page described in User Experience Design.
When the Selection Page is supported, the User selects the Wallet Solution. The Relying Party then retrieves the Wallet metadata as described in Wallet Metadata Retrieval Flow.
When authorization_endpoint is present in the Wallet metadata and its value is an HTTPS URL, that URL is a universal link. The operating system associates that URL with the installed Wallet Instance and starts that Wallet Instance when the User opens it. The Relying Party SHOULD place that URL in the HTML href of the Same Device flow or in the QR Code of the Cross Device flow.
When authorization_endpoint is absent, or when its value is not an HTTPS URL, on the EUDIW path the Relying Party MUST use eu-eaap://.
The Wallet Instance MUST support eu-eaap:// for its authorization_endpoint ([ETSI TS 119 472-2] clause 6.4.1, OIDFVP-HAIP-REDIRECTS-03).
The Wallet Instance MUST support openid4vp://. openid4vp:// is defined in Section 13.1.2 of [OpenID4VP].
The Wallet Instance MUST support haip-vp://. haip-vp:// is defined in Section 5.1 of [OPENID4VC-HAIP].
When authorization_endpoint is absent, or when its value is not an HTTPS URL, on the National path the Relying Party MUST use one of openid4vp://, haip-vp://, and eu-eaap://.
When the Relying Party does not support the Selection Page, or when Wallet metadata retrieval fails, the Relying Party MUST invoke the Wallet Instance with the scheme required above for that path.
For a redirect flow, the Relying Party provides the user-agent with a JavaScript page inspecting the status endpoint and the Wallet Instance with a URL containing the Authorization Request. The Request Object is passed by reference only. The URL MUST contain client_id and request_uri. The URL MUST NOT contain request, as detailed in OPENID4VC-HAIP.
In the Cross Device Flow, the Authorization Request is presented as a QR Code displayed to the User. The User scans the QR Code using the Wallet Instance and retrieves a URL.
Below is represented a non-normative example of a QR Code issued by the Relying Party.
Note
The error correction level chosen for the QR Code MUST be Q (Quartily - up to 25%), since it offers a good balance between error correction capability and data density/space. This level of quality and error correction allows the QR Code to remain readable even if it is damaged or partially obscured (RPR-77).
The URL inside the QR Code contains client_id, request_uri, and optional request_uri_method parameters (WP_076–077).
Below is represented a non-normative example of the QR Code raw payload with Request Object by reference:
An official, self-contained HTML template for this Cross Device QR code page—including header, footer, accessibility, multilingual copy, and a configurable demonstrative payload—is provided in the HTML Components section (IT-Wallet Presentation QR Code Page). It is linked from the wallet cards on the IT-Wallet Selection Page in the same section.
Conversely, in the Same Device Flow, the Relying Party uses an HTTP response redirect (with status code set to 302) or an HTML page with an href button (WP_076–077).
For the EUDIW path, the URL uses client_id with the x509_hash prefix, eu-eaap:// invocation, and request_uri.
For the National path it uses the openid_federation prefix.
Below is a non-normative example with Request Object by reference:
Steps 9-11 (Request URI Request): The Wallet Instance reads request_uri_method from the outer Authorization Request before retrieving the signed Request Object (WP_083).
If it is provided and is equal to post, the Wallet Instance MUST provide its metadata to the Relying Party with an HTTP POST request and content type application/x-www-form-urlencoded. The Relying Party updates the Request Object according to the Wallet Instance technical capabilities.
The following is a non-normative example of an HTTP request made by the Wallet Instance to the Relying Party.
If request_uri_method is equal to get or is not present, the Wallet Instance MUST request the signed Request Object using HTTP GET (WP_082).
Step 12 (Request URI Response): The Relying Party issues the Request Object by signing it with one of its cryptographic private keys.
For openid_federation, the Wallet Unit MUST evaluate trust using the Federation Entity Authentication and National Authorization (Federation Entity Authentication and Authorization). The Wallet Unit MUST obtain the openid_credential_verifier metadata through Metadata Retrieval and Validation. The Wallet Unit MUST verify the signature with the key identified by kid in that metadata.
For x509_hash, the Wallet Unit MUST verify the leaf certificate hash against client_id. The Wallet Unit MUST validate the WRPAC path against the Providers of WRPAC LoTE. The Wallet Unit MUST verify the signature with the WRPAC key, as defined in EUDIW Authentication.
The Wallet Instance MUST NOT switch paths (WP_084).
The Wallet Instance MUST NOT retry verification with evidence from the other path.
Below is a non-normative example of the Redirect URI Response:
Steps 13-15 (WI Checks): The Wallet Instance verifies the Request Object, which is in the form of a signed JWT, and checks that the outer-request and signed-request client_id, iss, and Relying Party identity are consistent under the selected prefix (WP_085–086).
The following are non-normative examples of Request Objects in the form of decoded headers and payloads. Each example uses exactly one trust framework.
The following non-normative example is the EUDIW Request Object that uses x509_hash.
For x509_hash, the Wallet Instance authenticates the WRPAC, validates the WRPRC, and binds the direct or intermediated Relying Party identity to the WRPAC, WRPRC, and the data.identifier member of the verifier_info element whose format is registrar_dataset according to EUDIW Authentication and EUDIW Authorization. It checks the Service Provider entitlement and the exact, case-sensitive DCQL scope.
For openid_federation, the Wallet Instance validates the registration Trust Mark, its entitlements, and its exact, case-sensitive scope. The Wallet Instance MUST NOT treat WRPAC or WRPRC material as National trust evidence.
A failed evaluation terminates processing. The Wallet Instance MUST NOT trigger a retry under the other framework (WP_087).
Steps 16-17 (User Consent): Before disclosure, the Wallet Instance MUST display the verified Relying Party. The Wallet Instance MUST display the verified Service. The Wallet Instance MUST display the intended use or purpose. The Wallet Instance MUST display the requested Credentials from the authoritative authorization artifact. The Wallet Instance MUST display the requested attributes from the authoritative authorization artifact. On the National path, the Wallet Instance MUST also display the Federation Intermediate when applicable. In an EUDIW intermediated flow, the Wallet Instance MUST display the intermediated Relying Party. The Wallet Instance MUST NOT display Intermediary trade names. The User authorizes and consents to presentation by selecting the data to release (WP_088).
Step 18 (Authorization Response): The Wallet Instance provides the encrypted Authorization Response to the Relying Party using an HTTP POST with response mode direct_post.jwt.
Below is a non-normative example of the Authorization Response:
Below is a non-normative example showing the decrypted JWE protected header and the payload of the JWT contained in the response, before base64url encoding. The vp_token parameter value corresponds to the format used when the DCQL query language is used in the presentation request.
{"state":"3be39b69-6ac1-41aa-921b-3e6c07ddcb03","vp_token":{"personal id data":["eyJhbGciOiJFUzI1NiIs...PT0iXX0"],"mobile driving license":["o2Nkb2N0eXBlb3Jzby4xO...Nib3JfZHVtbXk"]}}
Note
When returning a requested Credential in mso_mdoc format in the vp_token, the Wallet Instance MUST cryptographically bind the mdoc presentation to the current OpenID4VP transaction, as defined in OpenID4VP Appendix B.2.
Steps 19-22 (RP Checks): The Relying Party verifies the encrypted Authorization Response, extracts the vp_token, and validates its overall format and each presentation against the DCQL query.
For SD-JWT VC, issuer-key resolution MUST use the X.509 x5c chain excluding the trust anchor and a non-self-signed signing certificate.
The Relying Party MUST validate the issuer signature.
The Relying Party MUST validate the holder signature.
The Relying Party MUST validate the proof of possession.
The status check is specified in Checking Credentials Statuses.
Presentation-signature validation MUST support at least ES256 on P-256 with SHA-256.
Hash validation MUST support SHA-256.
Trust in each presented Credential is governed by that Credential's Rulebook and is independent of the Relying Party trust path.
Selecting x509_hash MUST NOT imply Federation-based Credential Issuer trust.
If all verifications succeed, the Relying Party updates the User session.
Steps 23-24 or 25 (Relying Party Response): The Relying Party provides to the Wallet Instance the response about the presentation, which informs the User.
Upon receiving and validating the Authorization Response at the Response Endpoint, the Relying Party returns to the Wallet Instance an HTTP 200 OK.
In the Same Device Flow, the Relying Party MUST include the redirect_uri parameter in the response to the Wallet Instance (RPR-83).
Upon receiving the redirect_uri, the Wallet Instance MUST perform a redirect to the URL specified by the redirect_uri.
In the Cross Device Flow, the response does not include redirect_uri.
The Wallet Instance does not redirect.
The following is a non-normative example of the response in the Same Device Flow.
When the Wallet Instance has provided the presentation to the Relying Party's response_uri endpoint and, in the Same Device Flow, the user-agent has successfully returned via redirect_uri within the same user session, the User authentication is successful. The Relying Party updates the session cookie allowing the user-agent to access to the protected resource. A redirect URL is provided carrying the location where the user-agent is intended to navigate.
The following is a non-normative example of the response with the redirect_uri from the Relying Party to the user-agent.
Steps 28-29: In the Same Device Flow, the user-agent is redirected to the redirect URI to continue the navigation with the protected resource made available to the User (WP_094). The Relying Party MUST consider the transaction completed only if the redirect back is received in the same user session in which the flow was initiated. Otherwise the Relying Party MUST reject the presentation.
In the Cross Device Flow, completion does not depend on that redirect.
Note
During each Credential presentation transaction executed through the remote flow, the Wallet Instance MUST create and maintain a corresponding transaction record in the transaction log (see Wallet Instance Dashboard and Transaction Logging).
The transaction record MUST be created once the Wallet Instance has accepted the presentation request for processing (i.e., after request validation and Relying Party trust/policy checks, Steps 13–15). At this point, the record MUST include the transaction metadata and the request context available at that stage (e.g., the requested Credential type(s) and the identifier(s) of the requested attributes), without logging any attribute values.
The record MUST be updated as the transaction progresses to reflect the evolving transaction state and result context (e.g., what was actually presented after User consent and response preparation/sending, Steps 16–18), without logging any attribute values.
The record MUST be finalized when the transaction ends, indicating the outcome (e.g., completed, failed, or aborted. Steps 23–29).
The URL parameters contained in the Relying Party Authorization Request are described in the table below.
Name
Description
client_id
REQUIRED. Unique identifier of the Relying Party. The value MUST use one of the following Client Identifier Prefixes (as defined in OpenID4VP, Section 5.9): openid_federation (Relying Party’s Entity Identifier in a Trust Chain) or x509_hash (base64url-encoded SHA-256 hash of the Relying Party’s X.509 certificate).
request_uri
REQUIRED. The HTTPS URL where the Relying Party provides the signed Request Object to the Wallet Instance. The Request Object MUST be retrieved by reference.
request_uri_method
OPTIONAL only if request_uri is present. Otherwise it MUST NOT be present. The value MUST be get or post (RPR-07, RPR-08, RPR-09). If it is not provided or is equal to get, the Wallet Instance MUST fetch the Request Object with HTTP GET. If it is equal to post, the Wallet Instance MUST provide its metadata in the HTTP POST body, encoded as application/x-www-form-urlencoded.
Note
The value corresponding to the request_uri endpoint SHOULD be randomized, according to RFC 9101#section-5.2.1.
For redirect flows, to prevent endpoint mix-up attacks, the values of request_uri, response_uri and redirect_uri MUST each be attested by a trusted third party.
Under the National Trust Framework, the Wallet Unit MUST evaluate trust using the Federation Entity Authentication and National Authorization (Federation Entity Authentication and Authorization), and the values MUST match the corresponding request_uris, response_uris and redirect_uris parameters in the openid_credential_verifier metadata obtained through Metadata Retrieval and Validation.
Under the EUDIW Trust Framework they MUST satisfy the WRPAC/WRPRC identity and endpoint binding, as specified in EUDIW Authentication and EUDIW Authorization. Evidence from the unselected framework MUST NOT authorize an endpoint.
This requirement applies to request_uri as specified in WP_081 and RPR-85.
The Relying Party SHOULD provide the POST method with its request_uri endpoint allowing the Wallet Instance to inform the Relying Party about its technical capabilities.
This feature can be useful when, for example, the Wallet Instance supports a restricted set of features, supported algorithms or a specific url for its authorization_endpoint, and any other information that it deems necessary to provide to the Relying Party for interoperability.
Warning
The Wallet Instance, when providing its technical capabilities to the Relying Party, MUST NOT include any User information or other explicit (RPR-86) information regarding the hardware used or usage preferences of its User (RPR-86).
When request_uri_method is post, the Wallet Instance provides the metadata as specified in Steps 9-11 (WP_083).
The request and its parameters are defined in Section 5 (Authorization Request) of OpenID4VP. Below are the normative details and references about the parameters to be used by the Wallet Instance in the request (WP_083a–083c).
REQUIRED in the request body when request_uri_method is post. JSON object with metadata parameters. See OpenID4VP, Section 10.1 and the table below, "Wallet Metadata Parameters".
wallet_nonce
RECOMMENDED. String used by Wallet Instance to prevent replay of the Relying Party's responses.
REQUIRED. Object containing a list of name/value pairs, where the name is a Credential Format Identifier and the value defines format-specific parameters that a Wallet supports. See OpenID4VP Appendix B. Wallet Instances MUST support the Credential Format Identifiers required by OPENID4VC-HAIP (including dc+sd-jwt and mso_mdoc).
client_id_prefixes_supported
REQUIRED. A non-empty array of the Client Identifier Prefixes that the Wallet Instance supports. Wallet Instances MUST include both x509_hash (EUDIW / [OPENID4VC-HAIP]) and openid_federation (National Trust Framework).
request_object_signing_alg_values_supported
OPTIONAL. See OpenID Connect Discovery.
Note
In the IT Wallet, legacy Relying Parties using an https URI as client_id are treated as using the openid_federation prefix for backward compatibility. Their trust is established and validated through Trust Chain resolution. This does not define a third client identifier path or a pre-registered default.
Note
The wallet_nonce parameter is RECOMMENDED for Wallet Instances that want to prevent reply of their http requests to the Relying Parties.
When present, the Relying Party MUST evaluate it (RPR-81).
The Relying Party issues the signed Request Object using the content type set to application/oauth-authz-req+jwt. For the content of the Request Object see Section Request Object.
When the Relying Party encounters errors while issuing the Request Object from the request_uri endpoint, it MUST return an error response with application/json as the content type.
The response MUST include the following parameters:
error: The error code.
error_description: Text in human-readable form providing further details to clarify the nature of the error encountered.
The following table lists the HTTP Status Codes and related error codes that MUST be supported for the error response:
Status Code
Error Code
Description
400BadRequest
invalid_request
The Request Object could not be retrieved due to an invalid or malformed request at the request_uri endpoint. (RFC 6749#section-4.1.2.1).
500InternalServerError
server_error
The request cannot be fulfilled because the Request URI Endpoint encountered an internal problem. (RFC 6749#section-4.1.2.1).
503ServiceUnavailable
temporarily_unavailable
The request cannot be fulfilled because the Request URI Endpoint is temporarily unavailable (e.g., due to maintenance or overload). (RFC 6749#section-4.1.2.1).
The following is an example of an error response from request_uri endpoint:
HTTP/1.1500Internal Server ErrorContent-Type:application/json{"error":"server_error","error_description":"The Request Object cannot be retrieved due to an internal server error."}
Upon receiving an error response, the Wallet Instance SHOULD inform the User of the error condition in an appropriate manner (WP_089).
The Wallet Instance SHOULD log the error (WP_089a).
The Wallet Instance MAY attempt to recover from certain errors if feasible.
Recovery MUST remain within the selected transport and trust path.
A new QR code MAY be offered where applicable (WP_089b).
REQUIRED. Algorithm used to sign the JWT, according to [RFC 7516#section-4.1.1]. It MUST be one of the supported algorithms in Section Cryptographic Algorithms. It MUST NOT be set to none or to a symmetric algorithm (MAC) identifier. For signed presentation-request validation, implementations MUST support at least ES256 using P-256 and SHA-256 (RPR-88).
typ
REQUIRED. Media Type of the JWT, as defined in [RFC 7519] and [RFC 9101]. The value MUST be oauth-authz-req+jwt (RPR-89).
kid
On the National path only. REQUIRED when client_id uses the openid_federation prefix. It identifies the public key in the Federation metadata obtained after Federation Entity Authentication and Metadata Retrieval and Validation, as defined in [RFC 7517]. It is not EUDIW authentication evidence.
trust_chain
On the National path only. OPTIONAL sequence of Entity Statements composing the Relying Party Trust Chain, as defined in OID-FED Section 4.3 Trust Chain Header Parameter. It is not EUDIW authentication evidence.
x5c
On the EUDIW path only. REQUIRED when client_id uses the x509_hash prefix. It contains the WRPAC first, followed by its cryptographic chain up to but excluding the trust anchor. The WRPAC MUST be used to verify the JWT signature. The chain MUST be valid against the Providers of WRPAC LoTE, as defined in EUDIW Authentication. The WRPAC binds the Relying Party identity and applicable presentation endpoints according to EUDIW Authorization. It is not National authentication evidence.
Note
For x509_hash, the x5c header MUST contain the WRPAC first. The x5c header MUST NOT include the trust anchor, as required by OPENID4VC-HAIP. The chain MUST validate to a trust anchor obtained from the Providers of WRPAC LoTE according to EUDIW Authentication. See Section X.509 Certificate Profile for background on X.509 certificate chain validation.
The JWT payload parameters are described herein:
Name
Description
client_id
REQUIRED. Unique Identifier of the Relying Party. It MUST use the same prefix-qualified value as the Authorization Request. It MUST identify the same Relying Party as iss and the selected trust evidence.
client_metadata
REQUIRED for both paths. A JSON object containing the Relying Party metadata values defined in Section 5.1 of OpenID4VP. It contains the following parameters:
jwks. REQUIRED by [ETSI TS 119 472-2]. Contains the request-specific ephemeral response-encryption public key and the applicable response-encryption capabilities. Every key MUST have kid and use. Each kid MUST identify exactly one key. The Verifier metadata MUST list both A128GCM and A256GCM. For x509_hash, applicable RP metadata is carried here.
vp_formats_supported. Used by the Wallet Instance to determine the supported Verifiable Presentation formats.
client_name and logo_uri. OPTIONAL. Used for user consent display and to show the Relying Party identity in the Wallet Instance interface.
REQUIRED on the EUDIW path. It MUST identify the intended Wallet audience and be consistent with the selected client_id and Relying Party identity.
dcql_query
REQUIRED. Object representing a request for a presentation of Credentials, according to the DCQL query language defined in Section 6 of OpenID4VP. On the EUDIW path, each applicable query MUST use the ETSI Trusted Lists Authority Key Identifier mechanism with trusted_authorities type etsi_tl.
Each object MUST contain format and data.
The array MUST contain one object whose format is registrar_dataset.
Its data MUST be a non-empty object containing the registered identifier, srvDescription, registryURI, intendedUseIdentifier, purpose and policyURI members.
srvDescription and purpose MUST use registered MultiLangString values.
The array MUST contain one object whose format is registration_cert.
Its data MUST be the base64url serialization of the WRPRC.
The array MUST NOT contain credential_ids [ETSI TS 119 472-2].
These objects are not required for openid_federation, whose equivalent authorization and transparency data comes from the validated registration Trust Mark (see Metadata Retrieval and Validation).
transaction_data
OPTIONAL. Non-empty array of strings. Each string is a base64url-encoded JSON object describing a transaction that the Relying Party requests the User to authorize, as defined in Section 5.1 of OpenID4VP. The decoded object includes:
type. String that identifies the transaction data type.
credential_ids. Array referencing one or more Credentials from the dcql_query that can authorize the transaction.
transaction_data_hashes_alg. OPTIONAL, and only for dc+sd-jwt. Array of strings, each a hash algorithm identifier listed in the IANA Named Information Hash Algorithm Registry. One of these algorithms MUST be used to calculate the hashes in the transaction_data_hashes parameter of the Key Binding JWT. If omitted, the hash algorithm MUST be sha-256. See OpenID4VP, Appendix B.3.3.
REQUIRED if previously provided by Wallet Instance (RPR-81). String value used to mitigate replay attacks of the response, as defined in Section 5.10 (Request URI Method) of OpenID4VP.
response_uri
REQUIRED. The Response URI to which the Wallet Instance MUST send the Authorization Response using an HTTP request using the method POST (RPR-92).
nonce
REQUIRED. Fresh cryptographically random number with sufficient entropy, which length MUST be at least 32 digits (RPR-93).
state
RECOMMENDED. Unique identifier of the Authorization Request, its value SHOULD be opaque to the Wallet Instance.
iss
REQUIRED. The entity that has issued the JWT. It MUST equal the prefix-qualified client_id and the Authorization Request issuer's identity.
iat
REQUIRED. Unix Timestamp, representing the time at which the JWT was issued.
exp
REQUIRED. Unix Timestamp, representing the expiration time on or after which the JWT MUST NOT be valid anymore (RPR-94).
When transaction_data is present, the Wallet Instance binds the transaction details to the Authorization Response using the Credential format mechanism.
dc+sd-jwt: the Wallet Instance MUST return transaction_data_hashes and, when applicable, transaction_data_hashes_alg inside the Key Binding JWT (KB-JWT). See OpenID4VP Appendix B.3.3.
mso_mdoc: the Wallet Instance MUST bind the data through mdoc device authentication, as defined in OpenID4VP Appendix B.2.1. If the type is not supported by the document type or is not authorized by the issuer (KeyAuthorizations), the Wallet Instance MUST reject the request.
Note
The state parameter binds the Authorization Request to the response and lets the Relying Party recognize the session. It is used to prevent Cross-Site Request Forgery (CSRF) attacks by including a unique and unpredictable value.
Note
client_metadata and client_metadata.jwks are required on both profiled paths because every request supplies a request-specific ephemeral response-encryption public key [ETSI TS 119 472-2].
On the National path, the Wallet Unit MUST obtain the verifier metadata from the Trust Chain (RPR-96).
client_metadata MUST NOT replace that metadata.
client_metadata.jwks and the response-encryption parameters carry the request-specific ephemeral key.
After obtaining the User authorization and consent for the presentation of the Digital Credentials, the Wallet Instance sends the Authorization Response to the Relying Party response_uri endpoint using an HTTP POST (WP_091).
When the Wallet Instance uses a batch Credential, the Wallet Instance SHOULD implement a Credential selection logic, for example based on the earliest expiring Credential. The Wallet Instance MUST mark the selected Credential as consumed. At the end of the flow, the Wallet Instance MUST decrease the number of available Credentials in the batch. The Wallet Instance can use that number to control when it needs to obtain a new batch of Credentials.
Every successful response MUST be encrypted using the request-specific ephemeral public key selected from client_metadata.jwks by its unique kid (WP_092).
Every successful response MUST use direct_post.jwt.
The Verifier MUST support both A128GCM and A256GCM.
The Wallet Instance MUST support at least one of A128GCM and A256GCM.
The Wallet Instance SHOULD prefer A256GCM when both are available [ETSI TS 119 472-2].
Note
Why the response is encrypted?
The response sent from the Wallet Instance to the Relying Party is encrypted to prevent a malicious agent from gaining access to the plaintext information transmitted within the Relying Party's network. This is only possible if the network environment of the Relying Party employs TLS termination. Such technique employs a termination proxy that acts as an intermediary between the client and the webserver and handles all TLS-related operations. In this manner, the proxy deciphers the transmission's content and either forwards it in plaintext or by negotiates an internal TLS session with the actual webserver's intended target. In the first scenario, any malicious actor within the network segment could intercept the transmitted data and obtain sensitive information, such as an unencrypted response, by sniffing the transmitted data.
This object MUST contain the presented Digital Credential(s), keyed by the Credential id values from the dcql_query in the Authorization Request.
The vp_token MUST be a JSON Object where each key corresponds to a requested Credential id, and each value is either a single presentation or an array of one or more presentations for that Credential. The encoding of each presentation depends on the Credential format, for example:
dc+sd-jwt: a compact-serialized SD-JWT VC string. The Wallet MUST append a KB-JWT whenever the presentation is cryptographically holder-bound (WP_093a).
mso_mdoc: a base64url-encoded CBOR DeviceResponse corresponding to the requested mdoc presentation (see OpenID4VP Appendix B.2). When multiple mdoc presentations are returned, each MUST be carried in a separate DeviceResponse aligned with the corresponding DCQL query item. In this case, the vp_token value for that Credential id MUST be an array of DeviceResponse values.
state
Unique identifier provided by the Relying Party within the Authorization Request.
Note
Although OpenID4VP considers SD-JWT-based Verifiable Credentials (SD-JWT VC) draft -10, the IT Wallet specification considers SD-JWT VC draft -13 (SD-JWT-VC) to be in line with the version identified in OpenID4VCI.
SD-JWT defines how a Holder can present a Digital Credential to a Relying Party, proving the legitimate possession of the Digital Credential. To do this, the Holder MUST include the KB-JWT in the SD-JWT by appending the KB-JWT at the end of the SD-JWT (WP_093b), as represented in the example below
To validate the signature on the Key Binding JWT, the Relying Party MUST use the key material included in the Issuer-Signed-JWT. The Key Binding JWT (KB-JWT) signature validation MUST use the public key included in the SD-JWT, using the cnf parameter contained in the Issuer-Signed-JWT.
When an SD-JWT is presented, its KB-JWT MUST contain the following parameters in the JWT header (WP_093c):
Claim
Description
typ
REQUIRED. MUST be kb+jwt, which explicitly types the Key Binding JWT as recommended in Section 3.11 of RFC 8725.
alg
REQUIRED. Signature Algorithm using one of the specified in the Section Cryptographic Algorithms.
When an SD-JWT is presented, the KB-JWT signature MUST be verified by the same public key included in the SD-JWT within the cnf parameter. The KB-JWT MUST contain the following parameters in the JWT payload:
Claim
Description
iat
REQUIRED. The value of this claim MUST be the time at which the Key Binding JWT was issued, using the syntax defined in RFC 7519.
aud
REQUIRED. The intended receiver of the Key Binding JWT. The value MUST be the Client Identifier (client_id) of the Relying Party, including its Client Identifier Prefix (openid_federation or x509_hash). For example, openid_federation:https://relying-party.example.org.
nonce
REQUIRED. Ensures the freshness of the signature. The value type of this claim MUST be a string. The value MUST match with the one provided in the request object.
sd_hash
REQUIRED. The base64url-encoded hash digest over the Issuer-signed JWT and the selected disclosures.
transaction_data_hashes
REQUIRED when the request includes transaction_data. Non-empty array of base64url-encoded hashes. Each hash is computed over the exact string value of the corresponding transaction_data item.
transaction_data_hashes_alg
REQUIRED only when the corresponding transaction_data object includes transaction_data_hashes_alg. String naming the hash algorithm actually used to compute transaction_data_hashes. If that parameter was not provided, the hash function MUST be sha-256.
There are cases where the Wallet Instance cannot validate the Request Object or the Request Object results invalid. This error occurs if the Request Object is successfully fetched from the url provided in the parameter request_uri but fails the validation checks. This could be due to incorrect signatures, malformed claims, or other validation failures, such as the revocation of the Relying Party.
If the Wallet Instance encounters an error during evaluation, it MUST send an Authorization Error Response only after the selected trust path has authenticated the applicable response_uri.
If the request or endpoint has not been authenticated, the Wallet Instance MUST terminate locally.
The Wallet Instance MUST notify the User.
The Wallet Instance MUST NOT disclose Wallet or Credential availability (WP_090).
For an authenticated redirect flow, the Wallet Instance sends the Authorization Error Response to the Relying Party response_uri endpoint using an HTTP POST request.
The error response MAY be unencrypted only where OpenID4VP permits it (WP_090).
The Authorization Error Response MUST be encoded in the request body using the format defined by the application/x-www-form-urlencoded content type.
Below is a non-normative example of an Authorization Error Response.
An error from one trust path is handled as specified in Failure Handling.
In the following table are listed error codes and descriptions that are supported for the Authorization Error Response:
Error Code
Description
invalid_request_uri
The request_uri in the authorization request returns an error, contains invalid data, or is otherwise malformed. RFC 9101
vp_formats_not_supported
The Wallet Instance does not support any of the vp formats required by the Relying Party. OpenID4VP
invalid_request_uri_method
The value of the request_uri_method parameter is neither get nor post. OpenID4VP
invalid_request
The request is malformed or inconsistent (e.g., it uses the vp_token Response Type but it does not include a dcql_query parameter), the Client Identifier Prefix is unsupported, or requirements of a prefix are violated (e.g., client_id with the x509_hash prefix without the required client_metadata). OpenID4VP
access_denied
The Wallet did not have the requested Credential, the User did not consent, or the Wallet failed to authenticate the User. OpenID4VP
invalid_client
The selected Relying Party trust path cannot authenticate or authorize the Relying Party. See Failure Handling. OID-FED and OpenID4VP
invalid_transaction_data
One or more objects in the transaction_data structure are invalid. For instance, those objects contain unknown or unsupported types, malformed (e.g., it is an object of a known type but containing unknown fields or contains fields of the wrong type for the transaction data type) or missing fields, invalid values (e.g., the credential_ids does not match), or references to unavailable Credentials. OpenID4VP
As defined in Section 8.2. (Response Mode direct_post) of the OpenID4VP specification, if the Response URI has successfully processed the Authorization Response or Authorization Error Response, it MUST respond with an HTTP status code of 200 with Content-Type of application/json and a JSON object in the response body.
In every successful redirect-based Same Device Flow, the Relying Party MUST add the redirect_uri parameter to the JSON object in the response body. Upon receiving the redirect_uri, the Wallet Instance MUST perform a redirect to the URL specified by the redirect_uri. The Relying Party MUST reject an absent redirect_uri. The Relying Party MUST reject a return in a different initiating user session.
This redirect allows the Relying Party to seamlessly resume interaction with the User on the device which initiated the flow, after the Wallet Instance has transmitted the Authorization Response to the designated response_uri.
The Relying Party MUST include a response code within the redirect_uri. The response code is a fresh, cryptographically random number used to ensure only the receiver of the redirect can fetch and process the Authorization Response. The number could be added as a path component, as a parameter or as a fragment to the URL. It is RECOMMENDED to use a cryptographic random value of 128 bits or more at the time of the writing of this specification.
Even if an adversary manages to steal the random value used in the request to the status endpoint, their user-agent would be rejected due to the missing cookie in the request.
If any validation check, performed by the Relying Party on the Authorization Response from the Wallet Instance, fails, the Response URI endpoint MUST return an error response. The structure of this error response depends on the specific nature of the error encountered. The response MUST use application/json as the content type.
The response MUST include the following parameters:
error: The error code.
error_description: Text in human-readable form providing further details to clarify the nature of the error encountered.
The following table lists the HTTP Status Codes and related error codes that MUST be supported for the error response:
Status Code
Error Code
Description
400BadRequest
invalid_request
The response cannot be processed because it is missing required parameters, contains invalid parameters or is otherwise malformed.
400BadRequest
invalid_request
The Credentials presented are malformed, invalid or revoked.
400BadRequest
invalid_request
The Credential presentation, contained in the vp_token object, is malformed, doesn't have the required parameters or is incorrectly formatted.
400BadRequest
invalid_request
The "sd-jwt" returned is malformed, missing required parameters or incorrectly formatted.
403Forbidden
invalid_request
The signature of the KB-JWT is invalid or does not match the associated public key (JWK) referenced in the Issuer signed SD-JWT.
403Forbidden
invalid_request
The nonce value provided is incorrect or otherwise malformed.
403Forbidden
invalid_request
Trust could not be established with the Credential Issuer.
500InternalServerError
server_error
The request cannot be fulfilled because the Response URI Endpoint encountered an internal problem.
503ServiceUnavailable
temporarily_unavailable
The request cannot be fulfilled because the Response URI Endpoint is temporarily unavailable (e.g., due to maintenance or overload).
Below there are two examples of HTTP responses using application/json that include both the error and error_description members:
HTTP/1.1403ForbiddenContent-Type:application/json{"error":"invalid_request","error_description":"Trust cannot be established with the issuer: https://issuer.example.com"}
HTTP/1.1400Bad RequestContent-Type:application/json{"error":"invalid_request","error_description":"The vp_token is malformed, missing required parameters or incorrectly formatted"}
This specification introduces the Relying Party Status Endpoint for implementations that choose to use it. This endpoint is an internal security feature of the implementation and is not required for interoperability.
When the Relying Party provides the Status Endpoint, this check MAY be implemented in the form of JavaScript code, within the page that shows the QR Code or the href button pointing to the request URL.
The JavaScript code makes the user-agent check the status endpoint using either a polling strategy (in seconds) or a push strategy (e.g., WebSocket).
Since the HTML page and the status endpoint are implemented by the Relying Party, the implementation details of this solution are the responsibility of the Relying Party, as this is related to the Relying Party's internal API. However, the text below describes an example implementation.
The Relying Party binds the request of the user-agent, with a session cookie marked as Secure and HttpOnly, with the issued request.
The request url SHOULD include a parameter with a random value. The HTTP response returned by this status endpoint MAY contain the HTTP status codes listed below:
201 Created. The signed Request Object was issued by the Relying Party that waits to be downloaded by the Wallet Instance at the request_uri endpoint.
202 Accepted. This response is given when the signed Request Object was obtained by the Wallet Instance.
200 OK. The Wallet Instance has provided the presentation to the Relying Party's response_uri endpoint and the User authentication is successful. The Relying Party updates the session cookie allowing the user-agent to access to the protected resource. A redirect URL is provided carrying the location where the user-agent is intended to navigate.
If instead any validation check performed by the Relying Party fails, the QRCode page SHOULD be updated with an error message. Moreover, the status endpoint MUST return an error response, whose structure depends on the nature of the error. The response MUST use application/json as the content type.
The response MUST include the following parameters:
error: The error code.
error_description: Text in human-readable form providing further details to clarify the nature of the error encountered.
The following table lists the HTTP Status Codes and related error codes that MUST be supported for the error response:
Status Code
Error Code
Description
401Unauthorized
authentication_failed
The Wallet Instance or its User have rejected the request, the request is expired, or other errors prevented the authentication.
403Forbidden
invalid_session
Either the session id provided in the request is invalid.
The redirect_uri value MUST be used with an HTTP method GET by the user-agent to redirect the User to a specific Relying Party's endpoint in order to complete the process.
When the user-agent is redirected to the Redirect URI provided by the Relying Party, several errors may occur that prevent the successful completion of the process. These errors are critical as they directly impact the User experience by hindering the seamless flow of information between the Wallet Instance and the Relying Party. Handling these errors requires clear communication to the User within the returned navigation web page. Relying Party MUST implement the error handling and validation mechanisms for Redirect URIs defined in this specification. Below are potential errors related to the Redirect URI. The error response MUST use application/json as the content type.
The response MUST include the following parameters:
error: The error code.
error_description: Text in human-readable form providing further details to clarify the nature of the error encountered.
The following table lists the HTTP Status Codes and related error codes that MUST be supported for the error response:
Status Code
Error Code
Description
403Forbidden
invalid_request
The Redirect URI provided by the Relying Party does not match any of the URIs linked with the User session. (RFC 6749#section-4.1.2.1)