Skip to content

Walkthrough: Build a Vaccine Card

This walkthrough demonstrates how a vaccination card can be issued, held, and shared using Verifiable Credentials with Trinsic.

Meet Allison

We'll follow Allison as she obtains a vaccine certificate, stores it in her digital wallet, and presents it to board an airplane.

In most credential exchange scenarios, there are three primary roles: Issuer, Holder, and Verifier.

Holder: Stores credentials received from issuers, and presents them to verifiers. (Said credentials are often, but not always, attesting information about the holder)

Issuer: Signs and issues credentials which attest information about a credential subject.

Verifier: Verifies credentials presented by holders.

In this case, Allison will be the holder, a vaccination clinic will be the issuer, and an airline will be the verifier.

Our SDKs

You can follow along using one of our SDKs, or use the Trinsic CLI, which implements full platform functionality.

Click here for installation instructions for the Trinsic CLI.

Click here for installation instructions for the Node/Browser SDK.

Click here for installation instructions for the .NET SDK.

Click here for installation instructions for the Python SDK.

Click here for installation instructions for the Java SDK.

Click here for installation instructions for the Go SDK.


Ecosystem Setup

Before we begin, you'll need an ecosystem -- somewhere for the resources we're about to create (wallets, templates, credentials) to live.

Use Existing Ecosystem

If you've already signed up as a customer, you'll have received an email with an ecosystem ID and authentication token.

Copy this ecosystem ID down, and skip to the next step.

Create New Ecosystem

If you don't already have an ecosystem provisioned for you, you'll need to create one first.

This will be a sandbox ecosystem; suitable for prototyping and testing, but not production purposes. To receive a production ecosystem, sign up.

trinsic provider create-ecosystem
const ecosystem = await trinsic
    .provider()
    .createEcosystem(CreateEcosystemRequest.fromPartial({}));
const ecosystemId = ecosystem.ecosystem!.id;
var trinsic = new TrinsicService(_options);
var (ecosystem, _) = await trinsic.Provider.CreateEcosystemAsync(new());
var ecosystemId = ecosystem?.Id;
ecosystem = await trinsic_service.provider.create_ecosystem()
ecosystem_id = ecosystem.ecosystem.id
var ecosystemResponse =
    trinsic.provider().createEcosystem(CreateEcosystemRequest.getDefaultInstance()).get();

var ecosystemId = ecosystemResponse.getEcosystem().getId();
ecosystem, _ := trinsic.Provider().CreateEcosystem(context.Background(), nil)
ecosystemId := ecosystem.Ecosystem.Id

The response to this call contains the name and ID of your newly-created ecosystem; copy either of these down.

Further Reading: Ecosystems


Create Accounts

We need to create Trinsic accounts for the participants in this credential exchange. Accounts and wallets can be considered interchangeably; all accounts have exactly one associated wallet.

Accounts can be created with a single call; they're designed to minimize onboarding friction for your users.

The clinic's account will issue the credential, Allison's account will hold it, and the airline's account will verify its contents.

The CLI makes it easy to create wallets. For demo purposes, we'll create all three on the same machine.

When using the CLI, the authentication token of the most recently used account is saved in ~/.trinsic. In a real-world scenario, you should back this token up securely.

trinsic account login --ecosystem {ECOSYSTEM_ID}
# Save auth token in `allison.txt` before continuing

trinsic account login --ecosystem {ECOSYSTEM_ID}
# Save auth token in `airline.txt` before continuing

trinsic account login --ecosystem {ECOSYSTEM_ID}
# Save auth token in `clinic.txt` before continuing
// Create 3 different profiles for each participant in the scenario
const allison = await trinsic
    .wallet()
    .createWallet({ ecosystemId: ecosystemId });
const clinic = await trinsic
    .wallet()
    .createWallet({ ecosystemId: ecosystemId });
const airline = await trinsic
    .wallet()
    .createWallet({ ecosystemId: ecosystemId });

If you would like to save the account for future use, simply write the auth token to storage. Take care to store it in a secure location.

