Skip to content

Latest commit

 

History

History
513 lines (391 loc) · 27.5 KB

6.Credentials.md

File metadata and controls

513 lines (391 loc) · 27.5 KB

6. Credentials

A credential is a set of signed information provided by an Issuer, representing digital credentials which can be used to prove yourself. Credential issuance implemented using Camenisch Lysyanskaya signature schema. During the credential issuance process, the Issuer signs a digital credential that the Holder processes and saves into Mobile SDK wallet thereby only the Holder can use it. Mobile SDK can receive an unlimited number of credential in this way.

There are two roles in the connection establishing process: Issuer and Holder.

  • The Issuer is the party that can sign some sort of reliable digital credentials. Verity SDK can be used as an Issuer.
  • The Holder is the party that accepts and stores digital credentials which can use later to prove yourself. Mobile SDK represents the Holder party. Bellow in this document we will explain which steps need to be taken in order to accept a Credential on the Holder side using Mobile SDK.

NOTE: library should be initialized before using credentials API. See initialization documentation

NOTE: there must be established connection between Issuer and Holder. See connections document

To complete this section read through the following sections:

  1. Responding to Credential Offers
  2. Deleting Credentials
  3. Cache data for Proof generation
  4. Credential with attachments

Responding to Credential Offers

Aries Credential Issuance protocol consists of several messages exchange:

  • Issuer sends Credential Offer message to Holder
  • Holder handles Credential Offer message and sends Credential Request message to Issuer
  • Issuer handles Credential Request message and sends Credential message to Holder
  • Holder handles Credential Request message and sends Credential Ack message (if requested) to Issuer

Steps overview

In order to handle a Credential Offer a Holder (client) need to take the following steps:

  1. Download and Parse Credential Offer message received from the Pairwise Cloud Agent.
  2. Create Credential state object using parsed Credential Offer message.
    1.1. Serialize Credential state object and save serialized representation.
    1.2. Update Credential Offer message status on the Agent as reviewed.
  3. Accept Credential Offer
    3.1. Deserialize associated Connection state object
    3.2. Deserialize Credential state object
    3.3. Send Credential Request message
    3.4. Await Credential status is completed
    3.5. Serialize Credential state object and save serialized representation
  4. Reject Credential Offer
    4.1. Deserialize associated Connection state object
    4.2. Deserialize Credential state object
    4.3. Send Credential Reject message
    4.4. Serialize Credential state object and save serialized representation

0. Credential Application object

As we mentioned before in the Storage document SDK does not save state objects, so the application must care about it. It is up to the developer regarding what data to store in the application.
On of the possible formats may match the following structure:

{
    "pwDid" - string, // reference to the connection from which credential offer was received 
    "serialized" - string, // serialized representation of SDK Credential state object
    "threadId" - string, // Identifier of credential issuance protocol. 
                         // This is needed to match the following messages related to the protocol instance.

    // metadata to show on the UI
    "name": string, // credential name
    "attributes": { // credential attributes
        <name>: <value>, // attribute: value
        ...
    },
    
    // optionally
    "connectionName": string // name of the connection from which Crdential Offer was received 
    "connectionLogo": string // logo of the connection from which Crdential Offer was received 
    
    "timestamp": int // optional, time of receiving a credential (it can be shown on the UI and used for sorting) 
                     // it must be set when actual credential is received.
    "status" - string, // credential status (pending / issued)
}

Later in this document, we will show how to get each of these fields.

