Skip to main content
European CommissionEBSI European Blockchain

How to share Verifiable Presentations

Last updated on

Context

This document defines Verifiable Presentation (VP) exchanges in compliance with OpenID for Verifiable Presentations (version: openid-4-verifiable-presentations-1_0-14). Unlike the flow described in the OpenID for Verifiable Presentations, where the flow is typically initiated by the Verifier, this document details a flow initiated by the Wallet. This approach eliminates the need for the Wallet to expose external endpoints.

In this flow, the VP Token Request is sent to the Wallet as a redirect location URI in response to the Wallet's Authorise Request to the Verifier. The VP is a JSON Web Token (JWT) that is signed using the Holder's private key, which matches the authentication key specified in the Holder's DID document. This signature proves that the Holder controls the private key, as only the Holder of the private key can generate a valid signature for the JWT.

The processes for Authorisation Request and Response, Token Request and Response, and Credential Request and Response are semantically the same with in-time flow of Verifiable Credential Issuance. The direct_post method must be executed according to the provided redirect_uri.

VP Token Request

The VP Token Request is initiated by the Authorisation Server (AS) to the Wallet and triggers the VP token exchange. The redirect URI schema is registered with the client_metadata.authorization_endpoint specified in the Authorisation Request. This request is transmitted as a signed request object containing the fields in the table below.

ParameterRequirementDescription
response_typeREQUIREDvp_token
client_idREQUIREDClient ID of the Verifier.
redirect_uriREQUIREDAn HTTPS endpoint where the Wallet must post the VP Token Response.
scopeREQUIREDopenid
response_modeREQUIREDdirect_post
presentation_definitionOPTIONALA string containing presentation definition. Either presentation_definition or presentation_definition_uri must be present.
presentation_definition_uriOPTIONALA URI where the Wallet will fetch the presentation definition. Either presentation_definition or presentation_definition_uri must be present.
stateRECOMMENDEDAn opaque value used by the client to maintain state between the request and callback. The Authorisation Server may include this value. The parameter SHOULD be used for preventing cross-site request forgery.
nonceREQUIREDUnique to this request. Used to mitigate replay attacks.
VP Token Request - Non-normative example
HTTP 302 Location: openid://
?client_id=https%3A%2F%2Fapi-conformance.ebsi.eu%2Fconformance%2Fv4%2Fauth-mock
&response_type=vp_token
&scope=openid
&redirect_uri=https%3A%2F%2Fapi-conformance.ebsi.eu%2Fconformance%2Fv4%2Fauth-mock%2Fdirect_post
&request=eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6ImM0S3JlcEpYem1CTVctcW8ybnREQ3drVGdMbTJDYl81ZWFiemtsalRoXzAifQ.eyJpc3MiOiJodHRwczovL2FwaS1jb25mb3JtYW5jZS5lYnNpLmV1L2NvbmZvcm1hbmNlL3YzL2F1dGgtbW9jayIsImF1ZCI6Imh0dHBzOi8vbXktaXNzdWVyLmV1L3N1ZmZpeC94eXoiLCJleHAiOjE1ODk2OTkxNjIsInJlc3BvbnNlX3R5cGUiOiJ2cF90b2tlbiIsInJlc3BvbnNlX21vZGUiOiJkaXJlY3RfcG9zdCIsImNsaWVudF9pZCI6Imh0dHBzOi8vYXBpLWNvbmZvcm1hbmNlLmVic2kuZXUvY29uZm9ybWFuY2UvdjMvYXV0aC1tb2NrIiwicmVkaXJlY3RfdXJpIjoiaHR0cHM6Ly9hcGktY29uZm9ybWFuY2UuZWJzaS5ldS9jb25mb3JtYW5jZS92My9hdXRoLW1vY2svZGlyZWN0X3Bvc3QiLCJzY29wZSI6Im9wZW5pZCIsIm5vbmNlIjoiRmdrZUVyZjkxa2ZsIiwicHJlc2VudGF0aW9uX2RlZmluaXRpb25fdXJpIjoiaHR0cHM6Ly9hcGktY29uZm9ybWFuY2UuZWJzaS5ldS9jb25mb3JtYW5jZS92My9hdXRoLW1vY2svZGVmaW5pdGlvbnMveHl6In0.i4VIO7jx9M9XnYDSzsNBf6Nd2QQSw5KiczSeh4SVUuzvbSw7f8D72Bld1VDde-CAGgGGRpW_vMoVCZm-Vt9wSg

