How to create an OID4VCI credential offer
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 parameters to support the issuance workflow.
Once the offer is created, it must be shared with the credential's intended holder so that they can claim the credential.
The process is similar for both the Authorization Code flow and the Pre-authorized Code flow. The main difference is the type of credential offer you need to create, depending on which workflow you are using.
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 (Only required when sharing the offer as a DID message):
- Issuer DID: This is a
did:web
that identifies the issuer who attests the claims in the credential are accurate. - 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.- 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.
- In production environments you must have a secure way to obtain the holder's digital
wallet DID:
- Issuer DID: This is a
Overview
The OID4VCI credential offer lifecycle comprises the following steps:
Generate an offer URI
Generate the offer URI by making one of the following requests based on the issuance flow you are using:
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 QR code.
- Send via a Deeplink.
- Send via a DID message.
You can use any of these methods regardless of the issuance flow you are using (Authorization Code or Pre-authorized Code).
A common way to allow a digital wallet user to claim a credential is to encode the offer URI into a QR code. You could even print out the QR code.
You can use a tool similar to the following to convert the URI to a QR code (make sure you use the
Plain text
option where available):
-
https://www.qr-code-generator.com/
MATTR is not affiliated with any of these service providers and cannot vouch for their offerings.
Once the QR code is created, you can send it to the intended holder via your preferred communication channel.
Best practices
- Make sure the QR code is large enough in size to be resolvable by a phone camera; 200px square is generally sufficient.
You can enable the intended holder to open the offer URI directly from their mobile device by creating a deep link.
- Perform base64url encoding of the offer URI.
You can use Base64 Guru or any similar tool. - Use the output (the offer URI encoded as base64url) to create a link of the following structure:
global.mattr.wallet://accept/{base64Url(openid-credential-offer://...)}
For example:
global.mattr.wallet://accept/b3BlbmlkLWNyZWRlbnRpYWwtb2ZmZXI6Ly8_Y3JlZGVudGlhbF9vZmZlcj0lN0IlMjJjcmVkZW50aWFsX2lzc3VlciUyMiUzQSUyMmh0dHBzJTNBJTJGJTJGdGVuYW50LnZpaS5tYXR0ci5nbG9iYWwlMjIlMkMlMjJjcmVkZW50aWFscyUyMiUzQSU1QiUyMjIwZDZiYmU2LWE5NzgtNDQ3Yy1iNWJkLWYzM2I2ZGNhMTllMiUyMiU1RCU3RA
- Once the deep link is created, you can send it to the recipient via your preferred communication channel.
MATTR GO deep-links
When sending a deep link to a MATTR GO Hold, replace the scheme with your app
bundle ID. The following example shows a deep link for a MATTR GO wallet that has
com.example.wallet
as its app bundle ID, as shown in the example below:
com.example.wallet://accept/b3BlbmlkLWNyZWRlbnRpYWwtb2ZmZXI6Ly8_Y3JlZGVudGlhbF9vZmZlcj0lN0IlMjJjcmVkZW50aWFsX2lzc3VlciUyMiUzQSUyMmh0dHBzJTNBJTJGJTJGdGVuYW50LnZpaS5tYXR0ci5nbG9iYWwlMjIlMkMlMjJjcmVkZW50aWFscyUyMiUzQSU1QiUyMjIwZDZiYmU2LWE5NzgtNDQ3Yy1iNWJkLWYzM2I2ZGNhMTllMiUyMiU1RCU3RA
MATTR Pi deep-links
For MATTR Pi Holder SDK customers, refer to your own implementation for deep linking requirements and best practices.
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:
POST /v1/messaging/encrypt
{
"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
Make a request of the following structure to send the encrypted Credential offer:
POST /v1/messaging/send
{
"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.
How would you rate this page?