1. Get Credential Offer from pending messages

  1. Download pending messages (see messages documentation for messages downloading information). Pending messages with credential-offer type should be used. Extract credential offer JSON string from the downloaded message (value of decryptedPayload field).

    Example of Credential Offer

    {
       "@id":"6269f643-beb2-4e98-92f1-b9683fa1cb36",
       "@type":"did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/issue-credential/1.0/offer-credential",
       "comment":"DEMO-Transcript",
       "credential_preview":{
          "@type":"did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/issue-credential/1.0/credential-preview",
          "attributes":[
             {
                "name":"DEMO-College Name",
                "value":"Faber College"
             },
             {
                "name":"DEMO-Degree",
                "value":"Computer Science"
             },
             {
                "name":"DEMO-GPA",
                "value":"4.0"
             },
             {
                "name":"DEMO-Major",
                "value":"SSI Software Engineering"
             },
             {
                "name":"DEMO-Student Name",
                "value":"Alice Andersen"
             }
          ]
       },
       "offers~attach":[
          {
             "@id":"libindy-cred-offer-0",
             "data":{
                "base64":"eyJzY2hlbWFfaWQiOiJMblhSMXJQbm5jVFBadlJkbUpLaEpROjI6REVNTy1UcmFuc2NyaXB0OjYyLjIzLjQ3IiwiY3JlZF9kZWZfaWQiOiJMblhSMXJQbm5jVFBadlJkbUpLaEpROjM6Q0w6MjcwNzA4OnRhZyIsImtleV9jb3JyZWN0bmVzc19wcm9vZiI6eyJjIjoiOTcyNDEyMDUwMDE0MTM4NDUwMjY4MzQ4OTU0MDA5NzEwNzgzNzcyMzE2MjcxODUyNDYzMjkyMTE5MzAxOTY2MjU0OTI1MTA5MzAzNzgiLCJ4el9jYXAiOiIxODc3MzMwNDEwNzM0NjA4MjQ0NzQ4OTIzMjMwNzk4MDE5NzgwNTI3MDM2MTQ2MzIwMzM3MDQ5MzQxMjkzMTU4MTY2NDUzMTg0MjAzMjUyOTU2Mzc1MzM3OTI5OTIwMzgxMDE1OTI5MTI0ODA2MjUxMjM3ODYyNTEzMjIyMDkyODc5OTI2MzM3Njg5MDY0NTI1NjAwNTYxMDE1ODk0MDc5NTk5MzM2OTcyNDE0MjI1NDIwMzQ1MTM5NTg5Njc5NzU3NjU5NjQ5MDYwMDM1NjkyMzY3MTgwNjA1NjQ0Mzk3NTYxNjA1MTY5NjU3NTA3MjE0OTEyMzkwMTQ5Njg2NDY3MTEzMTAzMjE0MDQxMDIwNDAzNjMwMzQ0NjI4MDE1NzkyMjQ1MDMzNDM3ODkwMzcwMzE0MzIxODc4NzgzMDA1NjE2NDQ5NTg3ODUwNDI3MTg4NzgyODQ3ODg4MjM1MzEwNDExNjA4NDY3NzUxMjkxMzY5NjE2OTgwMzE2MzcyODA2MDk5NzU0NzMyODY0NTM4Njg3MTUwOTM2NDI4NTQ3MDc2MTQ1NTY2NzIzNTU4MjI2OTIwMzE4MTA4NzQ5NjQyMjkzMDQwNTIyODA2MjExNzM2NTA4NzU4MTU2NzM5NTA4NjM5NDc5NDA0MTY2NTk5OTc2OTU3MzAyMzQ0OTQ2NjAyNTM5NTE4OTM2MzgxNDE2Mjk0NDk1NzExMjg2NjEwMjk0NTk0MTEyNzk3NzMxNDc0NzQwMDQ1NTYyNjUxNDQ1NzE1MTUxODYwNTAyNTkwNjk3NDcxNzczODI5MDg5OTI1NzM4OTI3OTUyNDkxMjg3NjEwNDgyNzQ5NTI4OTAxNDc4MzI3NzIwNDI5MDY1OTY4MjYwNTk3NTU4NTI4ODI4MTgyNjYzOTI2MDUwNjA2NTk2MzE2IiwieHJfY2FwIjpbWyJhZ2UiLCI2NjM3MzcyMzI4NDIwNjAxMTQ2ODc0OTcyNjU4MjIyOTY5NjIwMDM0MTY5NjMwMDA2MDg3NDUyOTU5NTg3MjM2MjExMzkwMjgwNTM1OTgzNTU0ODc4OTMxMTI2MTk1NjMzNTM3NDIxNTU3ODg0MTM1NDIxMDE2OTIyMzE0MzQ2MjE3NDE1Mzg0OTM1MzMzMjg2NTM5ODc4NTEyOTMxMDU2MjkyMjI1MDA2OTg5NDM5Mzc0OTM4ODMwNzc5ODE4NzczMTM4NDMyMjU2MzY0MzA5MjQyMjU4NzExMjgwODQwOTI3NzI2Nzg1MjM2MDg0Mjc1NzM1NjU1Mjc1OTU1OTc1NzkxMDczOTUzNDk4NTkwOTU4Mjk3ODM2MTExNjYxNzY3NDg3OTA4OTI2OTgwMzA2NzAyMTAxNzU1MDUwNjQzODMzNjc0MzQ0NDgxNzY2MzE1MDI4Mzg4NzQyMTE3MTI3NjI5MjczMTYwMTQyNjk1MjM5NDIyNDc2MzY2OTQyMjIzMjg0MTEzNDYxOTU4NTE3OTI4MjczMzgxNjE1NzM1MzY2NjQ4NTA0MTQwNTc5NDI2OTI2NDg1OTQzODUyODA0NjIyMzAxMDk4MDc5OTIzMTczOTAyNTA3NTE2MzYzNzA5NDM3MjU5NDQxMzY0OTU0OTE1NjAzNjUyMDE3OTk5MTUxNjk4NTkwMDcwNTM1OTUzNzE5MjkwOTI2NjEzNjIyNzI0MzYxNjA1OTg5NzU0Njc1MTUxNTEyNjMwNzE5NDU0MDMwNjcwNDkwMzE1MTUzOTE2Mzk2MTUzNTIzMTU0NTMxNjQ2OTc1MTYzNzc3OTY0Njg0ODYzODIwNjQ3NzUyMTE5NDU4NjkyNTE3Nzg2NDMwNzYxMjk2NDY3MjgxODQ2MTgzMjQzNTg3NjE1MjIzNTU2NDYiXSxbIm1lbWJlcmlkIiwiMTgyMjMyMDc4ODMxODEyNDc3NDM3NjE1NzU3ODgwMTIxNzA2MjIyMDYxNTE4MzMwMjI3NTE5NzUwMjEzMzk2OTYxMzE0MTU2OTU3OTg5MjQwNzUzNjQwMDQxNDc4MDYwOTE2MzAzNzI3MzQ4NTU1ODgzMjE2MzM0NTMxMzMzMjI1NzA3ODg5NDgyMzM5MTQ5NTMyMDAxMjA0MjM1OTg0NzAzNTAzOTA4OTg0MDc2NTE4MjY0Njg5ODAxMTkwMDc3MzY0MjQ4ODg1NTE2MDc0NTI0NTg4MjMwMTQ2NDI5MDIyOTgxMzIwNjQ1NDQ1Mjg2MTk3NDkyNDU1MDU1NjEwOTY3MTcxMzQxMzExMjg1NDY0NjY1NzYxODE2MTI3MDE0MjA3MzY0ODU1Mzg2OTYxODUwNzY5ODE3OTE2OTE2NTI5Njc0MjQ5NjY1MDc0MDI0MjgxMzMwMTE4NjAwMjQzOTM0NDk0MjQxMTM1MzI0MDQ5ODUxNDQwNjg5MzkxNDQxODI1NTc5Mzc4MjA3MDM2ODUyMzM5MzMxMTAxMjU1OTcwNjU2MDcxNDc5Mjc1ODQ1ODY0OTY1OTk4ODczMDQ0NjM3MTQ2MTY0MzEyMzMxMjIwNjExNDEwOTg1MDg0MDI3MTg4MDg5NzI1NzQxMDY1MDAyODg0NTQ4ODYzMTE3ODA2Mzk4MjMyNzA5MDQ5NzYwMjQ1MTQwNzI1NzEwNTM3NDExOTEzODE0NjkyMDk2MDExOTQ4ODc4MzE1NDA0MTc0MzM3NTg0MDY0MTg4NzYxMTgxMDU5NzY3MjIwNjk3MzA2MTMwMjEyMTE4MTM2NDc1OTQwMTg1OTA1NDczODMwNjUyOTc1NTM4NTY5MDUyODA2NTcwMjI2NDk3MzA5ODkzMzI3NjcwNjY3MDk4NzE4MTAzOTY0MyJdLFsic2V4IiwiMjAxMDExNTg1NDczNjY3MTYzNjMzOTc4MTg4MjA0MjgwNDM2MTI3NTM5OTYxNTA2NTk3MTYwNjUwMDY1NjMwNTg4NDQ4MTk0MDI4NTUyNDc5MDI1NTU5NzUxMjQ0NTY2NzA5ODIxMTU2NTUyMzIyNTgzMzYwNTUxNjg1MDY5Mzg3NzY1NTM2NjEzMDgwOTEwODE2NDA4NjgyNjUzNDc1MzE0MDAyNzM5MzM2MzY2MTM1Mzk2OTgzMDY1OTA4NjIyNjczMDEzOTM5NjUzOTk2OTc1NjE5Nzg1MjA0MzQzNzE4NjE3MjM3NzI3NTkyNDcyMDIxNjg3MDQ5ODU5MTQzODI0NjU1MTg2MzE2OTMxNjI4Mjc4NDg5MzYzNDAyMzQ0NDkzNDM2MTU1MzA3NTAxNjg2Njk2NjMwMzE4MTQxNDAxMDM3MjAyNzA2MDEwMzk1MDI3NjU3MjE3NDMzMjgwMDAyMjc4NTg3OTA1NTMxNTcxMjM2MTM5OTk2OTU5ODE2NjE1Mzg0NjU2OTM3NjA5NDE5MzExNzAzMTI1Mjk5Nzc4NDMwNzQyMjg5OTU1NzUwMzU5NjY1MjE0MzM4NzM5Nzg5MzAzNDIxOTY0MjIwMTAyMDI4MTkzMDgwMzk1OTg3NjEwOTQ5ODIzNDYyMTQ5NDkyMjgwNjkwNzk3MjU4ODc4NjQ5MjU5NTY3MDUyOTMyMjQzOTIyODgwNDE2ODI4ODQ0MzMyOTg0NjAyMjcxODkwODk3NjA0OTUyMDUzMjg2Mjk2MzEyMjU3MDQ4MDY3MzAyMzAxMzYwMjMxMTM1OTk3MDc3NDk2NzY5MzU5NzA0MDM0NjA1NjY0NzgzMTg2Njc4NDMxMDE0NzQ0MTEwODUwMTk0NjA3ODc5MjkxNzAyNjIzNDc0MDMwOTQ3OTU1MjAzNjk0MiJdLFsiZmlyc3RuYW1lIiwiMTMzNzE1MzcwMjA1MTU4NTc0NDYzODYzMjE2NjEzNjI0OTcxMTg3ODUwMjczNzUwNTYyMDkwMTg0MTc4OTAzOTM4Mjk3NDUxNjQ2NjEwNzQxNDU1MjA0NTY1NDU0NzU5ODMwMzgzMDk1MTg1MDI3MDY0Mzc4NzE5NzMwMTM3NjE5OTA2MDA5ODczMjA3Mjg0MDYyNjU5MjQzMjAzNzczMzQ3MTU2Njk5ODAwOTA4ODc4OTgyMDMxNzM0Mzc4MTUyNTc1MzA3MjkxNDUyNzAzMTkzNDI3Nzg0NDU4OTY3Njk4OTgyODU4MTE3MzAxNTQxNjU0NTkwMTY5NDY5Mjg1OTk2NjY5MDg0MjMxMDczMzc0MzM2OTU5MzM4Nzg5MDYxODMzMDg4OTA1NTQyNTMyMDI0MDYyNzI3NTk4MzM0MjUxMzA4OTQxOTcyNDM1ODQ4MDExNTQxMjg4MzU0NDk3MzE0NDM5MjY2ODQxMTcwOTU5MDg0OTg2ODYwODYyOTQ0MDY3ODY4MjE2NjI4OTQ1MzcyOTEyMTkzMjA3OTQ4Mzg5ODI0MTk4MjExNDc5Njc1NzA3OTU3MTU2MTAyNzg2NDUyOTk5Mjc3MTc3OTIzOTkxMDgyMjUzNDQ3NTMxNjQ5OTYzNDE0Nzc5ODg2MDgyMjk3OTk1ODg1MTczNzQzODY0MDc1NzI2MzI3NDc4NDYyNzE2NDY3ODg0NzYxNTA3MDM5NzAwOTQ1NDIzNzQ0MTA5ODI0MDA0MDEzMTkyNTQ0NjM4NTY4MzM3MzMwMDA4MDY4NDIxMjY0MTk2ODk0OTc2NTk1ODMyODc3ODQ3ODU2NDg3OTU4ODMxMTkwODQwODM2OTEzMDI1MDUwMjY2NDk2Njg3NzYzMzMwNDgyMDEwMTA0ODIyMjMwOTU5NzAxNTU3NDUzNiJdLFsic2FsYXJ5IiwiMTAyNjAyOTA4NzM4NjU4Nzc2MzY5NTg1Njc5OTUxMjM1MzUyNDUwMzM1MDA5NTIyMzY3Mjk2MDc0MTQ0ODcxODYyOTI4MjY3NDM5NTA1Nzk2MDU3MzI4MDU3MDYzODQyMjQzODEyNDkzODY1Mjc4NDY2MzM3NzI3NTk0MzIzODE2NzY1NTI5MTAxNDE1MDQ2NTIzOTg1NzU4ODUxNTkzMzU1NjU4Njk5NTA5MTUxMzM1ODI0Mjk1OTg1Nzg3OTc2NzEyOTkxNTAyNDE4ODQyNzk3MzU5NjM1MjM3Nzk1NzE5ODIzODExMjM3MTY0MzM1NDM5NDI5NDg4OTc3NjcyMjE1MzM4MDgwOTg0MjQ1MDUzNjgwNzYxNzQ0NTg5OTk2MjAzNzQ0MDIyMzE5NDA4NDgwMDA1Mzc5OTIwMjU2MzU3ODcxNTYzMzM5NTU2MzA1Njk5ODQzNzY0MzgxNDQzNDg3ODA5MDU0OTcyNDE0NjUzNTM0NTc1MjkwMTE1NDkwNDEwNzE4NzQ5MjM3NzY4MjQwNDEzMjc1MzM4MjUxMDYxMzIzNzcwMjkzNzg3ODY0ODgzNzcyMjc5NzAzOTA0MzAwOTQzNDI2NjM4NzQ0ODU1MTkyNjQwMzk1MDU3NzE0MDAyODk5NDgyNzkyMDcwODg5NjMzOTE4MDMyNDU4MzcxNzYwNDI4NzgxMTc5MzM0NDA3ODk5Nzg2NDg2MjU2MTU5MzY3OTA0MzUwOTM4NTgwMTg1MTkxOTg0MzU5NTc5Mzk0NDkwNzU2Mzg2NjU4NTUzOTI5NTkzNzYyODI2MTkyOTE0MTkyOTcwNzcxMDY2MTA0MTk2ODMyODAyMjg0MTAwMDc0ODAwODQ2NTcyODg3NDMwODExMjU3MjI5MDU3NzAwNDE0NTUzODE4OTc2MjQ4MzM2NyJdLFsibWFzdGVyX3NlY3JldCIsIjE5MTc1MjU2MTcxNzk1MTE4OTM2MzYxMDkyOTU5MDYyMDQzOTkxOTA3MTczNjE0OTM2MjY1ODI3MzExMzU2NzU1OTAyMDQ3NDM4ODA3Nzc2MzIyMTkzMzk4MDc3MDE0MDUwNTkyNDU4NzEzMDkyMzgwNTgyNTQzODgwODk3MzkyNTg3NDkwNDUxNjM1MjM5MDQ5OTA0ODI2NTEzOTUzODE1NDY0NTEwNDU1MDQwNTUwNTg3MTY2NTgwNzgyMzA4NjU5ODQxMzE2NzAwOTA1MTU3OTU2NjQ4MDY4MjA3MjY0MDc2NTM1NTIxMTE0NDUyOTg5ODk5NzM3MTcwNjkzNDI3NzQyODc5NDIzNjI4NTMxOTM2OTYzNjMwNzA4NDc2MzQ2ODY2Nzg3Mjk5NjQ2ODUyMDE5NDQ4MjgyMTUxMjU3OTA0NTk5NDQzODE3OTYwMjAzMzk0MTk0MTUxODY5Njk1NDI4NzA1Mzg3OTQ0NDQ0NTE3MjU0ODE2MTkwNDY1MTk5MzgyNzI1OTU5MTAzNzY1MTEwMTg5MTQxNzgyMzk0NTk0MjU1ODU3OTkxOTUwNzAwMDg1ODcxOTQ4OTEyMDY3MzMxNDE2MzQ4NTE3NjQyNDIyMTIxMDQ1ODUxMDg5NTIxNDA5NzMwNTM2NjE1MzAwOTEzNTY4OTUwMDUwODY4NDMzNDc4MzY5NjAwODAxNTkyNzY0ODg1MTkwMDQzNzMzNjk3MTM2MTMwMTQ5NzUzMDIxMDEyNjg2MTY0MzAwOTM4OTg5MDE2NzI4NTYwNzQ3MzQ4NzkxNDAwNjAzMTkyOTI3MzUzNzc3NjkzODk4MzAzOTI0OTU3ODY5NzgyNTU4MzI1ODM2NzE1MjM4MTQ5NDkxNDA0NDI5NTI0MDM5OTMzODgxNTUyMTAzMjEwNjUzNzE0OTgiXSxbImxhc3RuYW1lIiwiMTcwMjM1NzU3MDEwODIzNDA2NzYzNTY1NTAxNzY1NDg4MTE1MzAzNzkxNTk1NTk0NTAyNjcxOTg1ODU3MjY3NjY2MzEzNjE3MDkyNDgzMTIyODAwMzE0NzUyMjYyMjA1NzE1NTg4MzEzNDg4NTQ3NzQ1Mzk3MzAxMjE0NDU5NTI2MDA3Nzk1NjM2NDAxMzU5OTAzMDM0NzMzODEwOTA5NzgzNzQ0MzA4ODI0OTg3NTU5NDQyNjE0MTk3ODgwOTE1NDYyNzAwMTM1MjU0ODQyMDYzOTU0Mzg1OTcwMzY4NDQ1NzM5MTQ4OTMyMjYyNTkwNjQ1NjM2MDYxMDMwMjgyNTY5MjUxMDMzMjExMzE0NTk0NTQ1ODk3NjAwMDQ2MTU3Mzg3MDg0NTM5ODE1NTkyODU1NDYxNDA2Nzg1Njc5ODY0NTYwODQyOTMwMDQwNzg2MjY3ODY3ODMzMjYzMjA0OTcyMDI3NzcxMjcyOTk5MDc5MTU1NjE4OTMxMjI1MjcwOTE2OTU3MTEwNDQwMDA0NDA5MDI4MzA0MTAxNTk5MjYwNDYxMzQ5MTk1MDkxOTAzNjY5ODA0NzE3ODMzODE0NjQwNzU5OTM5ODI5NDY3MTc4ODkwOTEyMTMzNjU5ODIyMjg5NjA5NjMwNzk3Mjg2NzAxMDUyOTA2MDU4NTk4MTE5MTgxMzg1ODc2MDE2NDMyOTM0MTc5NzUzNDA2MjY0MzQzOTM4NTIwOTU1ODk0MTAwNjk3MTgxOTY1Mjg3NzkxMjYzMjkzNTY4MDIxNzAzNjU5NjU1OTQzNDIxNDY0NTQ4NzE1MDU1MTg0MjUwMDk3MDk1NTQ4NDI4MTIxODgxNzczOTI2MzM3NDMyMTE5NzU0NTI5ODMxMDE5MTI1MDM2NDU2Njc1Mzg4Nzg0MzY2MjU0OTA2NCJdXX0sIm5vbmNlIjoiNzE1MjI4ODAyOTM3MzkwNTU1MzA3NzEzIn0="
             },
             "mime-type":"application/json"
          }
       ],
       "~thread": { // (Optional) maybe omitted
          "thid": string, 
       }  
    }