var allison = await trinsic.Wallet.CreateWalletAsync(new() { EcosystemId = ecosystemId! });
var clinic = await trinsic.Wallet.CreateWalletAsync(new() { EcosystemId = ecosystemId! });
var airline = await trinsic.Wallet.CreateWalletAsync(new() { EcosystemId = ecosystemId! });

If you would like to save an account for future use, simply write the auth token to storage. Take care to store it in a secure location.

# Create an account for each participant in the scenario
allison = await trinsic_service.wallet.create_wallet(
    request=CreateWalletRequest(ecosystem_id=ecosystem_id)
)
airline = await trinsic_service.wallet.create_wallet(
    request=CreateWalletRequest(ecosystem_id=ecosystem_id)
)
clinic = await trinsic_service.wallet.create_wallet(
    request=CreateWalletRequest(ecosystem_id=ecosystem_id)
)

If you would like to save an account for future use, simply write the auth token to storage. Take care to store it in a secure location.

// Create an account for each participant in the scenario
var allison =
    trinsic
        .wallet()
        .createWallet(CreateWalletRequest.newBuilder().setEcosystemId(ecosystemId).build())
        .get();
var clinic =
    trinsic
        .wallet()
        .createWallet(CreateWalletRequest.newBuilder().setEcosystemId(ecosystemId).build())
        .get();
var airline =
    trinsic
        .wallet()
        .createWallet(CreateWalletRequest.newBuilder().setEcosystemId(ecosystemId).build())
        .get();

If you would like to save an account for future use, simply write the auth token to storage. Take care to store it in a secure location.

// Create an account for each participant in the scenario
createWallet := &wallet.CreateWalletRequest{EcosystemId: ecosystemId}
allison, _ := trinsic.Wallet().CreateWallet(context.Background(), createWallet)
airline, _ := trinsic.Wallet().CreateWallet(context.Background(), createWallet)
clinic, _ := trinsic.Wallet().CreateWallet(context.Background(), createWallet)

If you would like to save an account for future use, simply write the auth token to storage. Take care to store it in a secure location.

Production Usage

In this example, we've created anonymous accounts; the only way to access them is by saving the authentication token generated on account creation.

In a production scenario, you may want to create accounts tied to a user's email address or phone number. This allows users to securely access their Trinsic cloud wallets at any time.

Note that accounts are tied to their ecosystem. If you create an account tied to [email protected] in the example1 ecosystem, it will not be visible in any other ecosystem. The same email address can be used to create accounts in multiple ecosystems.

Further Reading: Accounts and Wallets


Define a credential template

Before we can issue a credential, we need to create a Credential for it.

Credential templates are simply a list of the fields that a credential can have.

First, prepare a JSON file which describes your template:

{
    "firstName": {
        "type": "string",
        "description": "First name of vaccine recipient"
    },
    "lastName": {
        "type": "string",
        "description": "Last name of vaccine recipient"
    },
    "batchNumber":{
        "type": "string",
        "description": "Batch number of vaccine"
    },
    "countryOfVaccination":{
        "type": "string",
        "description": "Country in which the subject was vaccinated"
    }
}

Then create the credential template:

trinsic template create -n "VaccinationCertificate" --fields-file templateData.json

The output of this command will include a credential template ID; copy this down for later use.

//Define all fields
const firstNameField = TemplateField.fromPartial({
    description: "First name of vaccine recipient",
    type: FieldType.STRING,
});

const lastNameField = TemplateField.fromPartial({
    type: FieldType.STRING,
    description: "Last name of vaccine recipient",
});

const batchNumberField = TemplateField.fromPartial({
    type: FieldType.STRING,
    description: "Batch number of vaccine",
});

const countryOfVaccinationField = TemplateField.fromPartial({
    type: FieldType.STRING,
    description: "Country in which the subject was vaccinated",
});

