Run Credential Verify using a Callback

This tutorial will allow you to perform a Credential Verify flow and obtain important information from the Presentation including all the claims, the Subject Identifiers and whether the Credential has been fully verified or not.

This guide intends to show the raw workings of the Presentation Request during a Verify flow, some orchestration of events is required and the exact integration patterns with your infrastructure will need to be carefully designed.

Pre-Requisites

You need access to the MATTR Platform APIs. If you’re experiencing any difficulties, contact us.

In order to complete this tutorial you will need the following:

Sample App

If you prefer a hands-on approach to getting this working the Verify Credentials using Presentation Request Callbacks will step you through creating a simple Node.js Express server to orchestrate many of the steps below.

Invoke the Presentation Request

The Create a Presentation Request should be called every time a Presentation is requested.

json
Copy to clipboard.
1{
2  "challenge": "GW8FGpP6jhFrl37yQZIM6w",
3  "did": "did:key:z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5",
4  "templateId": "f95e71b0-9bdf-11ea-aec9-3b5c35fc28c8",
5  "callbackUrl": "http://71df02cc96e5.ngrok.io/callback",
6  "expiresTime": 1638836401000
7}

challenge is a unique identifier per transaction, this can be used as an interaction id.

The did must be available on the tenant and have a key type that is able to be used for messaging (e.g. of a ed25519 key type).

Provide the ID of the templateId that exists on the tenant, this will define the response of the Presentation Request.

The callbackUrl is the exact path that you want the Platform to message once it has received and processed the Presentation from the Mobile Wallet holder, it will be in the form of a JSON body.

expiresTime is optional, with a default of 5 mins, once the time (in Unix Epoch time in milliseconds) is reached the Presentation corresponding to the challengeId will not be accepted by the Platform. For the purpose of testing you may wish to extend this out.

Response

json
Copy to clipboard.
1{
2  "id": "38d9ca70-8b61-48c3-9efc-b67d97410743",
3  "callbackUrl": "https://c44077c6bd05.ngrok.io/callback",
4  "request": {
5    "id": "38d9ca70-8b61-48c3-9efc-b67d97410743",
6    "type": "https://mattr.global/schemas/verifiable-presentation/request/QueryByExample",
7    "from": "did:key:z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5",
8    "created_time": 1607300517863,
9    "expires_time": 1638836401000,
10    "reply_url": "https://YOUR_TENANT_SUBDOMAIN.vii.mattr.global/core/v1/presentations/response",
11    "reply_to": [
12      "did:key:z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5"
13    ],
14    "body": {
15      "id": "5770506c-9ce9-4d54-b295-68ad2bb12a4c",
16      "name": "certificate-presentation",
17      "domain": "tenant.vii.mattr.global",
18      "query": [
19        {
20          "type": "QueryByExample",
21          "credentialQuery": [
22            {
23              "reason": "Please provide your certificate.",
24              "example": {
25                "type": "CourseCredential",
26                "@context": [
27                  "https://schema.org"
28                ],
29                "trustedIssuer": [
30                  {
31                    "issuer": "did:key:z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5",
32                    "required": true
33                  }
34                ]
35              },
36              "required": true
37            }
38          ]
39        }
40      ],
41      "challenge": "GW8FGpP6jhFrl37yQZIM6w"
42    }
43  }
44}

The id and callback are used on the Platform, the body of the request payload is required by the Mobile Wallet client.

Sign and Encode the Presentation Request body

In order for the Mobile Wallet to have assurance about the Presentation Request, it must be signed using the authentication key from the Verifier DID.

The Create a JWS with a DID endpoint is available for this purpose.

First find the authentication key from the same Verifier DID using in the Presentation Request using the Resolve a DID endpoint. This also known as a DIDUrl.

Request

http
Copy to clipboard.
1https://YOUR_TENANT_SUBDOMAIN.vii.mattr.global/core/v1/dids/did:key:z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5

Response snippet from the 

json
Copy to clipboard.
1{
2  "didDocument": {
3    "@context": "https://w3.org/ns/did/v1",
4    "id": "did:key:z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5#z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5",
5    "authentication": [
6      "did:key:z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5#z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5#z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5#z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5"
7    ]
8  }}

Request

Use the didUrl and copy the body from the request field from the Presentation Request response to the body of the payload.