JWT Header:
{
typ: 'JWT',
alg: 'ES256',
kid: 'c4KrepJXzmBMW-qo2ntDCwkTgLm2Cb_5eabzkljTh_0'
}
JWT Payload:
{
iss: 'https://api-conformance.ebsi.eu/conformance/v3/auth-mock',
aud: 'https://my-issuer.eu/suffix/xyz',
exp: 1589699162,
response_type: 'vp_token',
response_mode: 'direct_post',
client_id: 'https://api-conformance.ebsi.eu/conformance/v3/auth-mock',
redirect_uri: 'https://api-conformance.ebsi.eu/conformance/v3/auth-mock/direct_post',
scope: 'openid',
nonce: 'FgkeErf91kfl',
presentation_definition_uri: 'https://api-conformance.ebsi.eu/conformance/v3/auth-mock/definitions/xyz'
}

VP Token Response

The VP Token Response is sent to the AS by posting to URI defined in direct_post. The payload should be formatted as application/x-www-form-urlencoded data. The presentation submission parameters define how the requested VP should be interpreted. For detailed definitions, refer to the Presentation Exchange specification, though in this context, it is simplified to key-value pairs.

The state parameter is required in the VP Token Response if it was present in the VP Token Request from the AS. In such cases, the Client must ensure that the the state parameter values match in both requests.