The following data can be taken from the Credential Offer to fill the application Credential object we defined before:

  • comment - name of the credential.

  • credential_preview.attributes - array containing objects with offered attributes and their values.

  • ~thread.thid or else @id - Identifier of issue credential protocol. This value is needed to determine the next protocol message after offer acceptance.

    In order to fill pwDid field you need to take pairwiseDID value from the downloaded message.

2. Create Credential state object using received Credential Offer

  1. Create Credential state object

    iOS

    [appDelegate.sdkApi credentialCreateWithOffer: sourceId
            offer: message
            completion:^(NSError *error, NSInteger credentialHandle) {
                // ...
            }];

    Android

    int credentialHandle = CredentialApi.credentialCreateWithOffer(sourceId, message).get();

    sourceId - any string
    message - message downloaded on step 1.

  2. Serialize Credential state object

    iOS

    [appDelegate.sdkApi credentialSerialize: credentialHandle
            completion:^(NSError *error, NSString *state) {
                // ...
            }];

    Android

    String serializedCredential = CredentialApi.credentialSerialize(credentialHandle).get();
  3. Save serialized sdk credential state object into your application connection object.

  4. The status of the credential is considered as pending at this step.

  5. Every time in the future you want to perform some operations using the created credential object you first need to fetch Credential object from the storage and next deserialize SDK object from its serialized representation (receive a new handle).

  6. Update status of correspondent message on the Agent. See messages documentation for message update information.