json
Copy to clipboard.
1{
2    "didUrl": "did:key:z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5#z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5",
3    "payload": {
4    "id": "38d9ca70-8b61-48c3-9efc-b67d97410743",
5    "type": "https://mattr.global/schemas/verifiable-presentation/request/QueryByExample",
6    "from": "did:key:z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5",
7    "created_time": 1607300517863,
8    "expires_time": 1638836401000,
9    "reply_url": "https://YOUR_TENANT_SUBDOMAIN.vii.mattr.global/core/v1/presentations/response",
10    "reply_to": [
11      "did:key:z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5"
12    ],
13    "body": {
14      "id": "5770506c-9ce9-4d54-b295-68ad2bb12a4c",
15      "name": "certificate-presentation",
16      "domain": "YOUR_TENANT_SUBDOMAIN.vii.mattr.global",
17      "query": [
18        {
19          "type": "QueryByExample",
20          "credentialQuery": [
21            {
22              "reason": "Please provide your certificate.",
23              "example": {
24                "type": "CourseCredential",
25                "@context": [
26                  "https://schema.org"
27                ],
28                "trustedIssuer": [
29                  {
30                    "issuer": "did:key:z6MkjBWPPa1njEKygyr3LR3pRKkqv714vyTkfnUdP6ToFSH5",
31                    "required": true
32                  }
33                ]
34              },
35              "required": true
36            }
37          ]
38        }
39      ],
40      "challenge": "GW8FGpP6jhFrl37yQZIM6w"
41    }
42  }
43}

Response

The response is a JWS

Copy to clipboard.
1"eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa3JldXFGcTZXcndvelRlR0t1VUR6OGJuaVRGUk5BZzhmM1pCODYyWWRMcDd2I3o2TWtyZXVxRnE2V3J3b3pUZUdLdVVEejhibmlURlJOQWc4ZjNaQjg2MllkTHA3diJ9.eyJpZCI6IjM4ZDljYTcwLThiNjEtNDhjMy05ZWZjLWI2N2Q5NzQxMDc0MyIsInR5cGUiOiJodHRwczovL21hdHRyLmdsb2JhbC9zY2hlbWFzL3ZlcmlmaWFibGUtcHJlc2VudGF0aW9uL3JlcXVlc3QvUXVlcnlCeUV4YW1wbGUiLCJmcm9tIjoiZGlkOmtleTp6Nk1rakJXUFBhMW5qRUt5Z3lyM0xSM3BSS2txdjcxNHZ5VGtmblVkUDZUb0ZTSDUiLCJjcmVhdGVkX3RpbWUiOjE2MDczMDA1MTc4NjMsImV4cGlyZXNfdGltZSI6MTYzODgzNjQwMTAwMCwicmVwbHlfdXJsIjoiaHR0cHM6Ly90ZW5hbnQucGxhdGZvcm0ubWF0dHIuZ2xvYmFsL3YxL3ByZXNlbnRhdGlvbnMvcmVzcG9uc2UiLCJyZXBseV90byI6WyJkaWQ6a2V5Ono2TWtqQldQUGExbmpFS3lneXIzTFIzcFJLa3F2NzE0dnlUa2ZuVWRQNlRvRlNINSJdLCJib2R5Ijp7ImlkIjoiNTc3MDUwNmMtOWNlOS00ZDU0LWIyOTUtNjhhZDJiYjEyYTRjIiwibmFtZSI6ImNlcnRpZmljYXRlLXByZXNlbnRhdGlvbiIsImRvbWFpbiI6InRlbmFudC5wbGF0Zm9ybS5tYXR0ci5nbG9iYWwiLCJxdWVyeSI6W3sidHlwZSI6IlF1ZXJ5QnlFeGFtcGxlIiwiY3JlZGVudGlhbFF1ZXJ5IjpbeyJyZWFzb24iOiJQbGVhc2UgcHJvdmlkZSB5b3VyIGNlcnRpZmljYXRlLiIsImV4YW1wbGUiOnsidHlwZSI6IkNvdXJzZSIsIkBjb250ZXh0IjpbImh0dHBzOi8vc2NoZW1hLm9yZyJdLCJ0cnVzdGVkSXNzdWVyIjpbeyJpc3N1ZXIiOiJkaWQ6a2V5Ono2TWtqQldQUGExbmpFS3lneXIzTFIzcFJLa3F2NzE0dnlUa2ZuVWRQNlRvRlNINSIsInJlcXVpcmVkIjp0cnVlfV19LCJyZXF1aXJlZCI6dHJ1ZX1dfV0sImNoYWxsZW5nZSI6IkdXOEZHcFA2amhGcmwzN3lRWklNNncifX0.9UxUPiJncUY-kxHmGTJpgJ-rty5OPcVMUGkVTDaChu9GWvE9y40qgYjXCnIfvITWHHUt587t-ygSFudh0N5_Dw"

