PID/(Q)EAA Issuance¶
This section describes the PID and (Q)EAAs issuance flow with an high level of security. The relevant entities and interfaces involved in the issuance flow are:
Wallet Provider: The entity responsible for releasing an EUDI Wallet Solution. It also issues Wallet Instance Attestations to its Wallet Instances through an Attestation Service. The Wallet Attestation certifies the genuinity and authenticity of the Wallet Instance and its compliance with a Trust Framework in compliance to the security and privacy requirements.
Wallet Solution: Entire product and service owned by a Wallet Provider, offered to all the Users of that solution. The Wallet Solution is certified as EUDI-compliant by a Conformity Assessment Body (CAB).
Wallet Instance: Instance of a Wallet Solution, installed on the User device. It provides interfaces for User interaction with the Wallet Provider, Relying Parties, PID, and (Q)EAA Providers.
PID Provider: The entity that issues the eIDAS Person Identification Data (PID). It is composed of:
OpenID4VCI Component: based on the “OpenID for Verifiable Credential Issuance” specification [OIDC4VCI. Draft 13] to release PID credentials.
National eID Relying Party (OpenID Connect or SAML2): It represents the component to authenticate the User with the national Digital Identity Providers.
National Identity Provider: It represents preexisting identity systems based on SAML2 or OpenID Connect, already in production in each Member State (for Italy SPID and CIE id authentication schemed notified eIDAS with LoA High, see SPID/CIE OpenID Connect Specifications).
(Q)EAA Provider: It represents the Issuer of (Q)EAAs. It is composed of:
OpenID4VCI Component: based on the “OpenID for Verifiable Credential Issuance” specification [OIDC4VCI. Draft 13] to release (Q)EAAs.
Relying Party: It represents the component to authenticate the User with the PID. The (Q)EAA Provider acts as a Verifier and it sends a presentation request to the Wallet Instance according to [OpenID4VP]. The Wallet Instance MUST have a valid PID obtained prior to starting a transaction with the (Q)EAA Provider.
High-Level PID flow¶
The Fig. 2 shows a general architecture and highlights the main operations involved in the issuance of a PID.
Fig. 2 PID Issuance - General architecture and high level flow¶
Below a detailed description for each step represented in the previous picture:
Wallet Instance Setup: the first time the Wallet Instance is started a preliminary setup phase MUST be carried out. It consists of the release of a verifiable proof issued by the Attestation Service provided by the Wallet Provider that asserts the genuineness, the authenticity and the compliance with a trust framework of the Wallet Instance. The verifiable proof binds a public key corresponding to a local private key generated by the Wallet Instance.
Obtaining the trusted PID Provider: the Wallet Instance discovers the trusted PID Provider using the Federation API (e.g.: using the Subordinate Listing Endpoint of the Trust Anchor and its Intermediates), and then inspects the metadata looking for the availability of the PID credential.
Obtaining of PID Provider Metadata: the Wallet Instance establishes the trust to the PID Provider according to the Trust Model, obtaining the Metadata that discloses the formats of the PID, the algorithms supported, and any other parameter required for interoperability needs.
PID Request: following the Authorization Code Flow in [OIDC4VCI. Draft 13] the Wallet Instance requests a PID to the PID Provider. A fresh key pair that is generated by the Wallet Instance for the purpose of the sender-constrained Access Token will be used by the PID Provider for the Holder Key Binding of the PID.
User Authentication: the PID Provider authenticates the User with LoA High, acting as an IAM Proxy to the National eID system.
PID Issuance: once the User authentication with LoA High happens, the User gives their consent, and the PID Provider releases a PID bound to the key material held by the requesting Wallet Instance.
In the following sections the steps from 1 to 5 are further expanded into more technical details.
High-Level (Q)EAA flow¶
The Fig. 3 shows a general architecture and highlights the main operations involved in the issuance of a (Q)EAA, following the assumptions listed below:
the User has a valid PID stored in their own Wallet Instance;
the (Q)EAA requires a high security implementation profile.
Fig. 3 (Q)EAA Issuance - General architecture and high level flow¶
Below the description of the most relevant operations involved in the (Q)EAA issuance:
Obtaining the trusted (Q)EAA Issuer: the Wallet Instance discovers the trusted (Q)EAA Issuer ufing the Federaiton API (e.g.: using the Subordinate Listing Endpoint of the Trust Anchor and its Intermediates), then inspects the metadata looking for the credential capabilities.
Obtaining of (Q)EAA Provider Metadata: the Wallet Instance establishes the trust to the (Q)EAA Provider according to the Trust Model, obtaining the Metadata that discloses the formats of the (Q)EAA, the algorithms supported, and any other parameter required for interoperability needs.
(Q)EAA Request: according to the Authorization Code Flow in [OIDC4VCI. Draft 13] the Wallet Instance requests a (Q)EAA to the (Q)EAA Provider. A fresh key pair that is generated by the Wallet Instance for the sender-constrained Access Token TO be used by (Q)EAA Provider for the key binding of the (Q)EAA. The (Q)EAA Provider checks the Wallet Instance by means of the Wallet Instance Attestation and the Trust Chain related to the Wallet Provider.
User Authentication: the (Q)EAA Provider, acting as a Verifier (Relying Party), authenticates the User evaluating the presentation of the PID.
(Q)EAA Issuance: Once the User has been authenticated with a valid PID, the User gives their consent, then the (Q)EAA Provider releases a (Q)EAA bound to the key material held by the requesting Wallet Instance.
Detailed Flow¶
The PID/(Q)EAA Issuance phase is based on the Authorization Code Flow with Pushed Authorization Requests (PAR) [RFC 9126] and PKCE (Proof Key for Code Exchange, RFC 7636) as recommended in [OIDC4VCI. Draft 13. Section 3.4]. A Wallet Initiated Flow is involved and the User receives the PID/(Q)EAA directly in response to the Credential Request (Immediate Flow).
Warning
All the non-normative examples are referred to the PID Provider issuance flow.
Fig. 4 PID/(Q)EAA Issuance - Detailed flow¶
Steps 1-4 (Discovery): The User selects the PID/(Q)EAA Provider, and the Wallet Instance obtains the Metadata for the selected PID/(Q)EAA Provider.
Note
Federation Check: The Wallet Instance needs to check if the PID/(Q)EAA Provider is part of the Federation, obtaining then its protocol specific Metadata. A non-normative example of a response from the endpoint .well-known/openid-federation with the Entity Configuration and the Metadata of the PID/(Q)EAA Provider is represented within the section Entity Configuration Credential Issuer.
Steps 5-6 (PAR Request): The Wallet Instance creates a fresh PKCE code verifier, and state
parameter for the Pushed Authorization Request. The Wallet Instance sends these parameters along in a Pushed Authorization Request using the OIDC request
parameter (hereafter Request Object) (see RFC 9126 Section 3) to the PID/(Q)EAA Provider PAR endpoint to prevent Request URI swapping attack (see RFC 9126). The Wallet Instance MUST create the code_verifier
with enough entropy random string using the unreserved characters with a minimum length of 43 characters and a maximum length of 128 characters, making it impractical for an attacker to guess its value. The value MUST be generated following the recommendation in Section 4.1 of RFC 7636. The Wallet Instance signs this request using the private key that is created during the setup phase to obtain the Wallet Instance Attestation. The related public key that is attested by the Wallet Provider is inside the Wallet Instance Attestation cnf
claim.. An OAuth2 client authentication method is involved, since in this flow the Pushed Authorization Endpoint is a protected endpoint. The client authentication is based on the model defined in [RFC 7521] using the Wallet Instance Attestation JWS inside the client_assertion
parameter. The authorization_details [RAR RFC 9396] parameter is extended to allow Wallet Instance to specify the types of credentials when requesting authorization for the PID/(Q)EAA issuance. The PID/(Q)EAA Provider performs the following checks upon the receipt of the PAR request:
It MUST validate the signature of the Request Object using the algorithm specified in the
alg
header parameter (RFC 9126, RFC 9101) and the public key that can be retrieved from the Wallet Instance Attestation (cnf
) identified using thekid
header of the Request Object.It MUST check that the used algorithm for signing the request in the
alg
header is among the appropriate once reported in Section Cryptographic Algorithms.It MUST check that the
client_id
in the request body of the PAR request matches theclient_id
claim in the Request Object.It MUST check that the
iss
claim in the Request Object matches theclient_id
claim in the Request Object (RFC 9126, RFC 9101).It MUST check that the
aud
claim in the Request Object is equal to the identifier of PID/(Q)EAA Provider (RFC 9126, RFC 9101).It MUST reject the PAR request, if it contains the
request_uri
parameter (RFC 9126).It MUST check that the Request Object contains all the mandatory parameters and their values are validated according to what we defined in Table of the HTTP parameters [derived from RFC 9126].
It MUST check that the Request Object is not expired by checking the
exp
claim (RFC 9126).It MUST check that the Request Object was issued at a time acceptable by the PID/(Q)EAA Provider by checking the
iat
claim. For example, basing on the security policies of the PID/(Q)EAA Provider, it might reject the request if theiat
claim is too far away from the current time (RFC 9126).It MUST check that the
jti
claim in the Request Object has not been used before by the Wallet Instance identified by theclient_id
. This allows the PID/(Q)EAA Provider to mitigate replay attacks (RFC 7519).
Below a non-normative example of the PAR.
POST /as/par HTTP/1.1
Host: pid-provider.example.org
Content-Type: application/x-www-form-urlencoded
response_type=code
&client_id=$thumprint-of-the-jwk-in-the-cnf-wallet-attestation$
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
&request=eyJhbGciOiJSUzI1NiIsImtpZCI6ImsyYmRjIn0.ew0KIC Jpc3MiOiAiczZCaGRSa3F0MyIsDQogImF1ZCI6ICJodHRwczovL3NlcnZlci5leGFtcGxlLmNvbSIsDQo gInJlc3BvbnNlX3R5cGUiOiAiY29kZSBpZF90b2tlbiIsDQogImNsaWVudF9pZCI6ICJzNkJoZFJrcXQz IiwNCiAicmVkaXJlY3RfdXJpIjogImh0dHBzOi8vY2xpZW50LmV4YW1...
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-client-attestation
&client_assertion=$WalletInstanceAttestation$
The JWS header of Request Object is represented below:
{
"alg": "ES256",
"kid": "FifYx03bnosD8m6gYQIfNHNP9cM_Sam9Tc5nLloIIrc",
}
The JWS payload of the Request Object is represented below:
{
"iss":"$thumprint-of-the-jwk-in-the-cnf-wallet-attestation$",
"aud":"https://pid-provider.example.org",
"exp":1672422065,
"iat": 1672418465,
"jti":"ac80df576e7109686717bf50b869e882",
"response_type":"code",
"client_id":"$thumprint-of-the-jwk-in-the-cnf-wallet-attestation$",
"state":"fyZiOL9Lf2CeKuNT2JzxiLRDink0uPcd",
"code_challenge":"E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM",
"code_challenge_method":"S256",
"authorization_details":[
{
"type":"openid_credential",
"format": "vc+sd-jwt",
"credential_definition": {
"type": "PersonIdentificationData"
}
}
],
"redirect_uri":"eudiw://start.wallet.example.org",
"client_assertion_type":"urn:ietf:params:oauth:client-assertion-type:jwt-client-attestation",
}
Note
Federation Check: The PID/(Q)EAA Provider MUST check that the Wallet Provider is part of the federation and in addition it MUST verify the Wallet Instance Attestation validity by checking its signature and data.
Step 7 (PAR Response): The PID/(Q)EAA Provider MUST issue the request_uri
one-time use and bind it to the client identifier (client_id
) that is provided in the Request Object. Furthermore, the entropy of the request_uri
MUST be sufficiently large. The adequate shortness of the validity and the entropy of the request_uri
depends on the risk calculation based on the value of the resource being protected. The validity time SHOULD be less than a minute, and the request_uri
MUST include a cryptographic random value of 128 bits or more (RFC 9101). The entire request_uri
SHOULD NOT exceed 512 ASCII characters due to the following two main reasons (RFC 9101):
Many phones on the market still do not accept large payloads. The restriction is typically either 512 or 1024 ASCII characters.
On a slow connection such as a 2G mobile connection, a large URL would cause a slow response; therefore, the use of such is not advisable from the user-experience point of view.
The PID/(Q)EAA Provider returns the issued
request_uri
to the Wallet Instance.
HTTP/1.1 201 Created
Cache-Control: no-cache, no-store
Content-Type: application/json
{
"request_uri":"urn:ietf:params:oauth:request_uri:bwc4JK-ESC0w8acc191e-Y1LTC2",
"expires_in": 60
}
Steps 8-9 (Authorization Request): The Wallet Instance sends an authorization request to the PID/(Q)EAA Provider Authorization Endpoint. Since parts of this Authorization Request content, e.g., the code_challenge
parameter value, are unique to a particular Authorization Request, the Wallet Instance MUST only use a request_uri
value once (RFC 9126); The PID/(Q)EAA Provider performs the following checks upon the receipt of the Authorization Request:
It MUST treat
request_uri
values as one-time use and MUST reject an expired request. However, it MAY allow for duplicate requests due to a user reloading/refreshing their user-agent (derived from RFC 9126).It MUST identify the request as a result of the submitted PAR (derived from RFC 9126).
It MUST reject all the Authorization Requests that do not contain the
request_uri
parameter as the PAR is the only way to pass the Authorization Request from the Wallet Instance (derived from RFC 9126).
GET /authorize?client_id=$thumprint-of-the-jwk-in-the-cnf-wallet-attestation$&request_uri=urn%3Aietf%3Aparams%3Aoauth%3Arequest_uri%3Abwc4JK-ESC0w8acc191e-Y1LTC2 HTTP/1.1
Host: pid-provider.example.org
Note
User Authentication and Consent: The PID Provider performs the User authentication based on the requirements of eIDAS LoA High by means of national notified eIDAS scheme and requires the User consent for the PID issuance. The (Q)EAA Provider performs the User authentication requesting a valid PID to the Wallet Instance. The (Q)EAA Provider MUST use [OpenID4VP] to dynamically request the presentation of the PID. From a protocol perspective, the (Q)EAA Provider then acts as a Relying Party and provide the presentation request to the Wallet Instance. The Wallet Instance MUST have a valid PID obtained prior to start the transaction with the (Q)EAA Provider.
Steps 10-11 (Authorization Response): The PID/(Q)EAA Provider sends an authorization code
together with state
and iss
parameters to the Wallet Instance. The Wallet Instance performs the following checks on the Authorization Response:
It MUST check the Authorization Response contains all the defined parameters according to Table of the HTTP Response parameters.
It MUST check the returned value by the PID/(Q)EAA Provider for
state
parameter is equal to the value sent by Wallet Instance in the Request Object (RFC 6749).It MUST check that the URL of PID/(Q)EAA Provider in
iss
parameter is equal to the URL identifier of intended PID/(Q)EAA Provider that the Wallet Instance start the communication with (RFC 9027).
Note
The Wallet Instance redirect URI is a universal or app link registered with the local operating system, so this latter will resolve it and pass the response to the Wallet Instance.
HTTP/1.1 302 Found
Location: eudiw://start.wallet.example.org?code=SplxlOBeZQQYbYS6WxSbIA&state=fyZiOL9Lf2CeKuNT2JzxiLRDink0uPcd&iss=https%3A%2F%2Fpid-provider.example.org
Steps 12-13 (DPoP Proof for Token Endpoint): The Wallet Instance MUST create a new key pair for the DPoP and a fresh DPoP Proof JWT following the instruction provided in Section 4 of (RFC 9449) for the token request to the PID/(Q)EAA Provider. The DPoP Proof JWT is signed using the created private key for DPoP by Wallet Instance. DPoP provides a way to bind the Access Token to a certain sender (Wallet Instance) (RFC 9449). This mitigates the misuse of leaked or stolen Access Tokens at the Credential Endpoint of PID/(Q)EAA Issuer as the attacker needs to present a valid DPoP Proof JWT.
Step 14 (Token Request): The Wallet Instance sends a token request to the PID/(Q)EAA Provider Token Endpoint using the authorization code
, code_verifier
, DPoP Proof JWT and private_key_jwt
parameters (client_assertion_type
and client_assertion
).
The client_assertion
is signed using the private key that is created during the setup phase to obtain the Wallet Instance Attestation. The related public key that is attested by the Wallet Provider is provided within the Wallet Instance Attestation (cnf
claim). The PID/(Q)EAA Provider performs the following checks on the Token Request:
It MUST authenticate the Wallet Instance based on the
private_key_jwt
Client Authentication method OpenID.Core#TokenRequest.It MUST ensure that the Authorization
code
is issued to the authenticated Wallet Instance (RFC 6749).It MUST ensure the Authorization
code
is valid and has not been previously used (RFC 6749).It MUST ensure the
redirect_uri
is identical to the value that was initially included in the Request Object OpenID.Core#TokenRequest.It MUST validate the DPoP Proof JWT following the steps in Section 4.3 of (RFC 9449).
POST /token HTTP/1.1
Host: pid-provider.example.org
Content-Type: application/x-www-form-urlencoded
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik
VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR
nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE
QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj
oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia
WF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg
4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg
client_id=$thumprint-of-the-jwk-in-the-cnf-wallet-attestation$
&grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=eudiw://start.wallet.example.org
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=eyJhbGciOiJIUzI1NiI
Step 15 (Token Response): The PID/(Q)EAA Provider validates the request and if it is successful, it issues an Access Token (bound to the DPoP key) and a fresh c_nonce
.
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
{
"access_token": "Kz~8mXK1EalYznwH-LC-1fBAo.4Ljp~zsPE_NeO.gxU",
"token_type": "DPoP",
"expires_in": 2677,
"c_nonce": "tZign[...]snFbp",
"c_nonce_expires_in": 86400
}
Steps 16-17 (DPoP Proof for Credential Endpoint): The Wallet Instance creates a proof of possession with the DPoP key following the steps in Section 7.2.1 of OPENID4VCI and the c_nonce
obtained in Step 15 and it creates a DPoP Proof JWT based on Section 4 of (RFC 9449) for the request to the PID/(Q)EAA credential issuance endpoint. The jwk
value in the proof parameter MUST be equal to the public key generated for the DPoP.
Step 18 (Credential Request): The Wallet Instance requests a PID/(Q)EAA issuance to the PID/(Q)EAA credential endpoint. The request MUST contain the Access Token, the DPoP Proof JWT, and the credential type, the proof
(proof of possession of the key) and the format
parameters.
Note
PID/(Q)EAA Credential Schema and Status registration: The PID/(Q)EAA Provider MUST register all the issued credentials for their later revocation, if needed.
POST /credential HTTP/1.1
Host: pid-provider.example.org
Content-Type: application/x-www-form-urlencoded
Authorization: DPoP Kz~8mXK1EalYznwH-LC-1fBAo.4Ljp~zsPE_NeO.gxU
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik
VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR
nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R
1JEQSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiJlMWozVl9iS2ljOC1MQUVCIiwiaHRtIj
oiR0VUIiwiaHR1IjoiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLm9yZy9wcm90ZWN0Z
WRyZXNvdXJjZSIsImlhdCI6MTU2MjI2MjYxOCwiYXRoIjoiZlVIeU8ycjJaM0RaNTNF
c05yV0JiMHhXWG9hTnk1OUlpS0NBcWtzbVFFbyJ9.2oW9RP35yRqzhrtNP86L-Ey71E
OptxRimPPToA1plemAgR6pxHF8y6-yqyVnmcw6Fy1dqd-jfxSYoMxhAJpLjA
credential_definition=%7B%22type%22:%5B%22PersonIdentificationData%22%5D%7D
&format=vc+sd-jwt
&proof=%7B%22proof_type%22:%22...-ace0-9c5210e16c32%22%7D
A non-normative example of proof parameter is given below:
{
"proof_type": "jwt",
"jwt": "eyJraWQiOiJkaWQ6ZXhhbXBsZTplYm …"
}
Where the decoded content of the JWT is represented below:
{
"alg": "ES256",
"typ": "openid4vci-proof+jwt",
"jwk": {
"kty": "EC",
"x": "l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs",
"y": "9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA",
"crv": "P-256"
}
}
{
"iss": "0b434530-e151-4c40-98b7-74c75a5ef760",
"aud": "https://pid-provider.example.org",
"iat": 1504699136,
"nonce": "tZign...snFbp"
}
Steps 19-21 (Credential Response): The PID/(Q)EAA Provider MUST validate the DPoP JWT Proof based on the steps defined in Section 4.3 of (RFC 9449) and whether the Access Token is valid and suitable for the requested PID/(Q)EAA. It also MUST validate the proof of possession for the key material the new credential SHALL be bound to following the steps in Section 7.2.2 of OPENID4VCI. If all checks succeed, the PID/(Q)EAA Provider creates a new credential bound to the key material and provide it to the Wallet Instance. The Wallet Instance MUST perform the following checks before proceeding with the secure storage of the PID/(Q)EAA credential:
It MUST check that the PID Credential Response contains all the mandatory parameters and values are validated according to Table of the credential response parameters.
It MUST check the PID integrity by verifying the signature using the algorithm specified in the
alg
header parameter of SD-JWT (PID/(Q)EAA Data Model) and the public key that is identified using using thekid
header of the SD-JWT.It MUST check that the received PID credential (in credential claim) contains all the mandatory parameters defined in PID/(Q)EAA Data Model.
It MUST process and verify the PID that is in SD-JWT VC following the steps in Section 6 of SD.JWT#Verification.
It MUST verify the Trust Chain in the header of SD-JWT VC to verify that the PID Provider is trusted.
If the checks defined above are successful the Wallet Instance proceeds with the secure storage of the PID credential.
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"format": "vc+sd-jwt"
"credential" : "LUpixVCWJk0eOt4CXQe1NXK[...]WZwmhmn9OQp6YxX0a2L",
"c_nonce": "fGFF7[...]UkhLa",
"c_nonce_expires_in": 86400
}
Token endpoint¶
The token endpoint is used by the Wallet Instance to obtain an Access Token by presenting its authorization grant, as defined in RFC 6749.
Token Request¶
The request to the PID/(Q)EAA Token endpoint MUST be an HTTP request with method POST, where its body message is encoded in application/x-www-form-urlencoded
format. The Wallet Instance sends the Token endpoint request with private_key_jwt authentication and a DPoP proof containing the parameters defined in the table below.
The Token endpoint MUST accept and validate the DPoP proof sent in the DPoP HTTP header. The Token endpoint MUST validate the DPoP proof according to Section 4.3 of the DPoP specifications (RFC 9449). Thus, this mitigates the misuse of leaked or stolen Access Tokens at the credential endpoint. If the DPoP proof is invalid, the Token endpoint returns an error response, according to Section 5.2 of [RFC 6749] with invalid_dpop_proof
as the value of the error parameter.
All the parameters listed below are REQUIRED:
Claim |
Description |
Reference |
---|---|---|
client_id |
It MUST be set as in the Table of the HTTP parameters. |
|
grant_type |
It MUST be set to |
Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants. |
code |
Authorization code returned in the Authentication Response. |
Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants. |
redirect_uri |
It MUST be set as in the Request Object Table of the JWT Request parameters. |
Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants. |
code_verifier |
Verification code of the code_challenge. |
|
client_assertion_type |
It MUST be set to |
Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants. |
client_assertion |
JWT signed with the Wallet Instance private key containing the following parameters:
|
Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants. |
A DPoP Proof JWT is included in an HTTP request using the DPoP
header parameter containing a DPoP JWS.
The JOSE header of a DPoP JWT 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 and MUST NOT be set to |
[RFC 7515]. |
jwk |
representing the public key chosen by the Wallet Instance, in JSON Web Key (JWK) [RFC 7517] format that the Access Token shall be bound to, as defined in Section 4.1.3 of [RFC 7515]. It MUST NOT contain a private key. |
The payload of a DPoP JWT Proof MUST contain at least the following claims:
Claim |
Description |
Reference |
---|---|---|
jti |
Unique identifier for the DPoP proof JWT. The value SHOULD be set using 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 JWT 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]. |
Token Response¶
Token endpoint response MUST contain the following mandatory claims.
Claim |
Description |
Reference |
---|---|---|
access_token |
The DPoP-bound Access Token, in signed JWT format, allows accessing the PID/(Q)EAA Credential Endpoint for obtaining the credential. |
|
token_type |
Type of Access Token returned. It MUST be equal to |
|
expires_in |
Expiry time of the Access Token in seconds. |
|
c_nonce |
JSON string containing a |
|
c_nonce_expires_in |
JSON integer, it represents the lifetime in seconds of the c_nonce. |
Access Token¶
A DPoP-bound Access Token is provided by the PID/(Q)EAA Token endpoint as a result of a successful token request. The Access Token is encoded in JWT format, according to [RFC 7519]. The Access Token MUST have at least the following mandatory claims and it MUST be bound to the public key that is provided by the DPoP proof. This binding can be accomplished based on the methodology defined in Section 6 of (RFC 9449).
Claim |
Description |
Reference |
---|---|---|
iss |
It MUST be an HTTPS URL that uniquely identifies the PID/(Q)EAA Issuer. The Wallet Instance MUST verify that this value matches the PID/(Q)EAA Issuer where it has requested the credential. |
|
sub |
It identifies the subject of the JWT. It MUST be set to the value of the |
[RFC 9068], [RFC 7519] and [OpenID.Core#SubjectIDTypes]. |
client_id |
As provided in the Wallet Instance Attestation. |
[RFC 9068]. |
aud |
It Must be Set to the URL of Credential Endpoint of the PID/(Q)EAA Provider. |
[RFC 9068]. |
iat |
UNIX Timestamp with the time of JWT issuance, coded as NumericDate as indicated in RFC 7519. |
|
exp |
UNIX Timestamp with the expiry time of the JWT, coded as NumericDate as indicated in RFC 7519. |
|
jti |
It MUST be a String in uuid4 format. Unique Token ID identifier that the RP MAY use to prevent reuse by rejecting the Token ID if already processed. |
|
jkt |
JWK SHA-256 Thumbprint Confirmation Method. The value of the jkt member MUST be the base64url encoding (as defined in [RFC7515]) of the JWK SHA-256 Thumbprint of the DPoP public key (in JWK format) to which the Access Token is bound. |
Credential endpoint¶
The Credential Endpoint issues a credential as approved by the End-User upon presentation of a valid Access Token representing this approval, as defined in OPENID4VCI.
Credential Request¶
The Wallet Instance when requests the PID/(Q)EAA to the PID/(Q)EAA Credential endpoint, MUST use the following parameters in the entity-body of the HTTP POST request, using the application/json media type.
The Credential endpoint MUST accept and validate the DPoP proof sent in the DPoP field of the Header based on the steps defined in Section 4.3 of (RFC 9449). The DPoP proof in addition to the values that are defined in the Token Endpoint section MUST contain the following claim:
ath: hash of the Access Token. The value MUST be the result of a base64url encoding (as defined in Section 2 of RFC 7515) the SHA-256 hash of the ASCII encoding of the associated Access Token's value.
If the DPoP proof is invalid, the Credential endpoint returns an error response per Section 5.2 of [RFC 6749] with invalid_dpop_proof as the value of the error parameter.
Warning
The Wallet Instance MUST create a new DPoP proof for the Credential request and MUST NOT use the previously created proof for the Token Endpoint.
Claim |
Description |
Reference |
---|---|---|
credential_definition |
JSON object containing the detailed description of the credential type. It MUST have at least the type sub claims which is a JSON array containing the type values the Wallet SHALL request in the Credential Request. It MUST be set in accordance to the type of the requested PID/(Q)EAA that is obtained from the PID/(Q)EAA Issuer metadata. In the case of the PID it MUST be set to |
|
format |
Format of the Credential to be issued. This MUST be vc+sd-jwt. |
|
proof |
JSON object containing proof of possession of the key material the issued credential shall be bound to. The proof object MUST contain the following mandatory claims:
|
Note
If the format value is mso_mdoc, the credential request MUST contain the doctype
claim which is a JSON string identifying the credential type according to EIDAS-ARF . See Appendix E.2. of [OIDC4VCI. Draft 13] for more details.
The JWT proof type MUST contain the following parameters for the JOSE header and the JWT body:
JOSE Header |
Description |
Reference |
---|---|---|
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 and MUST NOT be set to |
[OIDC4VCI. Draft 13], [RFC 7515], [RFC 7517]. |
typ |
It MUST be set to openid4vci-proof+jwt. |
[OIDC4VCI. Draft 13], [RFC 7515], [RFC 7517]. |
jwk |
Representing the public key chosen by the Wallet Instance, in JSON Web Key (JWK) [RFC 7517] format that the PID/(Q)EAA shall be bound to, as defined in Section 4.1.3 of [RFC 7515]. The |
[OIDC4VCI. Draft 13], [RFC 7515], [RFC 7517]. |
Claim |
Description |
Reference |
---|---|---|
iss |
The value of this claim MUST be the client_id of the Wallet Instance. |
|
aud |
The value of this claim MUST be the identifier URL of the PID/(Q)EAA Issuer. |
|
iat |
UNIX Timestamp with the time of JWT issuance, coded as NumericDate as indicated in RFC 7519. |
[OIDC4VCI. Draft 13], [RFC 7519. Section 4.1.6]. |
nonce |
The value type of this claim MUST be a string, where the value is a c_nonce provided by the PID/(Q)EAA Issuer in the Token response. |
Credential Response¶
Credential Response to the Wallet Instance MUST be sent using application/json media type. The response MUST contain the following mandatory claims:
Claim |
Description |
Reference |
---|---|---|
format |
Format of the Credential to be issued. This MUST be set to vc+sd-jwt when the credential type is SD-JWT. |
|
credential |
Contains the issued PID/(Q)EAA. When the credential type is SD-JWT, it MUST be an SD-JWT JSON Object (see Section PID/(Q)EAA Data Model). |
Appendix E in [OIDC4VCI. Draft 13]. |
c_nonce |
JSON string containing a |
|
c_nonce_expires_in |
JSON integer corresponding to the c_nonce lifetime in seconds. |
Note
If the format value is mso_mdoc, the credential value MUST be a base64url-encoded JSON string according to Appendix E of [OIDC4VCI. Draft 13].
Entity Configuration Credential Issuer¶
Below is a non-normative example of an Entity Configuration containing an openid_credential_issuer metadata.
HTTP/1.1 200 OK
Content-Type: application/entity-statement+jwt
{
"alg": "RS256",
"kid": "FANFS3YnC9tjiCaivhWLVUJ3AxwGGz_98uRFaqMEEs",
"typ": "entity-statement+jwt"
}
.
{
"exp": "1649610249",
"iat": "1649437449",
"iss": "https://pid-provider.example.org",
"sub": "https://pid-provider.example.org",
"jwks": {
"keys": [{
"kty": "RSA",
"use": "sig",
"n": "1Ta-sE …",
"e": "AQAB",
"kid": "FANFS3YnC9tjiCaivhWLVUJ3AxwGGz_98uRFaqMEEs"
}]
},
"metadata": {
"openid_credential_issuer": {
"credential_issuer": "https://pid-provider.example.org",
"authorization_endpoint": "https://pid-provider.example.org/connect/authorize",
"token_endpoint": "https://pid-provider.example.org/connect/token",
"pushed_authorization_request_endpoint": "https://pid-provider.example.org/connect/par",
"dpop_signing_alg_values_supported": ["RS256", "RS512", "ES256", "ES512"],
"credential_endpoint": "https://pid-provider.example.org/credential",
"jwks": {
"keys": [
{
"crv": "P-256",
"kty": "EC",
"x": "newK5qDYMekrCPPO-yEYTdJVWJMTzasMavt2vm1Mb-A",
"y": "VizXaLO6dzeesZPxfpGZabTK3cTXtBUbIiQpmiYRtSE",
"kid": "ff0bded045fe63fe5d1d64dd83b567e0"
}]
}
"credentials_supported": [
{
"format": "vc+sd-jwt",
"id": "eudiw.pid.it",
"cryptographic_binding_methods_supported": ["jwk"],
"cryptographic_suites_supported": ["RS256", "RS512", "ES256", "ES512"],
"display": [{
"name": "PID Provider Italiano di esempio",
"locale": "it-IT",
"logo": {
"url": "https://pid-provider example.org/public/logo.svg",
"alt_text": "logo di questo PID Provider"
},
"background_color": "#12107c",
"text_color": "#FFFFFF"
},
{
"name": "Example Italian PID Provider",
"locale": "en-US",
"logo": {
"url": "https://pid-provider.example.org/public/logo.svg",
"alt_text": "The logo of this PID Provider"
},
"background_color": "#12107c",
"text_color": "#FFFFFF"
}
],
"credential_definition": {
"type": ["PersonIdentificationData"],
"credentialSubject": {
"given_name": {
"mandatory": true,
"display": [{
"name": "Current First Name",
"locale": "en-US"
},
{
"name": "Nome",
"locale": "it-IT"
}
]
},
"family_name": {
"mandatory": true,
"display": [{
"name": "Current Family Name",
"locale": "en-US"
},
{
"name": "Cognome",
"locale": "it-IT"
}
]
},
"birthdate": {
"mandatory": true,
"display": [{
"name": "Date of Birth",
"locale": "en-US"
},
{
"name": "Data di Nascita",
"locale": "it-IT"
}
]
},
"place_of_birth": {
"mandatory": true,
"display": [{
"name": "Place of Birth",
"locale": "en-US"
},
{
"name": "Luogo di Nascita",
"locale": "it-IT"
}
]
},
"unique_id": {
"mandatory": true,
"display": [{
"name": "Unique Identifier",
"locale": "en-US"
},
{
"name": "Identificativo univoco",
"locale": "it-IT"
}
]
},
"tax_id_code": {
"mandatory": true,
"display": [{
"name": "Tax Id Number",
"locale": "en-US"
},
{
"name": "Codice Fiscale",
"locale": "it-IT"
}
]
}
}
}
}
]
},
"federation_entity": {
"organization_name": "Pid Provider Organization Example",
"homepage_uri": "https://pid-provider.example.org",
"policy_uri": "https://pid-provider.example.org/privacy_policy",
"tos_uri": "https://pid-provider.example.org/info_policy",
"logo_uri": "https://pid-provider.example.org/logo.svg"
},
"openid_relying_party": {
<This is the metadata of the PID Provider acting as a Relying Party in the national digital identity framework (CIE/SPID). See spid-cie-oidc-docs for details.>
}
}
}