Skip to main content

Working with Credentials

warning

This feature is currently in the experimental stage of development. Do not use it in production environments or presume it is secure. Expect breaking changes.

The credential operations below meet the specifications defined in W3C VC Data Model.

What is a Credential?

From W3C:

Credentials are a part of our daily lives; driver's licenses are used to assert that we are capable of operating a motor vehicle, university degrees can be used to assert our level of education, and government-issued passports enable us to travel between countries. These credentials provide benefits to us when used in the physical world, but their use on the Web continues to be elusive.

- Source

What is a Verifiable Credential?

From W3C:

A verifiable credential (VC) can represent all of the same information that a physical credential represents. The addition of technologies, such as digital signatures, makes verifiable credentials more tamper-evident and more trustworthy than their physical counterparts.

- Source

MDIP Verifiable Credential Basic Workflow

The basic workflow involves three actors: Alice (the Issuer), Bob (the Holder), and Carol (the Verifier). In this scenario, Bob wishes to gain access to some resource controlled by Carol. Carol will grant Bob access only if Bob can prove that he owns a particular credential issued by Alice.

Steps to Create a VC

  1. The Issuer (Alice) creates a Credential. The Credential is like a type or a class; it describes the Credential, and specifies a schema. Each Verified Credential is an instance of a Credential.
  2. The Issuer binds a Credential to a Holder
  3. The Issuer issues a Credential, creating a Verifiable Credential (VC), by signing and encrypting a Bound Credential.
  4. The Holder (Bob) accepts the VC (adding it to their wallet for future use).
  5. The Verifier (Carol) creates a Challenge. A Challenge is a list of Credentials and trusted Issuers.
  6. The Holder creates a Response to the Challenge. A Response contains a list of Verified Presentations that correspond to the Credentials and trusted Issuers listed in the Challenge. If the User's wallet contains the right Verified Credentials, then it will be possible to create a valid Response to the Challenge. The Response is encrypted for the Verifier.
  7. The Verifier validates the Response. The Response is verified by checking that it contains a Verified Presentation for every Credential in the Challenge, that the VP is issued by a trusted Issuer, and that the VC corresponding the VP has not been revoked. If everything checks out the Response is accepted and the Holder is granted authorization.

Preparing or Selecting a Credential Schema File

JSON Schemas are ubiquitous. The schema defines the content of a future credential. Standardized schemas (ex: schema.org) for common credentials (ex: address, membership, etc) should be used to facilitate data interoperability.

$ cat data/schema/social-media.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"service": {
"type": "string"
},
"account": {
"type": "string",
"format": "uri"
}
},
"required": [
"service",
"account"
]
}

Creating a Credential DID

MDIP-compatible credentials are created using a JSON schema file as a template. The schema file will be registered with a Gatekeeper to create the Credential and receive its associated DID.

$ kc create-credential data/schema/social-media.json social-media
did:mdip:test:z3v8AuaeAPf9JMuyYZ1D79D626uUzDQmRPwq4d8oB1Th6ztzAS7
$ kc list-names
{
"social-media": "did:mdip:test:z3v8AuaeAPf9JMuyYZ1D79D626uUzDQmRPwq4d8oB1Th6ztzAS7"
}
$ kc resolve-did social-media
{
"@context": "https://w3id.org/did-resolution/v1",
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1"
],
"id": "did:mdip:test:z3v8AuaeAPf9JMuyYZ1D79D626uUzDQmRPwq4d8oB1Th6ztzAS7",
"controller": "did:mdip:test:z3v8AuabRm9DaiakqbwFPgsLd6vSYBQtdj7poQFGYBgsZCfqTvY"
},
"didDocumentMetadata": {
"created": "2024-03-22T15:00:31.047Z"
},
"didDocumentData": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"account": {
"format": "uri",
"type": "string"
},
"service": {
"type": "string"
}
},
"required": [
"service",
"account"
],
"type": "object"
},
"mdip": {
"registry": "hyperswarm",
"type": "asset",
"version": 1
}
}