VP Token Response - Non-normative example
HTTP POST into: https://api-conformance.ebsi.eu/conformance/v3/auth-mock/direct_post
vp_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDplYnNpOnpkUGoxR1BYamZFUlh4WFBFMVlUWWRKIzdqM1RwYU5kUE5UT3pPdG91T09rbmxPTFFrM0pQLXlrVGZyYVd0WTNHTUUifQ.eyJpc3MiOiJkaWQ6ZWJzaTp6ZFBqMUdQWGpmRVJYeFhQRTFZVFlkSiIsImF1ZCI6Imh0dHBzOi8vYXBpLWNvbmZvcm1hbmNlLmVic2kuZXUvY29uZm9ybWFuY2UvdjMvYXV0aC1tb2NrIiwic3ViIjoiZGlkOmVic2k6emRQajFHUFhqZkVSWHhYUEUxWVRZZEoiLCJpYXQiOjE1ODk2OTkyNjAsIm5iZiI6MTU4OTY5OTI2MCwiZXhwIjoxNTg5Njk5MjYwLCJub25jZSI6IkZna2VFcmY5MWtmbCIsImp0aSI6InVybjp1dWlkOjA3MDYwNjFhLWUyY2EtNDYxNC05ZGU3LTljMTQ1MTkzNWYwMiIsInZwIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sImlkIjoidXJuOnV1aWQ6MDcwNjA2MWEtZTJjYS00NjE0LTlkZTctOWMxNDUxOTM1ZjAyIiwidHlwZSI6WyJWZXJpZmlhYmxlUHJlc2VudGF0aW9uIl0sImhvbGRlciI6ImRpZDplYnNpOnpkUGoxR1BYamZFUlh4WFBFMVlUWWRKIiwidmVyaWZpYWJsZUNyZWRlbnRpYWwiOlsiZXlKMGVYQWlPaUpLVjFRaUxDSmhiR2NpT2lKRlV6STFOaUlzSW10cFpDSTZJbVJwWkRwbFluTnBPbnAyU0ZkWU16VTVRVE5EZG1aS2JrTlpZVUZwUVdSbEkwWXdjalZQZVhSZmJHRm9kblo2TmsxWGJGbHpNMjFqV1U1TFdtbHBVV1JWWm5GMk9IUnphRWhPT1hjaWZRLmV5SnBjM01pT2lKa2FXUTZaV0p6YVRwNmRraFhXRE0xT1VFelEzWm1TbTVEV1dGQmFVRmtaU0lzSW5OMVlpSTZJbVJwWkRwbFluTnBPbnBrVUdveFIxQllhbVpGVWxoNFdGQkZNVmxVV1dSS0lpd2lhV0YwSWpveE5UZzVOams1TWpZd0xDSnVZbVlpT2pFMU9EazJPVGt5TmpBc0ltVjRjQ0k2TVRVNE9UWTVPVEkyTUN3aWFuUnBJam9pZFhKdU9uVjFhV1JpTmpreE5tTXhNQzA0WWpZMExUUTBNamd0T0dKbU5TMWpaR1kwT0RNNE16TXhNR01pTENKMll5STZleUpBWTI5dWRHVjRkQ0k2V3lKb2RIUndjem92TDNkM2R5NTNNeTV2Y21jdk1qQXhPQzlqY21Wa1pXNTBhV0ZzY3k5Mk1TSmRMQ0pwWkNJNkluVnlianAxZFdsa09tSTJPVEUyWXpFd0xUaGlOalF0TkRReU9DMDRZbVkxTFdOa1pqUTRNemd6TXpFd1l5SXNJblI1Y0dVaU9sc2lWbVZ5YVdacFlXSnNaVU55WldSbGJuUnBZV3dpTENKV1pYSnBabWxoWW14bFFYUjBaWE4wWVhScGIyNGlMQ0pEVkZkaGJHeGxkRk5oYldWSmJsUnBiV1VpWFN3aWFYTnpkV0Z1WTJWRVlYUmxJam9pTWpBeU1DMHdOUzB4TjFRd056b3dOem8wTUZvaUxDSjJZV3hwWkVaeWIyMGlPaUl5TURJd0xUQTFMVEUzVkRBM09qQTNPalF3V2lJc0luWmhiR2xrVlc1MGFXd2lPaUl5TURJd0xUQTFMVEUzVkRBM09qQTNPalF3V2lJc0ltVjRjR2x5WVhScGIyNUVZWFJsSWpvaU1qQXlNQzB3TlMweE4xUXdOem93TnpvME1Gb2lMQ0pwYzNOMVpXUWlPaUl5TURJd0xUQTFMVEUzVkRBM09qQTNPalF3V2lJc0ltTnlaV1JsYm5ScFlXeFRkV0pxWldOMElqcDdJbWxrSWpvaVpHbGtPbVZpYzJrNmVtUlFhakZIVUZocVprVlNXSGhZVUVVeFdWUlpaRW9pZlN3aVkzSmxaR1Z1ZEdsaGJGTmphR1Z0WVNJNmV5SnBaQ0k2SW1oMGRIQnpPaTh2WVhCcExYQnBiRzkwTG1WaWMya3VaWFV2ZEhKMWMzUmxaQzF6WTJobGJXRnpMWEpsWjJsemRISjVMM1l5TDNOamFHVnRZWE12TUhneU16QXpPV1UyTXpVMlpXRTJZamN3TTJObE5qY3laVGRqWm1Gak1HSTBNamMyTldJeE5UQm1Oak5rWmpjNFpUSmlaREU0WVdVM09EVTNPRGRtTm1FeUlpd2lkSGx3WlNJNklrWjFiR3hLYzI5dVUyTm9aVzFoVm1Gc2FXUmhkRzl5TWpBeU1TSjlmWDAuOURya3kzcGpCTXFRT3JZSzRzSVRfLXFfM0g5WVlrSG9IRHA1V0hQc055VTVsNExPSFJPajlCOHRLbVZuVnc0aGEzMlVEd0xTd2Q4YzZFbHpUSzNfLVEiXX19.fGUeTLm5mplufL1VpCNbxKGmUzBeMS-NnSkaHNf6_08pFg6iEKfJmD2Wt2eDvj4qijXwnnbLFYV4zBt3PHfpWA
&presentation_submission=%7B%22id%22%3A%22a30e3b91-fb77-4d22-95fa-871689c322e2%22%2C%22definition_id%22%3A%2232f54163-7166-48f1-93d8-ff217bdb0653%22%2C%22descriptor_map%22%3A%5B%7B%22id%22%3A%22same-device-in-time-credential%22%2C%22path%22%3A%22%24%22%2C%22format%22%3A%22jwt_vp%22%2C%22path_nested%22%3A%7B%22format%22%3A%22jwt_vc%22%2C%22path%22%3A%22%24.vp.verifiableCredential%5B0%5D%22%7D%7D%5D%7D

