TrustAlliance Agent SDK
- Create, Revoke, Resolve, Update DIDs
- Connects with TrustAlliance chain
- Store DID documents in a Decentralised file store ( IPFS for MVP stage)
- This is a part of SDKs for Verifiable Credentials, Verifiable Credential Presentations, DID Keys, Self Sovereign Identity and Decentralised Identifiers
IMPORTANT!
- This is a minimum viable product suite with limited functionality.
- Do not use this for productionise code or for an end product
- Please view Limitations
Architecture
TrustAlliance Agent
Limitations
The following features are not available in this minimum viable SDK
- Zero Knowledge Proofs
- Batch insert / update of DIDs
- DID revocation - the DID document will be available on IPFS without DID meta information
- Support for JSON-LD
- Single Sign On (using Self Sovereign Identity)
- Saving a cryptographical print of a verifiable credential on chain
- Multiple authentication
- DID delegation is incomplete , only the nominated parties can modify a DID document
- DID delegation functionality over a verifiable credential will be delivered after MVP stage
Miscellaneous
- You may see warning messages when creating DIDs
- Only works with already created accounts on chain
Issue and Verify credentials
Requirements
- Install nodejs 14.0.0 or above.
- Install follwoing dependencies.
sudo npm i -g ts-node
npm install -g typescript
nvm use 14
npm install @trustalliance/agent
Constructing SSI Elements
Create an Issuer
import {CredentialIssuer,Connector, createAccount, TrustAllianceAgent} from '@trustalliance/agent';
async function createAnIssuer() {
// Create a Connector object.
const connector = new Connector();
// Initialise the `TrustAllianceAgent` with a connector instance.
const agent = new TrustAllianceAgent(connector);
// An Issuer needs an active account on TrustAlliance Blockchain
// Please use the default account for this MVP release
// Functionality will be added to create ad use your own objects in future releases.
const account = await connector.getDefaultAccount();
// A valid context is required to persist an object to the chain
const context = {
agent,
account: account
}
// Creates an issuer
const issuer = await CredentialIssuer.build();
// Saves a DID Document
await issuer.save(context, {"didDocumentMetadata": "docMeta"}, {"didResolutionMetadata": "resolutionMeta"});
let resolevedDIDDocument = await agent.procedure.resolve(issuer.toDidDocument().id);
/** resolevedDIDDocument
* {
did_resolution_metadata: { hello: 'resolutionMeta' },
did_document_metadata: { hello: 'docMeta' },
block_number: 218812,
block_time_stamp: 1635477636,
updated_timestamp: 1635477636,
did_ref: 'https://ipfs.trustalliance.dev:8080/ipfs/QmdH3JyxJ1A45goKAt18ja3TX67ea4Vz2NTyLkLXEQYTk8',
sender_account_id: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
public_keys: [ '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY' ],
did_document: {
'@context': [ 'https://www.w3.org/ns/did/v1' ],
id: 'did:trustalliance:e97aaebd-c221-44d6-925f-f73493eec3dd',
verificationMethod: [ [Object] ]
}
}
{
header: {
alg: 'EdDSA',
typ: 'JWT',
kid: 'did:trustalliance:key:JsonWebKey2020:ZpM9EIlXv2Yj9F1IaIS-S1-BkSrXIq8ad2rpAffDDlg#ZpM9EIlXv2Yj9F1IaIS-S1-BkSrXIq8ad2rpAffDDlg'
},
payload: {
nbf: 1635477651,
iss: 'did:trustalliance:e97aaebd-c221-44d6-925f-f73493eec3dd',
vp: {
'@context': [Array],
type: [Array],
verifiableCredential: [Array]
}
},
signature: 'PdPWI_J88vokw68_APAFh3BU7Go6grabOGj3SAtFbfOwpJCz0yyAh7xR7rdZIw7lhCHwPfB6-25QFYsUEehACw'
}
* */
}
Create a Verifiable Credential and a Verifiable Credential Presentation
import {CredentialIssuer,Connector, createAccount, TrustAllianceAgent} from '@trustalliance/agent';
async function verifiableCredential(credentialData: any) {
const connector = new Connector();
const agent = new TrustAllianceAgent(connector);
const account = await connector.getDefaultAccount();
const context = {
agent,
account: account
}
const issuer = await CredentialIssuer.build();
await issuer.save(context, {"hello": "docMeta"}, {"hello": "resolutionMeta"});
/*
Ppopulate Credential subject with data
Reference :- https://www.w3.org/TR/vc-data-model/#example-1-a-simple-example-of-a-verifiable-credential
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"alumniOf": {
"id": "did:example:c276e12ec21ebfeb1f712ebc6f1",
"name": [{
"value": "Example University",
"lang": "en"
}, {
"value": "Exemple d'Université",
"lang": "fr"
}]
}
},
*/
const credential = {
'@context': ['https://www.w3.org/2018/credentials/v1'],
type: ['VerifiableCredential'],
issuanceDate: '2010-01-01T19:23:24Z',
credentialSubject: credentialData, // default {}
issuer: issuer.id,
};
// Creates a JWT
const jwt = await issuer.createVerifiableCredentials(credential);
// Creates a JWT presentation
const jwtPresentation = await issuer.createVerifiablePresentation([jwt], issuer.keypair);
let decode = CredentialVerifier.decodeJWT(jwtPresentation);
// Prints decoded JWT presentation
console.log(decode);
}
Verification Process
/*
IssuerA Creates a Credential
*/
async function createCredentials() {
// Creates a connector object
const connector = new Connector();
// Creates the TrustAlliance Agent
const agent = new TrustAllianceAgent(connector);
// Creates the defualt account for the issuer
// `Alice` if there's no mnemonic
// The passing mnemonic must be a valid account on TrustAlliance
// For the MVP please use either Alice or Bob since we are finalising our token
// economic and account model
const account = await connector.getDefaultAccount();
// Creates the issuer's context
const context = {
agent,
account: account
}
// Create Issuer's keypair
const IsserA = await CredentialIssuer.build();
// Saves the Issuer's DID
// This needs to be done only once per issuer
// Do not create new issuers per credentials
await IsserA.save(context, {"hello": "docMeta"}, {"hello": "resolutionMeta"});
// Issuer creates a credential
// Pass teh required data as JSON to `credentialSubject: {},`
const credential = {
'@context': ['https://www.w3.org/2018/credentials/v1'],
type: ['VerifiableCredential'],
issuanceDate: '2010-01-01T19:23:24Z',
credentialSubject: {},
issuer: IsserA.id,
};
const jwt = await IsserA.createVerifiableCredentials(credential);
// Issuer creates a verifiable credential presentation
const jwtPresentation = await IsserA.createVerifiablePresentation([jwt], IsserA.keypair);
// The above jwtPresentation can reside on a wallet / website or in a database
A verifier verifies the JWT
async function verify(jwtPresentation) {
// Creates a connector object
const connector = new Connector();
// Creates the TrustAlliance Agent
const agent = new TrustAllianceAgent(connector);
// Create a verifier
let verifier = new CredentialVerifier();
// For the MVP please use an Account available on TrustAlliance Chain.
const accountB = await connector.getDefaultAccount("Bob");
const verifierContext = {
agent,
account: accountB
}
const r = await verifier.verifyPresentation(jwtPresentation, verifierContext);
console.log(r); // True | False
}
Usage
Installation
npm install @trustalliance/agent
## or yarn
yarn add @trustalliance/agent
Importing
ES Modules import
import { TrustAllianceAgent } from '@trustalliance/agent'
CommonJS import
const { TrustAllianceAgent } = require('@trustalliance/agent');
DID Operations
- Reference :- https://www.w3.org/TR/did-core/
Create a DID
- The DID Document must be saved on IPFS
/*
* `saveToDistributedStorage returns the `cid`
* Please Include this value as the didRef when calling the constructDIDDocument and updateDIDDocument methods.
*/
agent = new TrustAllianceAgent(new Connection());
let result = await agent.procedure.saveToDistributedStorage(desDIDStructure, null);
/*
* Returns Promise<ExtrinsicResults>
* ExtrinsicResults
export type ExtrinsicResults = {
[key: string]: any;
} | null;
*/
let agent = new TrustAllianceAgent(new Connector());
await agent.procedure.constructDIDDocument(
account,
didDocument,
didDocumentMetadata,
didResolutionMetadata,
didRef,
publicKeys
);
Resolve a DID
let did_uri = "did:0xfac17a:0x68b5d6033f8958558cc0bb48328bb9ba0651078b3f69eee533a2dfdba75965f2"
let agent = new TrustAllianceAgent(new Connector());
await agent.procedure.resolve(did_uri);
Revoke a DID
/*
* Returns Promise<ExtrinsicResults>
* ExtrinsicResults
export type ExtrinsicResults = {
[key: string]: any;
} | null;
*/
let did_uri = "did:0xfac17a:0x68b5d6033f8958558cc0bb48328bb9ba0651078b3f69eee533a2dfdba75965f2"
let agent = new TrustAllianceAgent(new Connector());
await agent.procedure.revoke(
account,
did_uri
);
Update a DID
- To update a DID Document, you need to grab the DID information and meta data from resove method
let did_uri = "did:0xfac17a:0x68b5d6033f8958558cc0bb48328bb9ba0651078b3f69eee533a2dfdba75965f2"
let agent = new TrustAllianceAgent(new Connector());
await agent.procedure.resolve(did_uri);
/*
* Returns Promise<ExtrinsicResults>
* ExtrinsicResults
export type ExtrinsicResults = {
[key: string]: any;
} | null;
*/
let agent = new TrustAllianceAgent(new Connector());
await agent.procedure.updateDIDDocument(
account,
didDocument,
didDocumentMetadata,
didResolutionMetadata,
didRef,
publicKeys
);
Create W3C Verifiable Credentials
Following steups to create and sign W3C credential as jwt
Sign credentials
import { CredentialIssuer } from '@trustalliance/agent'
import { createAccount } from '@trustalliance/agent/account'
const connector = new Connector();
// initialize the agent
const agent = new TrustAllianceAgent(connector);
const account = connector.getAccount(mnemonic)
// create context
const context = {
agent,
account
}
//initialize credential issuer
const issuer = await CredentialIssuer.build();
// save did document to ipfs
issuer.save(context)
const credential = {
'@context': ['https://www.w3.org/2018/credentials/v1'],
type: ['VerifiableCredential'],
issuanceDate: '2010-01-01T19:23:24Z',
credentialSubject: {},
issuer: issuer.id,
};
const jwtCredential = await issuer.createVerifiableCredentials(credential)
// jwt
Verify credentials
const connector = new Connector();
// initialize the agent
const agent = new TrustAllianceAgent(connector);
const account = connector.getAccount(mnemonic)
// create context
const context = {
agent,
account
}
const verifier = new CredentialVerifier();
// ... create jwtCredential
const r = await verifier.verifyCredentials(jwtCredential, context);
// true/false
Create W3C Verifiable Presentation
Sign presentation
Following steups to create and sign W3C Presentation as jwt
import { CredentialIssuer } from '@trustalliance/agent'
import { createAccount } from '@trustalliance/agent/account'
//initialize credential issuer
const issuer = await CredentialIssuer.build();
const keyPair = issuer.keypair
const jwtPresentaion = await issuer.createVerifiablePresentation([
jwtCredential
], keyPair)
// jwt
Verify presentation
Context is require to retrive verification for credentials
const connector = new Connector();
// initialize the agent
const agent = new TrustAllianceAgent(connector);
const account = connector.getAccount(mnemonic)
// create context
const context = {
agent,
account
}
const verifier = new CredentialVerifier();
// ... create jwtPresentation
const r = await verifier.verifyPresentation(jwtPresentation, context, issuer.keypair)
// true/false
With custom chain settings
You can use custom url with sdk.
More info on options
: https://polkadot.js.org/docs/api/start/rpc.custom
const { DefaultOptions } = require('@trustalliance/agent')
const options = {
url: 'ws://custom.node.example.com', // custom node url ws[s]://custom.node.example.com[:9944]
options: {...DefaultOptions.options} // using trustalliance defaults
}
const agent = new TrustAllianceAgent(new Connector(options));
Creates a new Account
// CREATE NEW ACCOUNT
const connector = new Connector();
const account = connector.createAccount({name:"TrustAlliance"});
// {
// keyPair:... ,
// mnemonic: ... // Your secret key
// }
// use polka js wallet to send credit to your account
// Creates the new account by using the mnemonic generated for the new account
// You can use a design implementation of your own to store the mnemonic
// https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Falpha-node.trustalliance.dev#/accounts
// initialize the agent
const agent = new TrustAllianceAgent(connector);
// load your account back
const importedAccount = connector.getAccount(account.mnemonic)
// create context
const context = {
agent,
account: importedAccount
}
// Creates an Issuer
const issuer = await CredentialIssuer.build();
const metada = { "content-type": "application/json" }
const resMetada = { "content-type": "application/json" }
// Creates a Transaction based on the new account
const result = await issuer.save(context, metada, resMetada);