The command above created a DID document with the schema file provided. For convenience, the user's wallet now contains a named alias (social-media) to the new credential's DID.

Binding the Credential

The Credential DID must now be bound to the Agent DID who is to become the Subject of the new credential. The binding process will generate a credential in JSON form that will be pre-populated with the DIDs of subject, issuer and credential type.

In the command below, both social-media and Bob are resolved to their respective DIDs using the named alias and identity names from the user's private wallet:

$ kc bind-credential social-media Bob
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"type": [
"VerifiableCredential",
"did:mdip:test:z3v8AuaeAPf9JMuyYZ1D79D626uUzDQmRPwq4d8oB1Th6ztzAS7"
],
"issuer": "did:mdip:test:z3v8AuabRm9DaiakqbwFPgsLd6vSYBQtdj7poQFGYBgsZCfqTvY",
"validFrom": "2024-03-22T15:04:33.684Z",
"validUntil": null,
"credentialSubject": {
"id": "did:mdip:test:z3v8AuairhLoGZqf6UDKw7zXyBknTvanvSzFHnLpwy8nwa7WLzk"
},
"credential": {
"account": "http://yNtjneCOyzLGUNtiAK.wnarGe6zodO-cGG47CGWl66-kvLbKVHCrFQPFy-ihIYfNlEuc",
"service": "in sit aliquip"
}
}

This JSON Bound Credential does not yet contain user-specific information other than the DID. The binding process pre-filled the required fields (account and service)with dummy data to be replaced in next step.

Editing the Credential

The bound credential must be populated with holder-specific information. This step will typically be automated in most deployments. In the case of our social media schema, we must populate a service field with the name of an online social media provider, and we must populate the account field with a URL to the holder's specific social media account.

$ kc bind-credential social-media Bob > bob-twitter.json
(output sent to the bob-twitter.json file)

Edit the bob-twitter.json file to populate the credential.account and credential.service fields with information that is pertinent with the subject of the credential:

$ cat bob-twitter.json
{
"@context": [
"`https://`www.`w3.org`/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"type": [
"VerifiableCredential",
"did:mdip:test:z3v8AuaeAPf9JMuyYZ1D79D626uUzDQmRPwq4d8oB1Th6ztzAS7"
],
"issuer": "did:mdip:test:z3v8AuabRm9DaiakqbwFPgsLd6vSYBQtdj7poQFGYBgsZCfqTvY",
"validFrom": "2024-03-22T15:06:24.773Z",
"validUntil": null,
"credentialSubject": {
"id": "did:mdip:test:z3v8AuairhLoGZqf6UDKw7zXyBknTvanvSzFHnLpwy8nwa7WLzk"
},
"credential": {
"account": "https://twitter.com/bob",
"service": "twitter.com"
}
}

Attesting a credential

The credential, bound and populated with the subject's information, must now be signed by the issuer and encrypted to the subject's keys:

$ kc issue-credential bob-twitter.json
did:mdip:test:z3v8AuaZAWJuERtD5CwDu2mNpLHjJ6imdNGTwdZpfKY6FK5ASk2

The issuer (Alice) should now send the VC's DID to the subject (Bob).

Verifying a credential

Only the issuer and holder of a VC can verify it since it is encrypted. When Bob receives the credential from Alice, he can view its contents before accepting it:

$ kc decrypt-json did:mdip:test:z3v8AuaZAWJuERtD5CwDu2mNpLHjJ6imdNGTwdZpfKY6FK5ASk2
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"type": [
"VerifiableCredential",
"did:mdip:test:z3v8AuaeAPf9JMuyYZ1D79D626uUzDQmRPwq4d8oB1Th6ztzAS7"
],
"issuer": "did:mdip:test:z3v8AuabRm9DaiakqbwFPgsLd6vSYBQtdj7poQFGYBgsZCfqTvY",
"validFrom": "2024-03-22T15:06:24.773Z",
"validUntil": null,
"credentialSubject": {
"id": "did:mdip:test:z3v8AuairhLoGZqf6UDKw7zXyBknTvanvSzFHnLpwy8nwa7WLzk"
},
"credential": {
"account": "https://twitter.com/bob",
"service": "twitter.com"
},
"signature": {
"signer": "did:mdip:test:z3v8AuabRm9DaiakqbwFPgsLd6vSYBQtdj7poQFGYBgsZCfqTvY",
"signed": "2024-03-22T15:09:02.994Z",
"hash": "62f7cb1a31d338d29287f9ce91b4da103391dca88b853ea1b05920c6049ae8ff",
"value": "37941a42492a431ceaff91c86de55eb0cd3ed98107a3ce19a76d88511b7fe2bc6fcf298c69e431b048ab0786e9624b647e4d03a4c26031c4c6e2b6882223defe"
}
}

