Skip to main content

Create a Verifiable Credential

A [verifiable credential (VC)](/shimmer/ can represent all information that a physical credential represents, such as a passport or university degree. However, by allowing other parties to cryptographically verify the authorship and integrity of the claims, verifiable credentials can be seen as more tamper-evident and more trustworthy than their physical counterparts.

In the IOTA Identity Framework you can create a Verifiable Credential with the following properties:

  • Context: list of JSON-LD context URIs. Includes "" by default.
  • Types: list of types describing the credential. Includes "VerifiableCredential" by default.
  • Subject: the claims of the issuer; a set of objects that contain one or more properties that are each related to a subject.
  • Issuer: the identifier of the issuer, typically their DID.
  • ID: optional URI identifier for the credential.
  • Issuance Date: optional timestamp for expressing the date and time when a credential becomes valid.
  • Expiration Date: optional timestamp for expressing the date and time when a credential ceases to be valid.
  • Status: optional information used to determine the current status of a credential, i.e. whether or not it has been revoked.
  • Schema: optional list of objects specifying the schema that the data must conform to.
  • Refresh Service: optional link to a service where the recipient may refresh the included credentials.
  • Terms of Use: optional list of policies defining obligations, prohibitions, or permissions of the presentation recipient.
  • Evidence: optional list of objects that can be used by the issuer to provide the verifier with additional supporting information in a verifiable credential.
  • Non-Transferable: optional flag that indicates that a verifiable credential must only be encapsulated in a verifiable presentation whose proof was issued by the credential subject.


After creation, the issuer signs the verifiable credential using one of their private keys, embedding the digital signature in its proof section. This is what allows verifiers to independently validate the credential using the corresponding public key from the issuer's DID Document.

Proof Options

A digital signature on a verifiable credential both provides data integrity and proves the DID of the issuer. The proof section embedded in a credential may also include additional metadata.

The following metadata properties can be configured by the framework and are optional and omitted by default:

  • Created: timestamp of when the credential was signed, recommended.
  • Expires: timestamp after which the signature is no longer considered valid. Implementers should prefer to set the dedicated Expiration Date property on credentials instead.
  • Proof Purpose: indicates the purpose of the signature.
    • AssertionMethod: to assert a claim. The signing verification method must have an assertionMethod relationship to be valid.
    • Authentication: to authenticate the signer. The signing verification method must have an authentication relationship to be valid.

Most verifiable credentials should be signed with the assertion method proof purpose to clearly indicate that the signature is asserting a claim and restrict it to valid verification methods. Whereas a proof may be attached to a verifiable presentation for authentication purposes.

Other metadata fields such as challenge and domain may be included, however they are more pertinent for verifiable presentations.


Verifiers should ensure certain properties of a credential are valid when receiving one or more in a verifiable presentation. Both issuers and holders may also wish to validate their credentials, particularly directly after creating or receiving one. Validation may be performed at any point in time and can be a useful way of checking whether a credential has expired or been revoked.

The IOTA Identity Framework supports the following checks during credential validation:

  • Semantic structure: ensures the credential adheres to the specification.
  • Proof: verifies the signature against the DID Document of the issuer.
  • Optional validations: additional checks on credential properties and the signature can be configured by specifying Validation Options.

Validation Options

These options specify conditions that specific properties in a credential must satisfy.

  • Expiry Date: check that the expirationDate property, if present, is not before a specific datetime. Defaults to the current datetime if unset.
  • Issuance Date: check that that issuanceDate property, if present, is not after a specific datetime. Defaults to the current datetime if unset.
  • Verifier Options: validates aspects of the credential signature and its metadata, see Proof Options.

Sharing Verifiable Credentials

A verifiable presentation is the recommended data format for sharing one or more verifiable credentials, as it provides cryptographic means of proving the DID of the holder presenting them, and for enforcing subject-holder relationships. See the Verifiable Presentations page for further detail.


The following code exemplifies how an issuer can create, sign, and validate a verifiable credential. In this example, the issuer signs a UniversityDegreeCredential with Alice's name and DID. This Verifiable Credential can be verified by anyone, allowing Alice to take control of it and share it with anyone.

// Copyright 2020-2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { Client, MnemonicSecretManager } from "@iota/client-wasm/node";
import { Bip39 } from "@iota/crypto.js";
import {
} from "@iota/identity-wasm/node";
import { API_ENDPOINT, createDid } from "../util";

* This example shows how to create a Verifiable Credential and validate it.
* In this example, Alice takes the role of the subject, while we also have an issuer.
* The issuer signs a UniversityDegreeCredential type verifiable credential with Alice's name and DID.
* This Verifiable Credential can be verified by anyone, allowing Alice to take control of it and share it with whomever they please.
export async function createVC() {
const client = new Client({
primaryNode: API_ENDPOINT,
localPow: true,

// Generate a random mnemonic for our wallet.
const secretManager: MnemonicSecretManager = {
mnemonic: Bip39.randomMnemonic(),

// Create an identity for the issuer with one verification method `key-1`.
const { document: issuerDocument, keypair: keypairIssuer } = await createDid(client, secretManager);

// Create an identity for the holder, in this case also the subject.
const { document: aliceDocument } = await createDid(client, secretManager);

// Create a credential subject indicating the degree earned by Alice, linked to their DID.
const subject = {
name: "Alice",
degreeName: "Bachelor of Science and Arts",
degreeType: "BachelorDegree",
GPA: "4.0",

// Create an unsigned `UniversityDegree` credential for Alice
const unsignedVc = new Credential({
id: "",
type: "UniversityDegreeCredential",
credentialSubject: subject,

// Sign Credential.
let signedVc = issuerDocument.signCredential(unsignedVc, keypairIssuer.private(), "#key-1", ProofOptions.default());

// Before sending this credential to the holder the issuer wants to validate that some properties
// of the credential satisfy their expectations.

// Validate the credential's signature, the credential's semantic structure,
// check that the issuance date is not in the future and that the expiration date is not in the past.
CredentialValidator.validate(signedVc, issuerDocument, CredentialValidationOptions.default(), FailFast.AllErrors);

// Since `validate` did not throw any errors we know that the credential was successfully validated.
console.log(`VC successfully validated`);

// The issuer is now sure that the credential they are about to issue satisfies their expectations.
// The credential is then serialized to JSON and transmitted to the holder in a secure manner.
// Note that the credential is NOT published to the IOTA Tangle. It is sent and stored off-chain.
const credentialJSON = signedVc.toJSON();
console.log(`Issued credential: ${JSON.stringify(credentialJSON, null, 2)}`);