//Create request
let request = CreateCredentialTemplateRequest.fromPartial({
    name: `VaccinationCertificate-${uuid()}`,
    fields: {
        firstName: firstNameField,
        lastName: lastNameField,
        batchNumber: batchNumberField,
        countryOfVaccination: countryOfVaccinationField,
    },
});

//Create template
const response = await trinsic.template().create(request);
const template = response.data;
// Set active profile to `clinic` so we can create a template
trinsic = new TrinsicService(_options.CloneWithAuthToken(clinic.AuthToken!));

// Prepare request to create template
CreateCredentialTemplateRequest templateRequest = new() {
    Name = "VaccinationCertificate",
    AllowAdditionalFields = false
};

templateRequest.Fields.Add("firstName", new() { Description = "First name of vaccine recipient" });
templateRequest.Fields.Add("lastName", new() { Description = "Last name of vaccine recipient" });
templateRequest.Fields.Add("batchNumber", new() { Description = "Batch number of vaccine", Type = FieldType.String });
templateRequest.Fields.Add("countryOfVaccination", new() { Description = "Country in which the subject was vaccinated" });

// Create template
var template = await trinsic.Template.CreateAsync(templateRequest);
var templateId = template?.Data?.Id;
template = await trinsic_service.template.create(
    request=CreateCredentialTemplateRequest(
        name=f"VaccinationCertificate-{uuid.uuid4()}",
        allow_additional_fields=False,
        fields={
            "firstName": TemplateField(
                description="First name of vaccine recipient"
            ),
            "lastName": TemplateField(description="Last name of vaccine recipient"),
            "batchNumber": TemplateField(
                description="Batch number of vaccine", type=FieldType.STRING
            ),
            "countryOfVaccination": TemplateField(
                description="Country in which the subject was vaccinated"
            ),
        },
    )
)

template_id = template.data.id
// Set active profile to 'clinic'
templateService.setAuthToken(clinic);

// Define fields for template
var fields = new HashMap<String, TemplateField>();
fields.put(
    "firstName",
    TemplateField.newBuilder().setDescription("First name of vaccine recipient").build());
fields.put(
    "lastName",
    TemplateField.newBuilder().setDescription("Last name of vaccine recipient").build());
fields.put(
    "batchNumber",
    TemplateField.newBuilder()
        .setType(FieldType.STRING)
        .setDescription("Batch number of vaccine")
        .build());
fields.put(
    "countryOfVaccination",
    TemplateField.newBuilder()
        .setDescription("Country in which the subject was vaccinated")
        .build());

// Create template request
var templateRequest =
    CreateCredentialTemplateRequest.newBuilder()
        .setName("VaccinationCertificate")
        .setAllowAdditionalFields(false)
        .putAllFields(fields)
        .build();

// Execute template creation
var template = templateService.create(templateRequest).get();
var templateId = template.getData().getId();
templateRequest := &template.CreateCredentialTemplateRequest{Name: "VaccinationCertificate", AllowAdditionalFields: false, Fields: make(map[string]*template.TemplateField)}
templateRequest.Fields["firstName"] = &template.TemplateField{Description: "First name of vaccine recipient"}
templateRequest.Fields["lastName"] = &template.TemplateField{Description: "Last name of vaccine recipient"}
templateRequest.Fields["batchNumber"] = &template.TemplateField{Description: "Batch number of vaccine", Type: template.FieldType_STRING}
templateRequest.Fields["countryOfVaccination"] = &template.TemplateField{Description: "Country in which the subject was vaccinated"}

createdTemplate, _ := trinsic.Template().Create(context.Background(), templateRequest)

templateId := createdTemplate.Data.Id

Further Reading: Credential Templates


Issue a Credential

Upon receiving her vaccine, the clinic issues Allison a Verifiable Credential, which proves that she was given the vaccine by the clinic.

A credential is a JSON document that has been cryptographically signed; this signature enables verifiers to trust that the data comes a trusted source, and has not been tampered with.

To issue a vaccine certificate, we'll use the credential template we created in the last step.

First, prepare a file named values.json with the following content:

{
    "firstName": "Allison",
    "lastName": "Allisonne",
    "batchNumber": "123454321",
    "countryOfVaccination": "US"
}

Then issue the credential:

trinsic config --auth-token $(cat clinic.txt)
trinsic vc issue-from-template --template-id {TEMPLATE_ID} --values-file values.json --out credential.json

The output of this command will contain a signed JSON document, which has been saved to credential.json.

Note that TEMPLATE_ID refers to the "Schema" URI of the credential template you created earlier called "VaccinationCertificate". More specifically, it's the property 'schema_uri' in the JSON returned by the trinsic template create... command.

// Prepare the credential values JSON document
const credentialValues = JSON.stringify({
    firstName: "Allison",
    lastName: "Allisonne",
    batchNumber: "123454321",
    countryOfVaccination: "US",
});

// Sign a credential as the clinic and send it to Allison
trinsic.options.authToken = clinic.authToken;
const issueResponse = await trinsic.credential().issueFromTemplate(
    IssueFromTemplateRequest.fromPartial({
        templateId: template.id,
        valuesJson: credentialValues,
    }),
);
// Prepare credential values
var credentialValues = new Dictionary<string, string> {
    { "firstName", "Allison" },
    { "lastName", "Allisonne" },
    { "batchNumber", "123454321" },
    { "countryOfVaccination", "US" }
};

// Issue credential as clinic
var issueResponse = await trinsic.Credential.IssueFromTemplateAsync(new() {
    TemplateId = templateId,
    ValuesJson = JsonSerializer.Serialize(credentialValues)
});

var signedCredential = issueResponse?.DocumentJson;
# Prepare values for credential
values = json.dumps(
    {
        "firstName": "Allison",
        "lastName": "Allisonne",
        "batchNumber": "123454321",
        "countryOfVaccination": "US",
    }
)

# Issue credential
issue_response = await trinsic_service.credential.issue_from_template(
    request=IssueFromTemplateRequest(template_id=template.id, values_json=values)
)

credential = issue_response.document_json
// Set active profile to 'clinic' so we can issue credential signed
// with the clinic's signing keys
trinsic.setAuthToken(clinic);

// Prepare credential values
var valuesMap = new HashMap<String, Object>();
valuesMap.put("firstName", "Allison");
valuesMap.put("lastName", "Allissonne");
valuesMap.put("batchNumber", "123454321");
valuesMap.put("countryOfVaccination", "US");

// Serialize values to JSON
var valuesJson = new Gson().toJson(valuesMap);

// Issue credential
var issueResponse =
    trinsic
        .credential()
        .issueFromTemplate(
            IssueFromTemplateRequest.newBuilder()
                .setTemplateId(templateId)
                .setValuesJson(valuesJson)
                .build())
        .get();

var credential = issueResponse.getDocumentJson();
// Prepare values for credential
valuesStruct := struct {
    FirstName            string
    LastName             string
    batchNumber          string
    countryOfVaccination string
}{
    FirstName:            "Allison",
    LastName:             "Allisonne",
    batchNumber:          "123454321",
    countryOfVaccination: "US",
}
values, _ := json.Marshal(valuesStruct)

// Issue credential
issueResponse, _ := trinsic.Credential().IssueFromTemplate(context.Background(), &credential.IssueFromTemplateRequest{
    TemplateId: createdTemplate.Id,
    ValuesJson: string(values),
})

issuedCredential := issueResponse.DocumentJson

Further Reading: Issuance and Credentials


Send Credential to Allison

Now that the clinic has a signed credential, it must be securely transmitted to Allison, so she can store it in her wallet.

Because it's just a JSON string, it could be delivered in many ways -- for example, in the response to an HTTPS request which triggered the issuance process.

Send via Trinsic

Trinsic also offers the ability to send a credential directly to a Trinsic user's wallet.

Click here to learn more about this feature.


Store Credential in Wallet

Once Allison receives the credential, it must be stored in her wallet.