JWT Header:
{
typ: 'JWT',
alg: 'ES256',
kid: 'did:ebsi:zdPj1GPXjfERXxXPE1YTYdJ#7j3TpaNdPNTOzOtouOOknlOLQk3JP-ykTfraWtY3GME'
}
JWT Payload:
{
iss: 'did:ebsi:zdPj1GPXjfERXxXPE1YTYdJ',
aud: 'https://api-conformance.ebsi.eu/conformance/v3/auth-mock',
sub: 'did:ebsi:zdPj1GPXjfERXxXPE1YTYdJ',
iat: 1589699260,
nbf: 1589699260,
exp: 1589699260,
nonce: 'FgkeErf91kfl',
jti: 'urn:uuid:0706061a-e2ca-4614-9de7-9c1451935f02',
vp: {
'@context': [ 'https://www.w3.org/2018/credentials/v1' ],
id: 'urn:uuid:0706061a-e2ca-4614-9de7-9c1451935f02',
type: [ 'VerifiablePresentation' ],
holder: 'did:ebsi:zdPj1GPXjfERXxXPE1YTYdJ',
verifiableCredential: [
'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDplYnNpOnp2SFdYMzU5QTNDdmZKbkNZYUFpQWRlI0YwcjVPeXRfbGFodnZ6Nk1XbFlzM21jWU5LWmlpUWRVZnF2OHRzaEhOOXcifQ.eyJpc3MiOiJkaWQ6ZWJzaTp6dkhXWDM1OUEzQ3ZmSm5DWWFBaUFkZSIsInN1YiI6ImRpZDplYnNpOnpkUGoxR1BYamZFUlh4WFBFMVlUWWRKIiwiaWF0IjoxNTg5Njk5MjYwLCJuYmYiOjE1ODk2OTkyNjAsImV4cCI6MTU4OTY5OTI2MCwianRpIjoidXJuOnV1aWRiNjkxNmMxMC04YjY0LTQ0MjgtOGJmNS1jZGY0ODM4MzMxMGMiLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJpZCI6InVybjp1dWlkOmI2OTE2YzEwLThiNjQtNDQyOC04YmY1LWNkZjQ4MzgzMzEwYyIsInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJWZXJpZmlhYmxlQXR0ZXN0YXRpb24iLCJDVFdhbGxldFNhbWVJblRpbWUiXSwiaXNzdWFuY2VEYXRlIjoiMjAyMC0wNS0xN1QwNzowNzo0MFoiLCJ2YWxpZEZyb20iOiIyMDIwLTA1LTE3VDA3OjA3OjQwWiIsInZhbGlkVW50aWwiOiIyMDIwLTA1LTE3VDA3OjA3OjQwWiIsImV4cGlyYXRpb25EYXRlIjoiMjAyMC0wNS0xN1QwNzowNzo0MFoiLCJpc3N1ZWQiOiIyMDIwLTA1LTE3VDA3OjA3OjQwWiIsImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmVic2k6emRQajFHUFhqZkVSWHhYUEUxWVRZZEoifSwiY3JlZGVudGlhbFNjaGVtYSI6eyJpZCI6Imh0dHBzOi8vYXBpLXBpbG90LmVic2kuZXUvdHJ1c3RlZC1zY2hlbWFzLXJlZ2lzdHJ5L3YyL3NjaGVtYXMvMHgyMzAzOWU2MzU2ZWE2YjcwM2NlNjcyZTdjZmFjMGI0Mjc2NWIxNTBmNjNkZjc4ZTJiZDE4YWU3ODU3ODdmNmEyIiwidHlwZSI6IkZ1bGxKc29uU2NoZW1hVmFsaWRhdG9yMjAyMSJ9fX0.9Drky3pjBMqQOrYK4sIT_-q_3H9YYkHoHDp5WHPsNyU5l4LOHROj9B8tKmVnVw4ha32UDwLSwd8c6ElzTK3_-Q'
]
}
}

Presentation Definition and Presentation Submission

Presentation Definition
{
id: '32f54163-7166-48f1-93d8-ff217bdb0653',
format: { jwt_vc: { alg: [ 'ES256' ] }, jwt_vp: { alg: [ 'ES256' ] } },
input_descriptors: [
{
id: 'same-device-in-time-credential',
format: { jwt_vc: { alg: [ 'ES256' ] } },
constraints: {
fields: [
{
path: [ '$.vc.type' ],
filter: {
type: 'array',
contains: { const: 'CTWalletSameAuthorisedInTime' }
}
}
]
}
}
]
}
Presentation Submission
{
id: "a30e3b91-fb77-4d22-95fa-871689c322e2",
definition_id: "32f54163-7166-48f1-93d8-ff217bdb0653",
descriptor_map: [
{
id: "same-device-in-time-credential",
path: "$",
format: "jwt_vp",
path_nested: {
id: "same-device-in-time-credential",
format: "jwt_vc",
path: "$.vp.verifiableCredential[0]",
},
},
],
};

Service-to-Service Token Flow

A VP Token can used by a service to request an access token from the AS. Before invoking the token endpoint, the service must first request a presentation definition from the AS that includes the desired scopes. The AS maps these scopes to corresponding VP definitions. The service then invokes the token endpoint with a presentation_submission encoded in the same manner as described for the VP Token Response above.