Accepting a credential

Accepting a credential adds the DID to the user's local wallet:

$ kc accept-credential did:mdip:test:z3v8AuaZAWJuERtD5CwDu2mNpLHjJ6imdNGTwdZpfKY6FK5ASk2
OK saved
$ kc show-wallet
{
"seed": {
"mnemonic": "MLPxAgU1ym_v_YR2Q6-nY47L8xxMqbJqG_NzRNBh3_MHcZ4QQA2x3DI4fSAG2g-XHC3M_EGtmqY6NhVpsC9yKysFYQmcqjm7cAknpJajZYCVlVs7hJPRLdOqkpy4eotTVblgZdYsYtcgbU9kmYc",
"hdkey": {
"xpriv": "xprv9s21ZrQH143K2x2kGfQ7tgaVHZYQkQVQKbuHgQ4wG7qjfsBoMQD35Ly6rupdEDED1ZBWKtRGWnjwcf9Wxbyvwn4idCPe1kayCrBoLAp8Hvb",
"xpub": "xpub661MyMwAqRbcFS7DNgw8FpXDqbNu9sDFgpptUnUYpTNiYfWwtwXHd9HaiD1pEfLtMGVBKpCR9D6Vtriqkv7co4W72stnzpLdxPRmuLWJUHS"
}
},
"counter": 3,
"ids": {
"Alice": {
"did": "did:mdip:test:z3v8AuabRm9DaiakqbwFPgsLd6vSYBQtdj7poQFGYBgsZCfqTvY",
"account": 0,
"index": 1,
"owned": [
"did:mdip:test:z3v8AuaeAPf9JMuyYZ1D79D626uUzDQmRPwq4d8oB1Th6ztzAS7",
"did:mdip:test:z3v8AuaZAWJuERtD5CwDu2mNpLHjJ6imdNGTwdZpfKY6FK5ASk2"
]
},
"Bob": {
"did": "did:mdip:test:z3v8AuairhLoGZqf6UDKw7zXyBknTvanvSzFHnLpwy8nwa7WLzk",
"account": 2,
"index": 0,
"held": [
"did:mdip:test:z3v8AuaZAWJuERtD5CwDu2mNpLHjJ6imdNGTwdZpfKY6FK5ASk2"
]
}
},
"current": "Bob",
"names": {
"social-media": "did:mdip:test:z3v8AuaeAPf9JMuyYZ1D79D626uUzDQmRPwq4d8oB1Th6ztzAS7"
}
}

Revoking a credential

The issuer of a credential can revoke their credential at any time. This will blank out the VC's credential content data and set the didDocumentMetadata.deactivated property to true.

$ kc revoke-credential did:mdip:test:z3v8AuaZAWJuERtD5CwDu2mNpLHjJ6imdNGTwdZpfKY6FK5ASk2
OK revoked
$ kc resolve-did did:mdip:test:z3v8AuaZAWJuERtD5CwDu2mNpLHjJ6imdNGTwdZpfKY6FK5ASk2
{
"@context": "https://w3id.org/did-resolution/v1",
"didDocument": {},
"didDocumentMetadata": {
"created": "2024-03-22T15:09:03.056Z",
"deactivated": true,
"updated": "2024-03-22T15:17:53.368Z"
},
"didDocumentData": {},
"mdip": {
"registry": "hyperswarm",
"type": "asset",
"version": 1
}
}