3. Accept Credential Offer

If a user agreed to receive a credential related to the received offer, the following steps should be done in order to receive the actual credential.

1. Deserialize Connection state object associated with received Credential Offer

iOS

[appDelegate.sdkApi connectionDeserialize:serializedConnection
        completion:^(NSError *error, NSInteger connectionHandle) {
            // ...
        }];

Android

int connectionHandle = ConnectionApi.connectionDeserialize(serializedConnection).get();

2. Deserialize Credential state object associated with accepted Credential Offer

iOS

[appDelegate.sdkApi credentialDeserialize:serializedCredential
        completion:^(NSError *error, NSInteger credentialHandle) {
            // ...
        }];

Android

int credOfferHandle = CredentialApi.credentialDeserialize(serializedCredOffer).get();

3. Send Credential Request message to the Issuer.

  • Credential Request message contains a blinding factor which Issuer must use during Credential signing. If someone later intercepts Credential message intended to the Holder he will not be able to use it without knowledge of the key which was used by the Holder to generate the blinding factor.

  • The private key used for credentials blinding is generated once on the first Mobile SDK initialization and stored in Mobile SDK wallet in encrypted form. The private key cannot be read from the wallet.

    #### iOS
    
    [appDelegate.sdkApi credentialSendRequest:credentialHandle
            connectionHandle:connectionHandle
            paymentHandle:0
            completion:^(NSError *error) {
                // ...
            }];

    Android

    CredentialApi.credentialSendRequest(credOfferHandle, connectionHandle, 0).get()