Send to the Mobile Wallet App

The Mobile Wallet App has three main methods for reading Presentation Requests

  1. Scanning a QR code

  2. Opening a Deeplink

  3. Send a notification

Both scanning a QR code and the deeplink methods require the URL to be constructed in this format, where {jws} is the entire JWS from the Create a JWS with a DID endpoint.

didcomm://https://demo.vii.mattr.global/?request={jws}

The notification method requires knowledge of the subject DID, which may be obtained from a prior verification request or using a DID auth method.

Scanning a QR code

QR codes are a useful way to transfer information from desktop application to mobile apps using the phone’s camera.

Given the nature of the Presentation Request and resulting size of the JWS, pushing that much information into a QR code can be problematic for the mobile device reading the QR code.

Using a QR code API service results in something like this:

http
Copy to clipboard.
1https://api.qrserver.com/v1/create-qr-code?&size=400x400&data=didcomm://https://demo.vii.mattr.global/?request=eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa3JkaUNuZHZjeVVCcGRUQ1ZkNVRyaldFYTlocGp6V01mbUgzM1Q5alRKODFFI3o2TWtyZGlDbmR2Y3lVQnBkVENWZDVUcmpXRWE5aHBqeldNZm1IMzNUOWpUSjgxRSJ9.eyJpZCI6ImExODZjMTdkLTc2NzMtNDA2My05YmJmLTk4YmFiZWU1MzBlZiIsInR5cGUiOiJodHRwczovL21hdHRyLmdsb2JhbC9zY2hlbWFzL3ZlcmlmaWFibGUtcHJlc2VudGF0aW9uL3JlcXVlc3QvUXVlcnlCeUV4YW1wbGUiLCJmcm9tIjoiZGlkOmtleTp6Nk1rcmRpQ25kdmN5VUJwZFRDVmQ1VHJqV0VhOWhwanpXTWZtSDMzVDlqVEo4MUUiLCJjcmVhdGVkX3RpbWUiOjE2MDczMDI4MDAxMzksImV4cGlyZXNfdGltZSI6MTYzODgzNjQwMTAwMCwicmVwbHlfdXJsIjoiaHR0cHM6Ly9kZW1vLnBsYXRmb3JtLm1hdHRyLmdsb2JhbC92MS9tZXNzYWdpbmciLCJyZXBseV90byI6WyJkaWQ6a2V5Ono2TWtyZGlDbmR2Y3lVQnBkVENWZDVUcmpXRWE5aHBqeldNZm1IMzNUOWpUSjgxRSJdLCJib2R5Ijp7ImlkIjoiYmFkOWJiNzctYjk2Ni00N2I4LWExMzktZTkwNzNlNTgyNGFkIiwibmFtZSI6Ik1BVFRSIEVtcGxveWVlIENyZWRlbnRpYWwgVjIiLCJkb21haW4iOiJkZW1vLnBsYXRmb3JtLm1hdHRyLmdsb2JhbCIsInF1ZXJ5IjpbeyJ0eXBlIjoiUXVlcnlCeUV4YW1wbGUiLCJjcmVkZW50aWFsUXVlcnkiOlt7InJlYXNvbiI6IlBsZWFzZSBwcm92aWRlIHlvdXIgTUFUVFIgRW1wbG95ZWUgQ3JlZGVudGlhbC4iLCJleGFtcGxlIjp7InR5cGUiOiJNQVRUUiBFbXBsb3llZSBDcmVkZW50aWFsIiwiQGNvbnRleHQiOlsiaHR0cHM6Ly9zY2hlbWEub3JnIl0sInRydXN0ZWRJc3N1ZXIiOlt7Imlzc3VlciI6ImRpZDprZXk6ejZNa21SSmdqSFZvWURvSEh4RVZFU1VacGdpZVVmZW1QaEs5SktVVmNTZlJzb1ZKIiwicmVxdWlyZWQiOnRydWV9XX0sInJlcXVpcmVkIjp0cnVlfV19XSwiY2hhbGxlbmdlIjoiR1c4RkdwUDZqaEZybDM3eVFaSU02dyJ9fQ.zdFvxJvH72jNOFDSH5rzF1ZCKiqwyCeY1sw40r7vL49zH0haxQtiKmW6Yla74dIyqtJGrrzJRF64Vk3knQdDAg

https://www.datocms-assets.com/38428/1621292585-callback-qr-code.webp?auto=format

You might find a high-end phone with decent camera will read the QR code but many lower-end phones will never be able to.

Redirect URLs

For this reason the MATTR Mobile Wallet app will follow a 302 redirect if it is constructed in the way show below, this allows for the QR code code to be much smaller in size and therefore faster and easier to read by a wide range of devices.

