Credential Service¶
The Credential Service exposes functionality for issuance, proof generation, verification, and revocation of Verifiable Credentials.
Signature Format
The Credential service currently supports BBS+ Signatures , which enable selective disclosure of credential fields during proof generation.
Credentials are signed, and proofs are created, using a key pair unique to the signing / holding wallet. This key pair is created and managed by Trinsic upon account creation.
Issue Credential from Template¶
Issues a credential from a previously-defined template.
trinsic vc issue-from-template [OPTIONS] --template-id <ID>
# OPTIONS
# --out <OUTPUT_FILE> (Optional) Output file to store the issued credential
# --values-data <JSON> The JSON values of the credential subject
# --values-file <FILE> The file with JSON values of the credential subject
let request = IssueFromTemplateRequest.fromPartial({
templateId: templateResponse?.data?.id ?? "",
valuesJson: JSON.stringify({
name: "Alice",
numberOfBags: 2,
dateOfBirth: new Date("1/1/2000").toISOString(),
vaccinated: true,
}),
});
let response = await trinsic.credential().issueFromTemplate(request);
var credentialJson = await trinsic.Credential.IssueFromTemplateAsync(new()
{
TemplateId = templateId,
ValuesJson = values
});
values = json.dumps({"firstName": "Jane", "lastName": "Doe", "age": "42"})
issue_response = await trinsic_service.credential.issue_from_template(
request=IssueFromTemplateRequest(
template_id=template.data.id, values_json=values
)
)
issueTemplateResponse, err := trinsic.Credential().IssueFromTemplate(context.Background(),
&credential.IssueFromTemplateRequest{
ValuesJson: valuesJson,
TemplateId: templateId,
})
var valuesMap = new HashMap<String, Object>();
valuesMap.put("firstName", "Jane");
valuesMap.put("lastName", "Doe");
valuesMap.put("age", 42);
var valuesJson = new Gson().toJson(valuesMap);
var issueResponse =
trinsic
.credential()
.issueFromTemplate(
IssueFromTemplateRequest.newBuilder()
.setTemplateId(templateId)
.setValuesJson(valuesJson)
.build())
.get();
template_id
IssueFromTemplateRequest
IssueFromTemplateRequest
Add governance information to issued credential¶
In order to attach governance information to the credential, issuers must request this explicitly by specifying the parameter
framework_id
in the above request. The framework identifier references the ecosystem governance framework that the issuer is authorized
to issue credentials of the designated type (schema). This identifier has the format urn:egf:<ecosystem>:<type>
.
When this parameter is specified, the issued credential will contain extended information in the issuer
field to assert authorization in
the given governance framework. The framework identifier will be in the issuer.trustRegistry
field.
Here's an example of a VC with extended issuer information:
"issuer": {
"id": "did:key:z5TcEFAQPu7RkrBCMCJDGgVziV",
"type": "AuthoritativeMember"
"governanceFramework": "https://acme.org/authorized-issuers",
"trustRegistry": "urn:egf:acme:92f21b4cb3bc48dd8bb19a872f03afca",
}
See Trust Registry Service for more information on using governance in your ecosystem.
Check Revocation Status¶
Checks a credential's revocation status by its credential_status_id
.
A credential_status_id
can be found in a credential's credentialStatus.id
field, if present.
trinsic vc get-status --credential-status-id <ID>
let checkStatusResponse = await trinsic
.credential()
.checkStatus(CheckStatusRequest.fromPartial({}));
var checkResponse = await trinsic.Credential.CheckStatusAsync(new() { CredentialStatusId = "" });
# check_response = await trinsic_service.credential.check_status(
# request=CheckStatusRequest(credential_status_id="")
# )
status, err := trinsic.Credential().CheckStatus(context.Background(), &credential.CheckStatusRequest{CredentialStatusId: ""})
var checkStatusResponse =
trinsic.credential().checkStatus(CheckStatusRequest.newBuilder().build()).get();
Update Revocation Status¶
Updates the revocation status of a credential (revoke or unrevoke).
A credential_status_id
can be found in a credential's credentialStatus.id
field, if present.
# Revoke a credential
trinsic vc update-status --revoked --credential-status-id <ID>
# Unrevoke a credential
trinsic vc update-status --unrevoked --credential-status-id <ID>
let updateStatusResponse = await trinsic
.credential()
.updateStatus(UpdateStatusRequest.fromPartial({}));
await trinsic.Credential.UpdateStatusAsync(new() { CredentialStatusId = "", Revoked = true });
# update_response = await trinsic_service.credential.update_status(
# request=UpdateStatusRequest(credential_status_id="", revoked=True)
# )
updateStatusResponse, err := trinsic.Credential().UpdateStatus(context.Background(), &credential.UpdateStatusRequest{CredentialStatusId: "", Revoked: true})
trinsic.credential().updateStatus(UpdateStatusRequest.newBuilder().build());
UpdateStatusRequest
Create Proof¶
Creates and signs a proof for a valid JSON-LD credential, using the BBS+ Signature Suite.
If the credential is stored in a Trinsic cloud wallet, pass its item_id
; otherwise, pass the raw JSON-LD credential via document_json
.
Selective Disclosure
BBS+ Signatures support the ability to generate a proof for a subset of a credential's fields, instead of every field.
This enables increased user privacy: fields which aren't included in reveal_document_json
will not be present in the generated proof.
- If
reveal_document_json
is passed, a proof will be generated for only the fields specified. This is a JSON-LD frame. - Rather than formulating a complete JSON-LD frame, you can instead provide a list of proof attributes to reveal, and the service will construct the JSON-LD proof frame internally
- If neither is provided, the entire proof will be returned.
trinsic vc create-proof --document-id <STRING> --out <OUTPUT_FILE> --reveal-document <JSONLD_FRAME_FILE>
let proof = await trinsic.credential().createProof(
CreateProofRequest.fromPartial({
itemId: insertItemResponse.itemId
})
);
let selectiveProof = await trinsic.credential().createProof(
CreateProofRequest.fromPartial({
itemId: insertItemResponse.itemId,
revealTemplate: {
templateAttributes: ["firstName", "lastName"],
},
})
);
var proof = await trinsic.Credential.CreateProofAsync(new()
{
DocumentJson = credentialJson.DocumentJson,
RevealDocumentJson = frame.ToString(Formatting.None)
});
var selectiveProof = await trinsic.Credential.CreateProofAsync(new()
{
DocumentJson = credentialJson.DocumentJson,
RevealTemplate = new()
{
// The other field, not disclosed, is "age"
TemplateAttributes = { "firstName", "lastName" }
}
});
proof_response = await trinsic_service.credential.create_proof(
request=CreateProofRequest(
document_json=credential_json
)
)
selective_proof_response = await trinsic_service.credential.create_proof(
request=CreateProofRequest(
document_json=credential_json,
reveal_template=RevealTemplateAttributes(
template_attributes=["firstName"]
),
)
)
request := &credential.CreateProofRequest{
Proof: &credential.CreateProofRequest_DocumentJson{
DocumentJson: credentialJson,
},
}
proofResponse, err := trinsic.Credential().CreateProof(context.Background(), request)
selectiveRequest := &credential.CreateProofRequest{
Proof: &credential.CreateProofRequest_DocumentJson{
DocumentJson: credentialJson,
},
Disclosure: &credential.CreateProofRequest_RevealTemplate{RevealTemplate: &credential.RevealTemplateAttributes{TemplateAttributes: []string{"name"}}},
}
selectiveResponse, err2 := trinsic.Credential().CreateProof(context.Background(), selectiveRequest)
var createProofResponse =
trinsic
.credential()
.createProof(
CreateProofRequest.newBuilder()
.setDocumentJson(signedCredentialJson)
.build())
.get();
var credentialProof = createProofResponse.getProofDocumentJson();
var selectiveProofResponse =
trinsic
.credential()
.createProof(
CreateProofRequest.newBuilder()
.setDocumentJson(signedCredentialJson)
.setRevealTemplate(
RevealTemplateAttributes.newBuilder()
.addTemplateAttributes("batchNumber")
.build())
.build())
.get();
var selectiveProof = selectiveProofResponse.getProofDocumentJson();
item_id
or document_json
may be provided, not both.CreateProofRequest
Verify Proof¶
Verifies a proof for validity and authenticity. Only supports BBS+ Signatures at present.
# The JSONLD_FILE refers to the proof document obtained from a CreateProofResponse
trinsic vc issuer verify-proof --proof-document <JSONLD_FILE>
let verifyResponse = await trinsic.credential().verifyProof({
proofDocumentJson: proof.proofDocumentJson,
});
⋯
proofDocumentJson: selectiveProof.proofDocumentJson,
var valid = await trinsic.Credential.VerifyProofAsync(new()
{ ProofDocumentJson = proof.ProofDocumentJson });
verify_result = await trinsic_service.credential.verify_proof(
request=VerifyProofRequest(proof_document_json=credential_proof)
)
selective_verify_result = await trinsic_service.credential.verify_proof(
request=VerifyProofRequest(
proof_document_json=selective_proof_response.proof_document_json
)
)
verifyResponse, err := trinsic.Credential().VerifyProof(context.Background(), &credential.VerifyProofRequest{
ProofDocumentJson: proofJson,
})
var verifyProofResponse =
trinsic
.credential()
.verifyProof(
VerifyProofRequest.newBuilder().setProofDocumentJson(credentialProof).build())
.get();
boolean isValid = verifyProofResponse.getIsValid();
VerifyProofRequest
validation_results
passedValidation Results
The verification process performs a number of validations, each of which may fail independently of the others.
For example, a credential may be expired or revoked, but otherwise perfectly valid.
validation_results
contains an entry for each of the following verification steps:
Name | Description |
---|---|
SignatureVerification |
The cryptographic proof over the entire Verifiable Credential, specifically using BBS+ Proof of Signature |
CredentialStatus |
(if supported by credential) Checks if credential has been revoked |
SchemaConformance |
Ensures credential conforms with its schema. It is possible to issue a credential omitting a required field (as captured in the credential template). If your use case allows this kind of omission, you can ignore this validation entry. |
TrustRegistryMembership |
(if relevant) Verifies that credential issuer is an authorized member of the credential's governing Trust Registry |
IssuerIsSigner |
Document issuer is same DID as document signer. If false, it is not safe to assume that the claimed issuer actually issued the credential. |
Exchange Credentials¶
Send via Email¶
Sends a credential to a user via email.
The specified email address must be tied to an existing account in the same ecosystem.
trinsic vc send --email <EMAIL_ADDRESS> --item <FILE>
await trinsic.credential().send(SendRequest.fromPartial({
email: "",
documentJson: JSON.stringify({}),
}));
var sendResponse = await trinsic.Credential.SendAsync(new() { Email = "[email protected]" });
send_response = await trinsic_service.credential.send(
request=SendRequest(
document_json=credential_json, email="[email protected]"
)
)
sendResponse, err := trinsic.Credential().Send(context.Background(), &credential.SendRequest{
DeliveryMethod: &credential.SendRequest_Email{
Email: "[email protected]",
},
DocumentJson: credentialJson,
})
trinsic
.credential()
.send(
SendRequest.newBuilder()
.setDocumentJson(signedCredentialJson)
.setEmail(recipientEmail)
.build());
SendRequest
Alternative Exchange Protocols
Credentials may only be sent to a wallet via email address or with the InsertItem call.
There are a number of ongoing industry efforts to standardize exchange protocols, such as:
We aim to provide support for these methods as they mature.