4. Serialize Credential state object and store in the application storage.

Theoretical, processing of the Credential Request message on the Issuer side may take a while and User can just close the application before completion.
It's better to store the credential state machine (received after sending Credential Request) into the applicaiton storage to avoid data loss.

If you wish, you can skip storing for now and do it only after the credential will be completed (after step 5).

  1. Serialize Credential state object

    iOS

    [appDelegate.sdkApi credentialSerialize: credentialHandle
            completion:^(NSError *error, NSString *state) {
                // ...
            }];

    Android

    String serializedCredential = CredentialApi.credentialSerialize(credentialHandle).get();
  2. Update serialized value from the corresponding record stored in the application storage.

5. Await Credential received.

When Credential message will be received from the Issuer the state of the Credential object will be equal 4 (Accepted). Mobile SDK unbind actual Credential and stores it into Mobile SDK wallet in encrypted form. The credential signature cannot be read from the wallet.

There are two options regarding how to await Credential message depending on the messages receiving strategy you use:

  1. Polling - call credentialUpdateState function in loop until returned state is not equal 4 (Accepted).

    • Call following code in a loop until the returned state is not equal 4 (Accepted).

      iOS

      while(1) {
          [appDelegate.sdkApi credentialUpdateState:(NSInteger) credentialHandle
                                            message:(NSString *) message         
                                         completion:^(NSError *error, NSInteger state)) {
                      if (state == 4){
                          break;
                      }
                  }];
      }

      Android

      int state = -1
      while (state != 4){
          state = CredentialApi.credentialUpdateState(handle).get();
      }
    • These functions do the following things internally:

      • Downloads all pending messages from the Cloud Agent related to the connection
      • Find matching Credential message
      • If message found -> updates state machine with it and update message status on the Cloud Agent as read.
  2. Push notifications - as push notification doesn't contain the type of received message we can download all messages and analyze them:

    • Use common downloadPendingMessages function to download messages.

    • Find matching Credential message. The following conditions must met:

      • value of ["decryptedPayload"]["@type"] field must ends with issue-credential
      • value of ["decryptedPayload"]["~thread"]["thid"] field must match to the value of @id field from Credential Offer.
    • Update Credential state object with received Credential message:

      iOS

          [appDelegate.sdkApi credentialUpdateStateWithMessage:connectionHandle
                                                       message:message
                                                withCompletion:^(NSError *error, NSInteger state) {
              // ....
          }

      Android

      int state = CredentialApi.credentialUpdateStateWithMessage(connectionHandle, message).get();
    • Update status of the message as read. See messages documentation for message update information.

      iOS

      [appDelegate.sdkApi updateMessages:messageStatus
              pwdidsJson:handledMessage
              completion:^(NSError *error) {
                  // ...
              }];

      Android

      UtilsApi.vcxUpdateMessages(messageStatus, handledMessage).get()  

6. Serialize Credential object and store in the application storage.

  1. Once we get the credential completed (it means that internal representation of SDK credential state object changed) we need to update the corresponding record in the application storage to contain the latest serialized credential state.

    iOS

    [appDelegate.sdkApi credentialSerialize:credentialHandle
            completion:^(NSError *error, NSString *state)) {
                // ...
            }];

    Android

    String serializedCredential = CredentialApi.credentialSerialize(credentialHandle).get();
  2. The status of the credential is considered as issued at this step.

  3. You also can save the timestamp of credential receiving.

  4. Update a related record in the storage with the latest value.

