Certificates
Certificate creation and utilization
This page explains how WalletClient works with off-chain signed certificates which are verifiable statements issued by a certifier such as CoolCert or SocialCert. You will see how to issue, prove, revoke, and discover certificates from the wallet's side.
Why Certificates Matter
With a certificate linked to a wallet, anyone who has your identity key and is given access to one of your certificates can verify whatever claim the certifier made about you. That opens the door to use‑cases such as:
-
Access control – enforce subscription tiers, seat limits, API quotas.
-
Proof of fact – confirm author identity, course completion, age, licences, etc.
-
Delegation – allow a key to spend or act on behalf of another key under strict limits.
Certificate Anatomy
- Certificate type - A 32‑byte Base‑64 string that names the certificate schema. Think of it as the template for an “ID Card”, “Passport”, or “Driver’s Licence”, with every certificate of that type shares the same field keys; only the values differ.
- Fields - An array of Key/value claims that fill the schema. Examples:
plan: premium,zip: 97201,cool: true. - Signature - 64-byte signature created by the certifier using their public key that ensures the authenticity of the certification.
Production Certifier Services
Below are two live certifiers used in the demos. The public details for CoolCert are shown so you can follow the code samples. A real, trusted certifier would normally keep these values private and authenticate requests on thier own backend.
CoolCert
1certifierUrl : https://prod-coolcert-921101068003.us-west1.run.app
2certifier : 02cab461076409998157f05bb90f07886380186fd3d88b99c549f21de4d2511b83
3type : AGfk/WrT1eBDXpz3mcw386Zww2HmqcIn3uY6x4Af1eo=SocialCert
1certifierUrl : integrated into their frontend
2certifier : `02cf6cdf466951d8dfc9e7c9367511d0007ed6fba35ed42d425cc412fd6cfd4a17`
3type : one per SocialCert schema: email / phone / X(Each service defines its own certificate types and required field names)
Issue A Certificate Using Coolcert
The snippet below shows how to ask CoolCert for a “cool” certificate. You can run it against the public CoolCert demo, but in practice, these would point to your own certification backend.
1// Coolcert's server public key
2const certifier = '02cab461076409998157f05bb90f07886380186fd3d88b99c549f21de4d2511b83'
3
4// Coolcert server's certifier url
5const certifierUrl = 'https://prod-coolcert-921101068003.us-west1.run.app'
6
7// Coolcert's certificate type
8const type ='AGfk/WrT1eBDXpz3mcw386Zww2HmqcIn3uY6x4Af1eo='
9
10await wallet.acquireCertificate({
11 certifier: '02cab461076409998157f05bb90f07886380186fd3d88b99c549f21de4d2511b83',
12 certifierUrl: 'https://prod-coolcert-921101068003.us-west1.run.app',
13 acquisitionProtocol: 'issuance',
14 type: 'AGfk/WrT1eBDXpz3mcw386Zww2HmqcIn3uY6x4Af1eo=',
15 fields: { cool: 'true' }
16});Your wallet now holds a signed CoolCert certificate that anyone can verify to see that you are cool.
Listing and Proving Certificates
After issuing a CoolCert certificate, Alice can list all of the certificates in her wallet and selectively prove fields to Bob. Only the specified fields become visible; everything else stays encrypted.
Alice's side:
1// you can add filters for listing certificates in your wallet
2const certifiers = ['0220529dc803041a83f4357864a09c717daa24397cf2f3fc3a5745ae08d30924fd'] // leave empty to search for certificates with any certifier
3const types = ['AGfk/WrT1eBDXpz3mcw386Zww2HmqcIn3uY6x4Af1eo='] // leave empty to search for certificates with any type
4
5// extract a list of the filtered certificates with encrypted fields
6const { certificates } = await wallet.listCertificates({
7 certifiers,
8 types
9});
10
11// if you specify a single certifier and a single type, there should generally only be one specific certificate returned
12const certificate = certificates[0]
13
14// create a decryptable record of the fields for the verifier's public identity key
15const { keyringForVerifier } = await wallet.proveCertificate({
16 certificate, // specify the specific certificate that you want prove
17 fieldsToReveal: ['cool'], // expose only this field
18 verifier: bobsIDKey
19})Bob's side:
1// receive the encrypted certificate and the keyring that was made for Bob
2const fields = VerifiableCertificate.fromCertificate(
3 certificate,
4 keyringForVerifier
5)
6
7// decrypt the fields using Bob's wallet
8const alicesCertificateFields = fields.decryptFields(bobsWallet)
9console.log('Alice\'s Certificate Fields:', alicesCertificateFields)Attribute Discovery (find identities by certificate fields)
WalletClient can also search the blockchain for certificates that match certain field values. For example, you can locate every identity that has a SocialCert email matching yours. (You can get one at https://socialcert.net/)
Managing trust - In BSV Desktop you’ll find a “Trust” tab where you can add or remove certifier servers, set trust levels for each certificate service, and set the minimum trust threshold. WalletClient ignores any certificate whose certifier scores below that threshold, so you stay in control of which certificates you accept in these discoveries.
1// locate identities that have a SocialCert email field set to your address
2const { certificates, totalCertificates } = await wallet.discoverByAttributes({
3 attributes: { email: 'your-email@example.com' }
4});
5console.log('Certificates found:', totalCertificates)
6
7// to see who provided the certificate and the revealed fields
8console.log('Certifier:', certificates[0].certifierInfo.name)
9console.log('Publicly revealed fields: ', certificates[0].publiclyRevealedKeyring)Discover by identity key
You can also look up all of the certificates owned by a single identityKey by using discoverByIdentityKey().
1// Replace bobsIDKey with the identity key you want to inspect
2const { certificates } = await wallet.discoverByIdentityKey({ identityKey: bobsIDKey });
3
4console.log('Certificates found:', certificates.length);
5certificates.forEach((c, i) => {
6 console.log(`${i + 1}. Type: ${c.type} · Certifier: ${c.certifierInfo.name}`);
7});Each entry in certificates includes:
-
Encrypted
fieldsandkeyringblobs that only the holder or someone they prove to can decrypt. -
A
publiclyRevealedKeyringthat lists fields the holder has chosen to make public. -
A
decryptedFieldsobject that appears only when the holder has revealed fields to you viaproveCertificate().
If you need to see the contents, ask the owner to prove the specific fields you care about just like Alice did for Bob in the earlier example.
Hosting Your Own Certifier (Overview)
If you would like to facilitate your own trusted certificates, creating a certifier backend like CoolCert would be a good way of doing that (see https://github.com/p2ppsr/coolcert for a reference implementation). At a high level you will:
-
Generate a certificate type by Base‑64‑encoding 32 random bytes.
-
Define a fixed set of field names for that schema.
-
Publish the
certifierUrl, your certifier’s public key, and the certificatetypeso wallets know where to send requests. -
Expose
/issue,/prove, and/revokeHTTP endpoints that follow the same JSON contract used by CoolCert and SocialCert.
There are many more ways to prove your identity and your authorization than just using Certificates. If you want another tool for identity discovery, you can turn to IdentityClient in the SDK. Its helpers let you more easily do things like parsing results into displayable formats based on common types and publishing your own certificates for discovery.
That’s all you need to manage certificates from the wallet side: issue, query, prove, revoke, and discover all while without exposing sensitive information you want to keep private.
