Relying Party Solution¶
This section describes how a Relying Party may request to a Wallet Instance the presentation of the PID and the (Q)EAAs, according to OpenID for Verifiable Presentations - draft 20.
In this section the following flows are described:
Remote Same Device Flow, where the user-agent and the Wallet Instance are used in the same device.
Remote Cross Device Flow, where the user-agent and the Wallet Instance are used in different devices.
In the Same Device and Cross Device Flows described in this chapter, the User interacts with a remote Relying Party.
Note
The provisioning of the Wallet Instance Attestation from the Wallet Instace to the Relying Party is under discussion within the international standardization working groups. At the current stage of the draft of this implementation profile, a mechanism based on OAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer (DPoP) is used.
Remote Protocol Flow¶
In this scenario the Relying Party MUST provide the URL where the signed presentation Request Object is available for download.
Depending on whether the Relying Party client is on a mobile device or a workstation, the Relying Party MUST activate one of the supported remote flows:
Same Device, the Relying Party MUST provide a HTTP redirect (302) location to the Wallet Instance;
Cross Device, the Relying Party MUST provide a QR Code which the User frames with their Wallet Instance.
Once the Wallet Instance establishes the trust with the Relying Party, the User gives the consent for the release of the personal data, in the form of a Verifiable Presentation.
Below a sequence diagram that summarizes the interactions between all the involved parties.
The details of each step shown in the previous picture are described in the table below.
Id |
Description |
---|---|
1, 2 |
The User asks for access to a protected resource, the Relying Party redirects the User to a discovery page in which the User selects the Login with the Wallet button. The Authorization flow starts. |
3, 4, 5 |
The Relying Party creates an Authorization Request which contains the scopes of the request and provides it to the requester. |
6, 7, 8, 9 |
In the Cross Device Flow: the Request URI is provided in the form of a QR Code that is shown to the User. The User frames the QRCode with the Wallet Instance and extracts the Request URI. In the Same Device Flow the Relying Party responses with the Request URI in the form of HTTP Redirect Location (302). |
10 |
The Wallet Instance requests the content of the Authorization Request by invoking the Request URI, passing an Authorization DPoP HTTP Header containing the Wallet Instance Attestation and the DPoP proof HTTP Header. |
11 |
The Relying Party attests the trust to the Wallet Instance using the Wallet Instance Attestation and evaluates the Wallet Instance capabilities. |
12 |
The Relying Party issues a signed Request Object, returning it as response. The |
13, 14, 15, 16 |
The Wallet Instance verifies the Request Object JWS. The Wallet Instance attests the trust to the Relying Party by verifying the Trust Chain. The Wallet Instance verifies the signature of the request and processes the Relying Party metadata to attest its capabilities and allowed scopes, attesting which Verifiable Credentials and personal attributes the Relying Party is granted to request. |
17, 18 |
The Wallet Instance requests the User's consent for the release of the credentials. The User authorizes and consents the presentation of their credentials, by selecting/deselecting the personal data to release. |
19 |
The Wallet Instance provides the Authorization Response to the Relying Party using an HTTP request with the method POST (response mode "direct_post"). |
20, 21, 22 |
The Relying Party verifies the Authorization Response, extracts the credential and attests the trust to the credentials Issuer. The Relying Party verifies the revocation status and the proof of possession of the presented credential. |
23 |
The Relying Party authenticates the User. |
24 |
The Relying Party notifies to the Wallet Instance that the operation ends successfully. |
Cross Device Flow Status Checks and Security¶
When the flow is Cross Device, the user-agent needs to check the session status to the endpoint made available by Relying Party (status endpoint). This check MAY be implemented in the form of JavaScript code, within the page that shows the QRCode, then the user-agent checks the status with a polling strategy in seconds or a push strategy (eg: web socket).
Since the QRcode page and the status endpoint are implemented by the Relying Party, it is under its responsability the implementation details of this solution, since it is related to the Relying Party's internal API.
The Relying Party MUST bind the request of the user-agent, with a Secure and HttpOnly session cookie, with the issued request. The request url SHOULD include a parameter with a random value. The HTTP response returned by this specialized 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 redirect_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. An URL is provided carrying the location where the user-agent is intended to navigate.
401 Unauthorized. The Wallet Instance or its User have rejected the request, or the request is expired. The QRCode page SHOULD be updated with an error message.
Below a non-normative example of the HTTP Request to this specialized endpoint, where the parameter id
contains an opaque and random value:
GET /session-state?id=3be39b69-6ac1-41aa-921b-3e6c07ddcb03
HTTP/1.1
HOST: relying-party.example.org
Request Object Details¶
The following actions are made by the Wallet Instance:
scan the QR Code (Cross Device only);
extract from the payload the
request_uri
parameter;invoke the retrieved URI;
provide in the request its Wallet Instance Attestation, using RFC 9449 to proof the legitimate possession of it;
obtain the signed Request Object from the Relying Party.
evaluate the trust with the Relying Party, by evaluating the Trust Chain related to it.
Below a non-normative example of HTTP request made by the Wallet Instance to the Relying Party to provide the Wallet Instance Attestion and retrieve the signed Request Object:
GET /request_uri HTTP/1.1
HOST: relying-party.example.org
Authorization: DPoP $WalletInstanceAttestation
DPoP: $WalletInstanceAttestationProofOfPossession
More detailed information about the Wallet Instance Attestation is available in its dedicated section of this technical specification.
To attest a high level of security, the Wallet Instance submits its Wallet Instance Attestation to the Relying Party, disclosing its capabilities and the security level attested by its Wallet Provider.
Below the description of the parameters defined in OAuth 2.0 Demonstration of Proof-of-Possession at the Application Layer (DPoP).
Note
The use of DPoP doesn't represent any breaking changes to Wallet Instances that do not support DPoP to a request_uri endpoint, since it is assumed to use it as an additional security mechanisms for the attestation of the status of the Wallet Instance.
If the DPoP HTTP Header is missing, the Relying Party would assume the lowest attestable level of security to the Wallet Instance it is interacting with.
DPoP HTTP Header¶
A DPoP proof is included in the request using the HTTP Header DPoP
and containing a JWS. The JWS MUST be verified with the public key made available in the Wallet Instance Attestation (Authorization: DPoP
).
The JOSE header of the DPoP JWS MUST contain at least the following parameters:
JOSE header |
Description |
Reference |
---|---|---|
typ |
It MUST be equal to |
|
alg |
A digital signature algorithm identifier such as per IANA "JSON Web Signature and Encryption Algorithms" registry. It MUST be one of the supported algorithms in Section Cryptographic Algorithms <supported_algs>`* and MUST NOT be none or an identifier for a symmetric algorithm (MAC). |
[RFC 7515] |
jwk |
Representing the public key chosen by the client, in JSON Web Key (JWK) [RFC7517] format, as defined in Section 4.1.3 of [RFC7515]. It MUST NOT contain a private key. |
The payload of a DPoP proof MUST contain at least the following claims:
Claim |
Description |
Reference |
---|---|---|
jti |
Unique identifier for the DPoP proof JWT. The value SHOULD be set with a UUID v4 value, according to [RFC 4122]. |
[RFC 7519. Section 4.1.7]. |
htm |
The value of the HTTP method of the request to which the JWT is attached. |
[RFC 9110. Section 9.1]. |
htu |
The HTTP target URI, without query and fragment parts, of the request to which the JWS is attached. |
[RFC 9110. Section 7.1]. |
iat |
UNIX Timestamp with the time of JWT issuance, coded as NumericDate as indicated in RFC 7519. |
[RFC 7519. Section 4.1.6]. |
ath |
Hash of the Wallet Instance Attestation. |
[RFC 9449. Section 4.2]. |
Therein a non-normative example of the DPoP decoded content:
{
"typ": "dpop+jwt",
"alg": "ES256",
"jwk": {
"kty": "EC",
"x": "l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs",
"y": "9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA",
"crv": "P-256"
}
}
.
{
"jti": "f47c96a1-f928-4768-aa30-ef32dc78aa69",
"htm": "GET",
"htu": "https://relying-party.example.org/request_uri",
"iat": 1562262616,
"ath": "fUHyO2r2Z3DZ53EsNrWBb0xWXoaNy59IiKCAqksmQEo"
}
Request URI response¶
The Relying Party issues the signed Request Object, where a non-normative example in the form of decoded header and payload is shown below:
{
"alg": "ES256",
"typ": "JWT",
"kid": "e0bbf2f1-8c3a-4eab-a8ac-2e8f34db8a47",
"trust_chain": [
"MIICajCCAdOgAwIBAgIC...awz",
"MIICajCCAdOgAwIBAgIC...2w3",
"MIICajCCAdOgAwIBAgIC...sf2"
]
}
.
{
"scope": "eu.europa.ec.eudiw.pid.it.1 pid-sd-jwt:unique_id+given_name+family_name",
"client_id_scheme": "entity_id",
"client_id": "https://relying-party.example.org",
"response_mode": "direct_post.jwt",
"response_type": "vp_token",
"response_uri": "https://relying-party.example.org/callback",
"nonce": "2c128e4d-fc91-4cd3-86b8-18bdea0988cb",
"state": "3be39b69-6ac1-41aa-921b-3e6c07ddcb03",
"iss": "https://relying-party.example.org",
"iat": 1672418465,
"exp": 1672422065
}
The JWS header parameters are described below:
Name |
Description |
---|---|
alg |
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 and MUST NOT be set to |
typ |
Media Type of the JWT, as defined in [RFC 7519]. |
kid |
Key ID of the public key needed to verify the JWS signature, as defined in [RFC 7517]. REQUIRED when |
trust_chain |
Sequence of Entity Statements that composes the Trust Chain related to the Relying Party, as defined in OIDC-FED Section 3.2.1. Trust Chain Header Parameter. |
The JWS payload parameters are described herein:
Name |
Description |
---|---|
scope |
Aliases for well-defined Presentation Definitions IDs. It is used to identify which required credentials and User attributes are requested by the Relying Party, according to the Section "Using scope Parameter to Request Verifiable Credential(s)" of [OID4VP]. |
client_id_scheme |
String identifying the scheme of the value in the |
client_id |
Unique Identifier of the Relying Party. |
response_mode |
It MUST be set to |
response_type |
It MUST be set to``vp_token``. |
response_uri |
The Response URI to which the Wallet Instance MUST send the Authorization Response using an HTTP request using the method POST. |
nonce |
Fresh cryptographically random number with sufficient entropy, which length MUST be at least 32 digits. |
state |
Unique identifier of the Authorization Request. |
iss |
The entity that has issued the JWT. It will be populated with the Relying Party client id. |
iat |
Unix Timestamp, representing the time at which the JWT was issued. |
exp |
Unix Timestamp, representing the expiration time on or after which the JWT MUST NOT be valid anymore. |
Warning
This implementation profile use the parameter scope
within the request instead of the presentation_definition
.
Using the parameter scope
requires that the Relying Party Metadata MUST
contain the presentation_definition
, where a non-normative example of it
is given below:
{
"presentation_definition": {
"id": "presentation definitions",
"input_descriptors": [
{
"id": "pid-sd-jwt:unique_id+given_name+family_name",
"name": "Person Identification Data",
"purpose": "User authentication",
"format": "vc+sd-jwt",
"constraints": {
"fields": [
{
"path": [
"$.credentialSubject.unique_id",
"$.credentialSubject.given_name",
"$.credentialSubject.family_name",
]
}
],
"limit_discolusre": "preferred"
}
}
]
}
}
Note
The following parameters, even if defined in [OID4VP], are not mentioned in the previous non-normative example, since their usage is conditional and may change in future release of this documentation.
presentation_definition
: JSON object according to Presentation Exchange. This parameter MUST not be present whenpresentation_definition_uri
orscope
are present.presentation_definition_uri
: string containing an HTTPS URL pointing to a resource where a Presentation Definition JSON object can be retrieved. This parameter MUST be present whenpresentation_definition
parameter or ascope
value representing a Presentation Definition is not present.client_metadata
: A JSON object containing the Relying Party metadata values. Theclient_metadata
parameter MUST NOT be present whenclient_id_scheme
isentity_id
. Theclient_metadata
is taken fromtrust_chain
.client_metadata_uri
: string containing an HTTPS URL pointing to a resource where a JSON object with the Relying Party metadata can be retrieved. Theclient_metadata_uri
parameter MUST NOT be present whenclient_id_scheme
isentity_id
.redirect_uri
: the redirect URI to which the Wallet Instance MUST redirect the Authorization Response. This parameter MUST not be present whenresponse_uri
is present.
Relying Party Entity Configuration¶
According to the Trust Model section, the Relying Party is a Federation Entity and MUST expose a well-known endpoint containing its Entity Configuration.
Below a non-normative example of the request made by the Wallet Instance to the openid-federation well-known endpoint to obtain the Relying Party Entity Configuration:
GET /.well-known/openid-federation HTTP/1.1
HOST: relying-party.example.org
Below is a non-normative response example:
{
"alg": "RS256",
"kid": "2HnoFS3YnC9tjiCaivhWLVUJ3AxwGGz_98uRFaqMEEs",
"typ": "entity-statement+jwt"
}
.
{
"exp": 1649590602,
"iat": 1649417862,
"iss": "https://rp.example.it",
"sub": "https://rp.example.it",
"jwks": {
"keys": [
{
"kty": "RSA",
"n": "5s4qi …",
"e": "AQAB",
"kid": "2HnoFS3YnC9tjiCaivhWLVUJ3AxwGGz_98uRFaqMEEs"
}
]
},
"metadata": {
"wallet_relying_party": {
"application_type": "web",
"client_id": "https://rp.example.it",
"client_name": "Name of an example organization",
"jwks": {
"keys": [
{
"kty": "RSA",
"use": "sig",
"n": "1Ta-sE …",
"e": "AQAB",
"kid": "YhNFS3YnC9tjiCaivhWLVUJ3AxwGGz_98uRFaqMEEs",
"x5c": [ "..." ]
}
]
},
"contacts": [
"ops@relying-party.example.org"
],
"request_uris": [
"https://relying-party.example.org/request_uri"
],
"redirect_uris": [
"https://relying-party.example.org/callback"
],
"default_acr_values": [
"https://www.spid.gov.it/SpidL2",
"https://www.spid.gov.it/SpidL3"
],
"vp_formats": {
"jwt_vp_json": {
"alg": [
"EdDSA",
"ES256K"
]
}
},
"presentation_definitions": [
{
"id": "pid-sd-jwt:unique_id+given_name+family_name",
"input_descriptors": [
{
"id": "sd-jwt",
"format": {
"jwt": {
"alg": [
"EdDSA",
"ES256"
]
},
"constraints": {
"limit_disclosure": "required",
"fields": [
{
"path": [
"$.sd-jwt.type"
],
"filter": {
"type": "string",
"const": "PersonIdentificationData"
}
},
{
"path": [
"$.sd-jwt.cnf"
],
"filter": {
"type": "object",
}
},
{
"path": [
"$.sd-jwt.family_name"
],
"intent_to_retain": "true"
},
{
"path": [
"$.sd-jwt.given_name"
],
"intent_to_retain": "true"
},
{
"path": [
"$.sd-jwt.unique_id"
],
"intent_to_retain": "true"
}
]
}
}
}
]
},
{
"id": "mDL-sample-req",
"input_descriptors": [
{
"id": "mDL",
"format": {
"mso_mdoc": {
"alg": [
"EdDSA",
"ES256"
]
},
"constraints": {
"limit_disclosure": "required",
"fields": [
{
"path": [
"$.mdoc.doctype"
],
"filter": {
"type": "string",
"const": "org.iso.18013.5.1.mDL"
}
},
{
"path": [
"$.mdoc.namespace"
],
"filter": {
"type": "string",
"const": "org.iso.18013.5.1"
}
},
{
"path": [
"$.mdoc.family_name"
],
"intent_to_retain": "false"
},
{
"path": [
"$.mdoc.portrait"
],
"intent_to_retain": "false"
},
{
"path": [
"$.mdoc.driving_privileges"
],
"intent_to_retain": "false"
}
]
}
}
}
]
}
],
"default_max_age": 1111,
// JARM related
"authorization_signed_response_alg": [[
"RS256",
"ES256"
],
"authorization_encrypted_response_alg": [
"RSA-OAEP",
"RSA-OAEP-256"
],
"authorization_encrypted_response_enc": [
"A128CBC-HS256",
"A192CBC-HS384",
"A256CBC-HS512",
"A128GCM",
"A192GCM",
"A256GCM"
],
// SIOPv2 related
"subject_type": "pairwise",
"require_auth_time": true,
"id_token_signed_response_alg": [
"RS256",
"ES256"
],
"id_token_encrypted_response_alg": [
"RSA-OAEP",
"RSA-OAEP-256"
],
"id_token_encrypted_response_enc": [
"A128CBC-HS256",
"A192CBC-HS384",
"A256CBC-HS512",
"A128GCM",
"A192GCM",
"A256GCM"
],
},
"federation_entity": {
"organization_name": "OpenID Wallet Relying Party example",
"homepage_uri": "https://relying-party.example.org/home",
"policy_uri": "https://relying-party.example.org/policy",
"logo_uri": "https://relying-party.example.org/static/logo.svg",
"contacts": [
"tech@relying-party.example.org"
]
}
},
"authority_hints": [
"https://registry.eudi-wallet.example.it"
]
}
}
The Entity Configuration is a JWS, where its header parameters are defined below:
Name |
Description |
---|---|
alg |
Algorithm used to sign the JWT |
typ |
Media Type of the JWT |
kid |
Key ID used identifying the key used to sign the JWS |