4. Reject Credential Offer

If a user does not want to receive a credential related to the received offer, the following steps should be done in order to explicitly reject offer (notify Issuer).

1. Deserialize Connection state object associated with rejected Credential Offer

#### iOS
```objC
[appDelegate.sdkApi connectionDeserialize:serializedConnection
        completion:^(NSError *error, NSInteger connectionHandle) {
            // ...
        }];
```

#### Android
```java
int connectionHandle = ConnectionApi.connectionDeserialize(serializedConnection).get();
```

2. Deserialize Credential state object associated with rejected Credential Offer

#### iOS
```objC
[appDelegate.sdkApi credentialDeserialize:serializedCredential
        completion:^(NSError *error, NSInteger credentialHandle) {
            // ...
        }];
```

#### Android
```java
int credentialHandle = CredentialApi.credentialDeserialize(serializedCredOffer).get();
```

3. Send Credential Reject message to the issuer

#### iOS
```objc
[appDelegate.sdkApi credentialReject:credentialHandle
        connectionHandle:connectionHandle
        comment:@"Rejection comment"
        completion:^(NSError *error) {
            // ...
        }];
```

#### Android
```java
CredentialApi.credentialReject(credOfferHandle, connectionHandle, "Rejection comment").get()
```

4. Serialize Credential state object