trinsic config --auth-token $(cat allison.txt)
trinsic wallet insert-item --item credential.json
// Allison stores the credential in her cloud wallet.
trinsic.options.authToken = allison.authToken;
const insertResponse = await trinsic.wallet().insertItem(
    InsertItemRequest.fromPartial({
        itemJson: issueResponse.documentJson,
    }),
);
// Set active profile to 'allison' so we can manage her cloud wallet
trinsic = new TrinsicService(_options.CloneWithAuthToken(allison.AuthToken!));

// Insert credential into Allison's wallet
var insertItemResponse = await trinsic.Wallet.InsertItemAsync(new() {
    ItemJson = signedCredential
});

var itemId = insertItemResponse?.ItemId;
# Allison stores the credential in her cloud wallet
trinsic_service.service_options.auth_token = allison.auth_token

insert_response = await trinsic_service.wallet.insert_item(
    request=InsertItemRequest(item_json=credential)
)

item_id = insert_response.item_id
// Set active profile to 'allison' so we can manage her cloud wallet
// setAuthToken() {
trinsic.setAuthToken(allison.getAuthToken());
// }

// Allison stores the credential in her cloud wallet.
var insertItemResponse =
    trinsic
        .wallet()
        .insertItem(InsertItemRequest.newBuilder().setItemJson(credential).build())
        .get();

final var itemId = insertItemResponse.getItemId();
// Allison stores the credential in her cloud wallet
trinsic.SetAuthToken(allison.AuthToken)
insertResponse, _ := trinsic.Wallet().InsertItem(context.Background(), &wallet.InsertItemRequest{ItemJson: issuedCredential})

itemId := insertResponse.ItemId

The response to this call contains an Item ID; copy this down.

Further Reading: Wallets


Create a Proof of Vaccination

Before boarding, the airline requests proof of vaccination from Allison. Specifically, they want to see proof that she holds a VaccinationCertificate credential.

Let's use the CreateProof call to build a proof for Allison's held credential.

trinsic config --auth-token $(cat allison.txt)
trinsic vc create-proof --item-id "{ITEM_ID}" --out proof.json
// Allison shares the credential with the venue.
trinsic.options.authToken = allison.authToken;
const proofResponse = await trinsic.credential().createProof(
    CreateProofRequest.fromPartial({
        itemId: insertResponse.itemId,
    }),
);
// Build a proof for the signed credential as allison
var proofResponse = await trinsic.Credential.CreateProofAsync(new() {
    ItemId = itemId
});

var proofJson = proofResponse?.ProofDocumentJson;
# Allison shares the credential with the airline
trinsic_service.service_options.auth_token = allison.auth_token

proof_response = await trinsic_service.credential.create_proof(
    request=CreateProofRequest(item_id=item_id)
)

credential_proof = proof_response.proof_document_json
// Set active profile to 'allison' so we can create a proof using her key
trinsic.setAuthToken(allison.getAuthToken());

// Allison shares the credential with the venue
var createProofResponse =
    trinsic
        .credential()
        .createProof(CreateProofRequest.newBuilder().setItemId(itemId).build())
        .get();

var credentialProof = createProofResponse.getProofDocumentJson();
// Allison shares the credential with the airline
trinsic.SetAuthToken(allison.AuthToken)
proofResponse, _ := trinsic.Credential().CreateProof(context.Background(), &credential.CreateProofRequest{
    Proof: &credential.CreateProofRequest_ItemId{ItemId: itemId},
})

credentialProof := proofResponse.ProofDocumentJson

Allison sends this proof to the airline for them to verify.

Partial Proofs

In this example, the proof is being created over the entire credential; all of its fields are revealed to the verifier.

It is possible for the airline to send Allison a frame which requests only certain fields of the credential. The airline would not be able to see other fields of the credential, but cryptographic guarantees would still hold over the revealed fields.

See the CreateProof reference for more information.

OpenID Connect for Presentation

Trinsic offers an OpenID Connect service as an alternative flow for the exchange of a credential between a holder and a verifier.

