How to issue a credential via the OID4VCI workflow
To issue a credential via the OID4VCI workflow you must create a Credential offer. This offer specifies the Credential configurations that will be used to issue the credential, as well as additional request parameters to support the authentication workflow.
Once the offer is created, it must be shared with the credential’s intended holder so that they can claim the credential.
Prerequisites
- The
id
identifier of one or more Credential configurations you wish to include in this offer. This is obtained when you create a Credential configuration. - DIDs:
- Issuer DID: This is a
did:web
that identifies the issuer who attests the claims in the credential are accurate.- Refer to Create a
did:web
if you need assistance in creating one.
- Refer to Create a
- Subject DID: This is a
did:key
that identifies the intended holder of the credential. This DID is usually retrieved from the intended holder’s digital wallet.- Refer to
Create a did:key
if you need assistance in creating one for testing this feature. - In production environments you must have a secure way to obtain the holder’s digital
wallet DID:
- Use DID Auth for any new interactions.
- Ask the user to share their wallet DID.
- Request an existing credential as part of a verification workflow, and extract the DID from that interaction.
- Refer to
- Issuer DID: This is a
Overview
Issuing a credential via the OID4VCI workflow comprises the following steps:
Generate an offer URI
Request
Make a request of the following structure to generate a new credential offer:
POST /v1/openid/offers
Request body
{
"credentials": ["20d6bbe6-a978-447c-b5bd-f33b6dca19e2"],
"request_parameters": {
"login_hint": "user@example.com",
"prompt": "login"
}
}
-
credentials
: This array includes a list of identifiers for credential configurations that will be included in the credential offer. These identifiers are theid
elements returned in the response when you create a Credential configuration.To issue multiple credential formats of the same credential in a single flow, include all the required credential configuration id elements in the request payload. For example, you could issue a CWT, JSON and/or mDocs credential using the same data in a single user journey.
-
request_parameters
(optional): Specifies a list of additional request parameters that are included in the credential offer and can be used by the wallet as part of the authentication workflow:login_hint
: Login hints are included in the authentication flow the holder is redirected to after accepting the credential offer. For example, you can include the user’s e-mail so that it is already populated in the login screen.prompt
: Prompts are sent to the Authentication provider to control the authentication flow. For example, usinglogin
would always require the user to authenticate, even if they had already completed login on the same device.
Response
{
"uri": "openid-credential-offer://?credential_offer=%7B%22credential_issuer%22%3A%22https%3A%2F%2Ftenant.vii.mattr.global%22%2C%22credentials%22%3A%5B%2220d6bbe6-a978-447c-b5bd-f33b6dca19e2%22%5D%2C%22request_parameters%22%3A%7B%22login_hint%22%3A%22user%40example.com%22%2C%22prompt%22%3A%22login%22%7D%7D"
}
uri
: This is the URI that should be used by the intended holder to claim the credential.
When a multi-format credential offer is created, this uri
is used to issue all the credential
formats in a single workflow.
Send an offer URI
Once a credential offer URI is generated, you can send it to the intended holder in one of the following methods:
- Send via a DID message
- Send via a QR code.
- Send via a Deeplink.
Send a Credential offer via a DID message
To send the Credential offer as a DID message you must first encrypt it and then send it as an encrypted message.
Step 1: Encrypt a Credential offer
Make a request of the following structure to encrypt the Credential offer:
Request
POST /v1/messaging/encrypt
Request body
{
"senderDidUrl": "did:web:learn.vii.au01.mattr.global#z6LShWb1DVC2gkxoQ91VwHmNhci2A4NdVH4srFvLiTP6ETBK",
"recipientDidUrls": ["did:key:z6MkgmEkNM32vyFeMXcQA7AfQDznu47qHCZpy2AYH2Dtdu1d"],
"payload": {
"id": "731961f2-bdc3-4f1e-8d59-cc308fd60ec8",
"type": "https://mattr.global/schemas/verifiable-credential/offer/OidcCredentialProvider",
"from": "did:web:organization.com",
"created_time": 1616466734,
"body": {
"uri": "openid-credential-offer://?credential_offer=%7B%22credential_issuer%22%3A%22https%3A%2F%2Ftenant.vii.mattr.global%22%2C%22credentials%22%3A%5B%2220d6bbe6-a978-447c-b5bd-f33b6dca19e2%22%5D%2C%22request_parameters%22%3A%7B%22login_hint%22%3A%22user%40example.com%22%2C%22prompt%22%3A%22login%22%7D%7D"
}
}
}
senderDidUrl
: Use the Issuer DID.recipientDidUrls
: Use the Subject DID.payload
:id
: Use the Credential configurationid
.type
: Use thehttps://mattr.global/schemas/verifiable-credential/offer/OidcCredentialProvider
to indicate that this message includes a Credential offer.from
: Use the Issuer DID.created_time
: Time of creation (Epoch Unix timestamp). The value must be a number and not a string, otherwise the holder will not be able to accept the Credential offer.
body
:uri
: Use the credential offer URI, obtained when the offer was created.
Response
{
"jwe": {
"protected": "eyJhbGciOiJYQzIwUCJ9",
"recipients": [
{
"header": {
"alg": "ECDH-1PU+A256KW",
"kid": "did:key:z6MkgmEkNM32vyFeMXcQA7AfQDznu47qHCZpy2AYH2Dtdu1d#z6LSsvqSJkBvVEsDC8cxMHuQ3sKoLRMXB1MdtoLrMUq6A8Rg",
"epk": {
"kty": "OKP",
"crv": "X25519",
"x": "JOLnYaD7L-Rszz7fczPhn6MkNre25PUsztzB1RHoz14"
},
"skid": "did:key:z6MkreuqFq6WrwozTeGKuUDz8bniTFRNAg8f3ZB862YdLp7v#z6LScyz3YLToyoKwZE6Tfq65hgZUkZdHrC4ZqohcUH9X6Twx"
},
"encryption_key": "ag5iKzjJOth9Wa68dCVKJW_vnO_Ga0zSJgQp5rIUg69HCzIjuNYhDg"
}
],
"ciphertext": "xpW-D6sDPpWc_jk87nEyxPX7JQV8_OZpaQft7ySQ5XmNhoj-lQyDkXDncOCyhB7yMSdZrRBNQjKxlEbpY_WLk1hBoWfsTeszVSAuFbX_VKUSJ7GR6rcnWGVNgDfKS8GsyC_owtswXatkF_65_mzFOygctkUmd2eI5bcpQpWjhw2vqnvnWkb7l2J27aWFF_c9cu52dB559j8lwLYyYC9oSMgV5piB6ppfrWBGo_DigjxvJcAYcjFYqFcT6A1nphPhwVTQ2HNfJodbQoseHub8UQdG4qAOcggq5DI84tbqor1SU9rdPH03jPkLgoO_aeXyJg5meITXoFSiu_tRfvf8QQ6vKq6pkTTXs8zKXcBCGhGIyKBNBG4R4RIY1UffTMnJQQQGBble3P06pGOnsnSop0BtygelB9M0ZEwnAUSAQqN1RR4AQwWcn9nH6hHEu1pMhSvhCuFNAPWS-hg24JGGw8Xe3EEZlLH0PM8qpUAfksPq",
"iv": "FJq5zKvuPiUQIdRcMtiChHCJByuY8XK9",
"tag": "u8kT0VAAtTswjGXxNpuX0g=="
}
}
Step 2: Send an encrypted Credential offer
Request
Make a request of the following structure to send the encrypted Credential offer:
POST /v1/messaging/send
Request body
{
"to": "did:key:z6MkgmEkNM32vyFeMXcQA7AfQDznu47qHCZpy2AYH2Dtdu1d",
"message": {
"protected": "eyJhbGciOiJYQzIwUCJ9",
"recipients": [
{
"header": {
"alg": "ECDH-1PU+A256KW",
"kid": "did:key:z6MkgmEkNM32vyFeMXcQA7AfQDznu47qHCZpy2AYH2Dtdu1d#z6LSsvqSJkBvVEsDC8cxMHuQ3sKoLRMXB1MdtoLrMUq6A8Rg",
"epk": {
"kty": "OKP",
"crv": "X25519",
"x": "JOLnYaD7L-Rszz7fczPhn6MkNre25PUsztzB1RHoz14"
},
"skid": "did:key:z6MkreuqFq6WrwozTeGKuUDz8bniTFRNAg8f3ZB862YdLp7v#z6LScyz3YLToyoKwZE6Tfq65hgZUkZdHrC4ZqohcUH9X6Twx"
},
"encryption_key": "ag5iKzjJOth9Wa68dCVKJW_vnO_Ga0zSJgQp5rIUg69HCzIjuNYhDg"
}
],
"ciphertext": "xpW-D6sDPpWc_jk87nEyxPX7JQV8_OZpaQft7ySQ5XmNhoj-lQyDkXDncOCyhB7yMSdZrRBNQjKxlEbpY_WLk1hBoWfsTeszVSAuFbX_VKUSJ7GR6rcnWGVNgDfKS8GsyC_owtswXatkF_65_mzFOygctkUmd2eI5bcpQpWjhw2vqnvnWkb7l2J27aWFF_c9cu52dB559j8lwLYyYC9oSMgV5piB6ppfrWBGo_DigjxvJcAYcjFYqFcT6A1nphPhwVTQ2HNfJodbQoseHub8UQdG4qAOcggq5DI84tbqor1SU9rdPH03jPkLgoO_aeXyJg5meITXoFSiu_tRfvf8QQ6vKq6pkTTXs8zKXcBCGhGIyKBNBG4R4RIY1UffTMnJQQQGBble3P06pGOnsnSop0BtygelB9M0ZEwnAUSAQqN1RR4AQwWcn9nH6hHEu1pMhSvhCuFNAPWS-hg24JGGw8Xe3EEZlLH0PM8qpUAfksPq",
"iv": "FJq5zKvuPiUQIdRcMtiChHCJByuY8XK9",
"tag": "u8kT0VAAtTswjGXxNpuX0g=="
}
}
to
: Use the intended holder’s Subject DID.message
: Use the content of thejwe
object from the previous step’s response (do not include thejwe
property name, just its content).
Response
A 200
response indicates that the message payload was sent to the service endpoint of the
dereferenced DID Document (or the default MATTR service endpoint).
Accept a Credential offer
Once the Credential offer is shared with the intended holder, it is up to them to use their digital wallet to accept the offer and claim the credential.
The credential is only issued after the intended holder accepts the Credential offer.
Troubleshooting
Below are a few common problems and their solutions:
Problem | How to solve |
---|---|
The app opens but does not show the credential being offered | Make sure the mobile device is connected to the internet |
Scanning the QR code using the phone’s camera doesn’t open the app (opens Google search or tries to load in the browser and fails) |
|