iOS

```objC
[appDelegate.sdkApi credentialSerialize:credentialHandle
        completion:^(NSError *error, NSString *state)) {
            // ...
        }];
```

Android

```java
String serializedCredential = CredentialApi.credentialSerialize(credentialHandle).get();
```

5. Update a related record in the storage with the latest value of the serialized Credential state object.

Deleting Credentials

It may happen that after some time a User wants to delete credential that are no longer need to him. In order to delete a credential you need to perform the next steps:

1. Delete a Credential stored in the Mobile SDK wallet

  • 1.1. Deserialize existing Credential state object

     #### iOS
      ```objC
      [appDelegate.sdkApi credentialDeserialize:serializedCredential
              completion:^(NSError *error, NSInteger credentialHandle) {
                  // ...
              }];
      ```
    
     #### Android
      ```java
      int credentialHandle = CredentialApi.credentialDeserialize(serializedCredOffer).get();
      ```
    
  • 1.2. Delete Credential from the Mobile SDK wallet

     #### iOS
      ```objC
      [appDelegate.sdkApi deleteCredential:credentialHandle
              withCompletion:^(NSError *error) {
                  // ...
              }];
      ```
    
     #### Android
      ```java
       CredentialApi.deleteCredential(credentialHandle).get();
      ```
    

