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:
- Responding to Credential Offers
- Deleting Credentials
- Cache data for Proof generation
- Credential with attachments
Aries Credential Issuance protocol consists of several messages exchange:
- Issuer sends
Credential Offer
message to Holder - Holder handles
Credential Offer
message and sendsCredential Request
message to Issuer - Issuer handles
Credential Request
message and sendsCredential
message to Holder - Holder handles
Credential Request
message and sendsCredential Ack
message (if requested) to Issuer
In order to handle a Credential Offer
a Holder (client) need to take the following steps:
- Download and Parse Credential Offer message received from the Pairwise Cloud Agent.
- 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. - 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 - 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
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.
-
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 ofdecryptedPayload
field).{ "@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 takepairwiseDID
value from the downloaded message.
-
Create Credential state object
[appDelegate.sdkApi credentialCreateWithOffer: sourceId offer: message completion:^(NSError *error, NSInteger credentialHandle) { // ... }];
int credentialHandle = CredentialApi.credentialCreateWithOffer(sourceId, message).get();
sourceId
- any string
message
- message downloaded on step 1. -
Serialize Credential state object
[appDelegate.sdkApi credentialSerialize: credentialHandle completion:^(NSError *error, NSString *state) { // ... }];
String serializedCredential = CredentialApi.credentialSerialize(credentialHandle).get();
-
Save
serialized
sdk credential state object into your application connection object. -
The
status
of the credential is considered aspending
at this step. -
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).
-
Update status of correspondent message on the Agent. See messages documentation for message update information.
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.
[appDelegate.sdkApi connectionDeserialize:serializedConnection
completion:^(NSError *error, NSInteger connectionHandle) {
// ...
}];
int connectionHandle = ConnectionApi.connectionDeserialize(serializedConnection).get();
[appDelegate.sdkApi credentialDeserialize:serializedCredential
completion:^(NSError *error, NSInteger credentialHandle) {
// ...
}];
int credOfferHandle = CredentialApi.credentialDeserialize(serializedCredOffer).get();
-
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) { // ... }];
CredentialApi.credentialSendRequest(credOfferHandle, connectionHandle, 0).get()
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).
-
Serialize Credential state object
[appDelegate.sdkApi credentialSerialize: credentialHandle completion:^(NSError *error, NSString *state) { // ... }];
String serializedCredential = CredentialApi.credentialSerialize(credentialHandle).get();
-
Update
serialized
value from the corresponding record stored in the application storage.
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:
-
Polling - call
credentialUpdateState
function in loop until returned state is not equal4
(Accepted
).-
Call following code in a loop until the returned state is not equal
4
(Accepted
).while(1) { [appDelegate.sdkApi credentialUpdateState:(NSInteger) credentialHandle message:(NSString *) message completion:^(NSError *error, NSInteger state)) { if (state == 4){ break; } }]; }
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.
-
-
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 withissue-credential
- value of
["decryptedPayload"]["~thread"]["thid"]
field must match to the value of@id
field from Credential Offer.
- value of
-
Update Credential state object with received
Credential
message:[appDelegate.sdkApi credentialUpdateStateWithMessage:connectionHandle message:message withCompletion:^(NSError *error, NSInteger state) { // .... }
int state = CredentialApi.credentialUpdateStateWithMessage(connectionHandle, message).get();
-
Update status of the message as read. See messages documentation for message update information.
[appDelegate.sdkApi updateMessages:messageStatus pwdidsJson:handledMessage completion:^(NSError *error) { // ... }];
UtilsApi.vcxUpdateMessages(messageStatus, handledMessage).get()
-
-
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.
[appDelegate.sdkApi credentialSerialize:credentialHandle completion:^(NSError *error, NSString *state)) { // ... }];
String serializedCredential = CredentialApi.credentialSerialize(credentialHandle).get();
-
The
status
of the credential is considered asissued
at this step. -
You also can save the
timestamp
of credential receiving. -
Update a related record in the storage with the latest value.
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).
#### iOS
```objC
[appDelegate.sdkApi connectionDeserialize:serializedConnection
completion:^(NSError *error, NSInteger connectionHandle) {
// ...
}];
```
#### Android
```java
int connectionHandle = ConnectionApi.connectionDeserialize(serializedConnection).get();
```
#### iOS
```objC
[appDelegate.sdkApi credentialDeserialize:serializedCredential
completion:^(NSError *error, NSInteger credentialHandle) {
// ...
}];
```
#### Android
```java
int credentialHandle = CredentialApi.credentialDeserialize(serializedCredOffer).get();
```
#### iOS
```objc
[appDelegate.sdkApi credentialReject:credentialHandle
connectionHandle:connectionHandle
comment:@"Rejection comment"
completion:^(NSError *error) {
// ...
}];
```
#### Android
```java
CredentialApi.credentialReject(credOfferHandle, connectionHandle, "Rejection comment").get()
```
```objC
[appDelegate.sdkApi credentialSerialize:credentialHandle
completion:^(NSError *error, NSString *state)) {
// ...
}];
```
```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.
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.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(); ```
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.
Assume you received Credential.
-
Assume that you just received and stored Credential, and the state of the Credential object is 4.
-
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.
```objC
[appDelegate.sdkApi fetchPublicEntities:^(NSError *error, NSString *state)) {
// ...
}];
```
```java
UtilsApi.vcxFetchPublicEntities().get();
```
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.
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.