http
Copy to clipboard.
1didcomm://${redirecterUrl}/{path}

The redirectUrl will need to return a 302 with the location of your tenant URL with the query param of ?request={jws}

Check out the “verify-callback-express” app as part of the MATTR Sample Apps to see a working example of this method.

The MATTR Mobile Wallet is set up to register global.mattr.wallet as a scheme and requires accept/ in the path.

In order to provide the didcomm://.. URL via a Deeplink, we need a further step to base64 encode that URL before being appended to the Deeplink URL.

Either use the terminal or an online tool to base64 encode the constructed URL.

Copy to clipboard.
1base64 <<< "didcomm://https://demo.vii.mattr.global/?request=eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa3JkaUNuZHZjeVVCcGRUQ1ZkNVRyaldFYTlocGp6V01mbUgzM1Q5alRKODFFI3o2TWtyZGlDbmR2Y3lVQnBkVENWZDVUcmpXRWE5aHBqeldNZm1IMzNUOWpUSjgxRSJ9.eyJpZCI6ImExODZjMTdkLTc2NzMtNDA2My05YmJmLTk4YmFiZWU1MzBlZiIsInR5cGUiOiJodHRwczovL21hdHRyLmdsb2JhbC9zY2hlbWFzL3ZlcmlmaWFibGUtcHJlc2VudGF0aW9uL3JlcXVlc3QvUXVlcnlCeUV4YW1wbGUiLCJmcm9tIjoiZGlkOmtleTp6Nk1rcmRpQ25kdmN5VUJwZFRDVmQ1VHJqV0VhOWhwanpXTWZtSDMzVDlqVEo4MUUiLCJjcmVhdGVkX3RpbWUiOjE2MDczMDI4MDAxMzksImV4cGlyZXNfdGltZSI6MTYzODgzNjQwMTAwMCwicmVwbHlfdXJsIjoiaHR0cHM6Ly9kZW1vLnBsYXRmb3JtLm1hdHRyLmdsb2JhbC92MS9tZXNzYWdpbmciLCJyZXBseV90byI6WyJkaWQ6a2V5Ono2TWtyZGlDbmR2Y3lVQnBkVENWZDVUcmpXRWE5aHBqeldNZm1IMzNUOWpUSjgxRSJdLCJib2R5Ijp7ImlkIjoiYmFkOWJiNzctYjk2Ni00N2I4LWExMzktZTkwNzNlNTgyNGFkIiwibmFtZSI6Ik1BVFRSIEVtcGxveWVlIENyZWRlbnRpYWwgVjIiLCJkb21haW4iOiJkZW1vLnBsYXRmb3JtLm1hdHRyLmdsb2JhbCIsInF1ZXJ5IjpbeyJ0eXBlIjoiUXVlcnlCeUV4YW1wbGUiLCJjcmVkZW50aWFsUXVlcnkiOlt7InJlYXNvbiI6IlBsZWFzZSBwcm92aWRlIHlvdXIgTUFUVFIgRW1wbG95ZWUgQ3JlZGVudGlhbC4iLCJleGFtcGxlIjp7InR5cGUiOiJNQVRUUiBFbXBsb3llZSBDcmVkZW50aWFsIiwiQGNvbnRleHQiOlsiaHR0cHM6Ly9zY2hlbWEub3JnIl0sInRydXN0ZWRJc3N1ZXIiOlt7Imlzc3VlciI6ImRpZDprZXk6ejZNa21SSmdqSFZvWURvSEh4RVZFU1VacGdpZVVmZW1QaEs5SktVVmNTZlJzb1ZKIiwicmVxdWlyZWQiOnRydWV9XX0sInJlcXVpcmVkIjp0cnVlfV19XSwiY2hhbGxlbmdlIjoiR1c4RkdwUDZqaEZybDM3eVFaSU02dyJ9fQ.zdFvxJvH72jNOFDSH5rzF1ZCKiqwyCeY1sw40r7vL49zH0haxQtiKmW6Yla74dIyqtJGrrzJRF64Vk3knQdDAg" | less

Add this base64 string to the Deeplink URL

global.mattr.wallet://accept/{base64String}

Then send this URL inside a standard message that can be opened on the mobile device (e.g. in an email or Slack message etc).

Send notification

All notification sent to Subject holder should be encrypted to protect the privacy of the MATTR Wallet users.
Use the Presentation request response with the Encrypt message endpoint with the known subject DID as the recipientDidUrl.
Send a message can determine the service endpoint of the known Subject DID which the encrypted payload will be forwarded to, which will result in a push notification to the MATTR Wallet mobile app user.