In this flow, a holder simply clicks a link (or scans a QR code), logs into their Trinsic cloud wallet, and selects a credential to share.


Verify Proof

Once the airline receives the proof, they can use the VerifyProof call to ensure its authenticity.

trinsic config --auth-token $(cat airline.txt)
trinsic vc verify-proof --proof-document proof.json
// The airline verifies the credential
trinsic.options.authToken = airline.authToken;
const verifyResponse = await trinsic.credential().verifyProof(
    VerifyProofRequest.fromPartial({
        proofDocumentJson: proofResponse.proofDocumentJson,
    }),
);
// Set active profile to `airline`
trinsic = new TrinsicService(_options.CloneWithAuthToken(airline.AuthToken!));

// Verify that Allison has provided a valid proof
var verifyResponse = await trinsic.Credential.VerifyProofAsync(new() {
    ProofDocumentJson = proofJson
});

var credentialValid = verifyResponse?.IsValid ?? false;
# The airline verifies the credential
trinsic_service.service_options.auth_token = airline.auth_token

verify_result = await trinsic_service.credential.verify_proof(
    request=VerifyProofRequest(proof_document_json=credential_proof)
)

valid = verify_result.is_valid
trinsic.setAuthToken(airline.getAuthToken());

// Verify that Allison has provided a valid proof
var verifyProofResponse =
    trinsic
        .credential()
        .verifyProof(
            VerifyProofRequest.newBuilder().setProofDocumentJson(credentialProof).build())
        .get();

boolean isValid = verifyProofResponse.getIsValid();
// The airline verifies the credential
trinsic.SetAuthToken(airline.AuthToken)
verifyResult, _ := trinsic.Credential().VerifyProof(context.Background(), &credential.VerifyProofRequest{ProofDocumentJson: credentialProof})
valid := verifyResult.IsValid

Interoperability

The Verifiable Credentials and Proofs that Trinsic's platform produces are based on open standards.

Although we use the VerifyProof call in this example, the proof could be verified using any standards-compliant software.


Full Source Code

This sample is available as VaccineDemoShared.ts in our SDK repository.

This sample is available as VaccineWalkthroughTests.cs in our SDK repository.

This sample is available as vaccine_demo.py in our SDK repository.

This sample is available as VaccineDemo.java in our SDK repository.

This sample is available as vaccine_test.go in our SDK repository.


Trust Registry Setup

Before we begin, you'll need to prepare your trust registry. This defines who is an authorized issuer of your vaccine card.

Register Issuer

First, let's grab our account info. You can use an email address, walletId or PublicDID as identifiers for a wallet. We will use publicDID.

trinsic account info

The response should look like:

{
  ...
  "ecosystem_id": "urn:trinsic:ecosystems:<ecosystem-name>",
  "public_did": "did:web:xxxxxxxx......", // <public_did>
  "wallet_id": "urn:trinsic:wallets:xxxxxx....>"
}

Request to register a member as a valid issuer of a specific credential schema. Only one of did_uri, wallet_id, or email may be specified.
did_uri
string
DID URI of member to register
wallet_id
string
Trinsic Wallet ID of member to register
email
string
Email address of member to register. Must be associated with an existing Trinsic account.
schema_uri
string
URI of credential schema to register member as authorized issuer of
valid_from_utc
uint64
Unix Timestamp member is valid from. Member will not be considered valid before this timestamp.
valid_until_utc
uint64
Unix Timestamp member is valid until. Member will not be considered valid after this timestamp.

Response to RegisterMemberRequest
This message has no fields


Registers an authorized issuer for a specific credential type (identified by its schema_uri), using the public_did, framework_id and template_uri from above:

trinsic trust-registry register-member \
    --framework-id <framework_id> \
    --schema <template_uri> \
    --did <public_did>