2. Delete credential data from the application storage.

Cache data for Proof generation - Optional

The first time SDK generates Proof using a specific credential it fetches the credential's public Credential Definition and Schema from the Ledger. These operations take some time that increases the overall time taken to present proof to the remote side. In order to decrease that time your application can fetch and cache these public entities right after receiving a credential. Furthermore, it makes the Proof presentation independent of the Ledger connectivity as well.

Steps

Assume you received Credential.

  1. Assume that you just received and stored Credential, and the state of the Credential object is 4.

  2. Fetch public Credential Definition and Schema associated with stored in the wallet credentials from the Ledger.

NOTE: This function checks that data fetched and cached for all stored in the Wallet credentials

NOTE: The recommended way is to call it in a separate thread as it may take several seconds.

iOS

```objC
[appDelegate.sdkApi fetchPublicEntities:^(NSError *error, NSString *state)) {
            // ...
        }];
```

Android

```java
UtilsApi.vcxFetchPublicEntities().get();
```

Credential with attachments

Credentials with attachments can be issued and attachments can be shown in client application.

For example, attachments can be represented as base64 encoded strings, please refer to Credentials with attachments example.

NOTE: base64 encoded strings is just a representation of attachment, any other ways are valid and up to your system architecture.

Next Step

Now your application is able to receive and store verifiable credentials. You are ready to read how to fill proof requests using credentials in your wallet.