Further details can be found at the messaging overview page.

Action the request

Fulfilling the request (scan QR, click on deeplink or open notification) will result in the MATTR Mobile Wallet opening, you’ll need to authenticate, then the ‘Verification request’ screen should open.

https://www.datocms-assets.com/38428/1621293233-callback-wallet-present.webp?auto=format

The presentation is sent in this format

json
Copy to clipboard.
1{
2  "presentation": {
3    "@context": [
4      "https://www.w3.org/2018/credentials/v1"
5    ],
6    "type": [
7      "VerifiablePresentation"
8    ],
9    "verifiableCredential": [
10      {
11    "@context": [
12      "https://www.w3.org/2018/credentials/v1",
13      "https://schema.org"
14    ],
15    "type": [
16      "VerifiableCredential",
17      "CourseCredential"
18    ],
19    "issuer": {
20      "id": "did:key:z6MkndAHigYrXNpape7jgaC7jHiWwxzB3chuKUGXJg2b5RSj",
21      "name": "tenant"
22    },
23    "issuanceDate": "2020-08-30T23:24:54.876Z",
24    "credentialSubject": {
25      "id": "did:key:z6MkfxQU7dy8eKxyHpG267FV23agZQu9zmokd8BprepfHALi",
26      "givenName": "Chris",
27      "familyName": "Shin",
28      "educationalCredentialAwarded": "Certificate Name"
29    },
30    "proof": {
31      "type": "Ed25519Signature2018",
32      "created": "2020-08-30T23:24:55Z",
33      "jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..BSHdalZrYml0slwgAXFVF5uAcg2DbPMfwatturKs8TnuxBxylQDnS3JkORORVmO73Ruh7h8KJvVvHO4pE5NsCQ",
34      "proofPurpose": "assertionMethod",
35      "verificationMethod": "did:key:z6MkndAHigYrXNpape7jgaC7jHiWwxzB3chuKUGXJg2b5RSj#z6MkndAHigYrXNpape7jgaC7jHiWwxzB3chuKUGXJg2b5RSj"
36    }
37  }
38    ],
39    "id": "335032c1-0f8b-405e-9740-44928237e06c",
40    "holder": "did:key:z6MksMYtQSvQsfk3KZy7vxBzjcBJhx1i7TaLuvJePPPDEAjH",
41    "proof": {
42      "type": "Ed25519Signature2018",
43      "created": "2020-12-08T20:12:18Z",
44      "challenge": "e1b35ae0-9e0e-11ea-9bbf-a387b27c9e60",
45      "domain": "global.mattr.wallet",
46      "jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..MfVEy102c4oZA_G98G6HUxEmfXFLEIWbX9C36zF_cA-D8EF8jRMQWc5eJpMn3hgLm2xhPw8GzTrnwPHa37L-DA",
47      "proofPurpose": "authentication",
48      "verificationMethod": "did:key:z6MksMYtQSvQsfk3KZy7vxBzjcBJhx1i7TaLuvJePPPDEAjH#z6MksMYtQSvQsfk3KZy7vxBzjcBJhx1i7TaLuvJePPPDEAjH"
49    }
50  }
51}

Receiving the Credential Presentation Callback

Once a valid Presentation is sent by the Mobile App, the Platform will perform some checks to ensure the validity of the Presentation:

  • Issuer DID of each Credential can be resolved

  • JSON-LD context is valid for subject claims

  • Proof is valid & the credential has not been tampered with

  • If present check any Credential against its RevocationList2020 status

These checks will inform the verified boolean and where the contents is mapped to these fields and presented to the Callback URL as an application/json body.

json
Copy to clipboard.
1{
2  "presentationType": "QueryByExample",
3  "challengeId": "GW8FGpP6jhFrl37yQZIM6w",
4  "claims": {
5      "id": "did:key:z6MkfxQU7dy8eKxyHpG267FV23agZQu9zmokd8BprepfHALi",
6      "givenName": "Chris",
7      "familyName": "Shin",
8      "educationalCredentialAwarded": "Certificate Name"
9  },
10  "verified": true,
11  "holder": "did:key:z6MkgmEkNM32vyFeMXcQA7AfQDznu47qHCZpy2AYH2Dtdu1d"
12}

Conclusion

The steps outlined above give a detail explanation of the steps and some of the challenges involved in setting up an end to end experience. For a more hands-on step through, checkout the Verify Credentials using Presentation Request Callbacks sample app, alternatively Verify using the OIDC Bridge is another approach to obtaining verified credential data.