Request to register a member as a valid issuer of a specific credential schema. Only one of did_uri, wallet_id, or email may be specified.
did_uri
string
DID URI of member to register
wallet_id
string
Trinsic Wallet ID of member to register
email
string
Email address of member to register. Must be associated with an existing Trinsic account.
schema_uri
string
URI of credential schema to register member as authorized issuer of
valid_from_utc
uint64
Unix Timestamp member is valid from. Member will not be considered valid before this timestamp.
valid_until_utc
uint64
Unix Timestamp member is valid until. Member will not be considered valid after this timestamp.

Response to RegisterMemberRequest
This message has no fields


Check Issuer Status

Check the status of an issuer for a specific credential type using the public_did, framework_uri and template_uri from above:

trinsic trust-registry get-membership-status \
    --framework-id <framework_id> \
    --schema <template_uri> \
    --did <public_did>

The response should look like:

ok

Request to fetch member status in Trust Registry for a specific credential schema.
did_uri
string
DID URI of member
schema_uri
string
URI of credential schema associated with member

Response to GetMemberAuthorizationStatusRequest
status
Status of member for given credential schema
Show enum values


Issue a Credential with Trust Registry

We need to prepare a credential with a Trust Registry specified. This will consist of:

  1. Issuing the credential with Trust Registry enabled
  2. Inserting the credential into your wallet
  3. Deriving a proof of the credential

First, prepare a file named values.json with the following content:

{
    "firstName": "Allison",
    "lastName": "Allisonne",
    "batchNumber": "123454321",
    "countryOfVaccination": "US"
}

Then issue the credential:

trinsic vc issue-from-template --template-id <template_id> --values-file values.json --out credential.json
trinsic wallet insert-item --item credential.json

The response should look like:

ok
item id  "urn:uuid:..." // <item_id>

trinsic vc create-proof --item-id <item_id> --out proof.json

Verify a proof with Trust Registry status

Now we can verify the proof from the previous step, and get the Trust Registry status.

trinsic vc verify-proof --proof-document proof.json

The response should look like:

is valid  "true"
validation results  {
  "CredentialStatus": {
    "is_valid": true,
    "messages": []
  },
  "IssuerIsSigner": {
    "is_valid": true,
    "messages": []
  },
  "SchemaConformance": {
    "is_valid": true,
    "messages": []
  },
  "SignatureVerification": {
    "is_valid": true,
    "messages": []
  },
  "TrustRegistryMembership": {
    "is_valid": true,
    "messages": []
  }
}


Revoke Issuer

Revoke the status of an issuer for a specific credential type using the public_did, framework_uri and template_uri from above:

trinsic trust-registry unregister-member \
    --schema <template_uri> \
    --did <public_did>

Request to unregister a member as a valid issuer of a specific credential schema. Only one of did_uri, wallet_id, or email may be specified. The URI of the credential schema must be specified.
did_uri
string
DID URI of member to unregister
wallet_id
string
Trinsic Wallet ID of member to unregister
email
string
Email address of member to unregister. Must be associated with an existing Trinsic account.
schema_uri
string
URI of credential schema to unregister member as authorized issuer of

Response to UnregisterMemberRequest
This message has no fields

Verify a proof with Trust Registry status after revocation of issuer

Now we can verify the proof from the previous step, and get the Trust Registry status.

trinsic vc verify-proof --proof-document proof.json

The response should look like:

is valid  "false"
validation results  {
  "CredentialStatus": {
    "is_valid": true,
    "messages": []
  },
  "IssuerIsSigner": {
    "is_valid": true,
    "messages": []
  },
  "SchemaConformance": {
    "is_valid": true,
    "messages": []
  },
  "SignatureVerification": {
    "is_valid": true,
    "messages": []
  },
  "TrustRegistryMembership": {
    "is_valid": false,
    "messages": [
      "issuer is not authorized in the specified registry"
    ]
  }
}



Further Reading: Trust Registries

Next Steps

Congratulations! If you've completed all the steps of this walkthrough, you've just created a mini ecosystem of issuers, verifiers, and holders all exchanging credentials. Depending on your goals, there are a couple of possible next steps to take.