Skip to main content

Holder

The holder is the person a credential is about, usually a student or graduate. A holder has two kinds of things:

  • Files: the credential package the issuer handed over (a JSON file with the signed credential, the holder's details, the salts that open the on-chain commitments, and the key that decrypts the document). Anyone who has the package can do what the package allows, wallet or not.
  • Optionally, a bound wallet: a wallet linked to the student by accepting an issuer's invitation. The bound wallet sees delivered credentials in an inbox, signs disclosure files, signs for a verifier on a phone, and admits people to the access gate.

Words used here: a binding is the on-chain record in HolderRegistry that links one issuer's salted student commitment to one wallet. See Enrolment and the Glossary.

How the app recognises a holder​

There are two answers, and they matter for different actions.

QuestionCheckUsed for
Does this wallet get the holder workspace?Connected, and IssuerAccessService.accessOf says neither isIssuer nor isAdminThe top bar shows My credentials with My credentials (/student), On this phone (/wallet) and Access (/access). A registered issuer opening /student is sent to /dashboard.
Is this wallet the holder of this credential?HolderRegistry.holderOf(anchor.issuer, anchor.subjectCommitment) equals the walletThe inbox, disclosure signatures (checked by verifiers), signing for a verifier on a phone, and admit and removeMember on the access gate.

Many holder actions need neither: opening, sharing and exporting work from the package alone, and the phone wallet at /wallet needs no wallet to add and show codes.

What a holder sees​

/student on v0.3 has the page title My credentials and these parts:

PartTitle in the pageWhat it holds
InboxIssued to this walletCredentials delivered to the bound wallet, read from chain events, with their live status.
InvitationAccept an invitationAccepts an issuer's invitation file.
Documents groupOpen and share your documentsOpen a document, Open a shared document, My share code.
Prove groupShow only what is neededShare some details only (selective disclosure) and Export as a verifiable credential.

/wallet (Credentials on this phone) keeps credentials in the phone's browser for offline showing. /access is also open to holders, though it is mainly for requesters.

Actions​

  1. The issuer creates an invitation for the student ID and the wallet address the student gave, and sends the file.
  2. On /student, under Accept an invitation, choose the Invitation file and press Accept invitation. The wallet asks to confirm a transaction (HolderRegistry.redeem).
  3. If the student was already linked to another wallet, the same button sends rebind instead, which moves the binding to the new wallet. The app chooses by reading holderOf first.

The invitation must name the connected wallet, must not be expired (an issuer can choose 1, 7, 14 or 29 days), and must carry the issuer's current binding epoch, so a cancelled invitation fails. While the system is paused the button is disabled and the page shows: "The system is paused. New credentials, invitations and record types cannot be created right now. Revoking, suspending and other corrections still work." Flow: Enrolment. File: Invitation file.

See delivered credentials​

Once linked, credentials the issuer issued with Deliver to the student's linked wallet ticked appear under Issued to this wallet, including ones issued before the invitation was accepted. Each row offers Verify, Show QR and, where the access gate is deployed, Manage access. A failed read says "Could not load your credentials." and "This is not proof that you have none." Credentials issued without delivery never appear. Flow: Holder inbox.

Open the document​

  1. Under Open a document, choose the Credential package file and press Open document.
  2. The encrypted container is fetched, decrypted in the browser with the package's key, and its SHA-256 is compared with the hash on chain before it is offered.
  3. If the package was chosen but the document did not open (for example because the issuer replaced the document key), the panel asks "Did the issuer send you a key update?": choose the Key update file. It replaces the stored copy the package points at, saves the updated package and opens the document with it.

A package that points at no stored document says "This package does not point to a stored document." Flow: Document storage. File: Credential package, Encrypted container.

Share the document​

After opening, Share this document offers two ways:

WayStepsWho can open
Shared filePaste the Recipient's share code (the recipient gets it from My share code on their own page) and press Create shared file. Send the saved file.Only the wallet that made that share code.
LinkPress Create a link, confirm Create link in the dialog "Create a link to this document?", then Copy link.Anyone with the link ("Anyone with this link can read the document.").

Sharing needs no wallet and sends nothing to the chain. A recipient opens a shared file under Open a shared document (Shared document file, then Open document) and a link at /open. Sharing cannot be taken back: the recipient keeps what they read. Flow: Sharing. File: Sharing files.

Get a share code (to receive a document)​

Under My share code, press Show my share code, then Copy code. The code is a public key derived from a wallet signature; the wallet may ask for that signature. Send the code to whoever will share with you.

Show only some details​

  1. The verifier gives you a challenge (they copy it from Check a disclosure on /verify).
  2. Under Share some details only, choose the Package to choose details from, pick the fields to show, paste the Verifier's challenge and press Create disclosure file. The bound wallet signs the file.
  3. Send the saved file to the verifier.

Verifiers check that the fields were signed by the issuer and that the file was signed by the wallet bound to the student. A package issued before selective disclosure existed needs disclosure data from the issuer first. Flow: Selective disclosure. File: Disclosure file.

Export a verifiable credential or Open Badge​

Under Export as a verifiable credential, choose a Format (Verifiable credential, Open Badge, and Open Badge with standard proof where the page can sign it), optionally tick "Include my wallet address as the subject id", and choose the Package to export. The file is saved at once. Ticking the box makes two of your credentials linkable to each other. Flow: Verifiable credentials. File: Verifiable credential.

Carry a credential on a phone​

  1. Open /wallet on the phone. Under Add a credential, choose a Credential file, paste a Code or link and press Add, or scan the code the issuer showed (Show a QR code for the holder's phone on the issued card).
  2. Tick "Keep my name and details on this phone (needed to show them or to sign for a verifier)" if you want that.
  3. Check the details under Add this credential? and press Add to this phone. A code whose details do not match what the issuer signed is refused.
  4. To show it, press Show the code on the card. "Include my name and details in the code" decides what a scanner sees. Remove from this phone deletes it.
  5. To prove it is yours, under Sign for a verifier, paste or scan the Challenge from the verifier, pick the Credential, press Sign with my wallet and show the answer QR.

The credentials stay in that browser and open offline; clearing the site data removes them. Flow: Phone wallet. Codes: Compact codes.

Let someone prove access​

  1. On an inbox row, press Manage access to open Who can prove access.
  2. Paste the Requester's access code and press Admit. This is a transaction from the bound wallet.
  3. To take it back, press Remove on the member and confirm Remove access. "A proof made just before the removal still works for up to 10 minutes. The slot stays used."

A credential admits 64 access codes over its whole life, removed ones included. Admitting needs the credential to be valid and the system not paused; removing works while paused. Flow: ZK access.

What a holder cannot do​

  • Change a credential's status. Only the issuer key in charge (and, for an admin hold, the admin) can suspend, reinstate, revoke or supersede.
  • Unlink their own wallet or cancel invitations. HolderRegistry.unbind and revokeInvitations take the issuer as the caller. A holder moves to a new wallet only with a fresh invitation.
  • Accept an invitation made for another wallet, an expired one, or one the issuer cancelled.
  • See undelivered credentials in the inbox. They exist on chain and work with the package and link, but no wallet can ever receive them.
  • Take back a share. A recipient who opened the document keeps it. The issuer can replace the key and remove old copies, which stops old links and grants from working for future reads.
  • Edit the details in a package: any change fails the commitment check on /verify.

Keys a holder holds​

Key or fileWhereWhy it matters
Credential packageA JSON file from the issuerContains the document key and the salts. Anyone with it can open the document and prove the details. The issuer card warns: "Keep this file private: it opens the document."
Bound walletThe holder's wallet appReceives deliveries, signs disclosures and phone answers, admits access codes.
Share code keyDerived from a wallet signature in the browserOpens shared files made for that code.
Phone wallet dataThe phone browser's storageHashes only by default; names and details only if the holder ticked the box.

Checklist​

  • Keep the credential package private and backed up; it cannot be rebuilt from the chain.
  • Accept the invitation with the exact wallet you gave the issuer, before it expires.
  • Check new credentials in Issued to this wallet and press Verify to see their status.
  • Share by share code when you can; use a link only when anyone holding it may read the document.
  • For a verifier who needs only some fields, use Share some details only with their fresh challenge.
  • Apply any key update file from the issuer before opening the document again.

Source files​

  • src/app/student/page.tsx, AcceptInvitationPanel.tsx, MyCredentialsPanel.tsx, CredentialRow.tsx
  • src/app/student/OpenDocumentPanel.tsx, ApplyKeyUpdate.tsx, SharePanel.tsx, SharedDocumentPanel.tsx, MyShareCodePanel.tsx
  • src/app/student/MakeDisclosurePanel.tsx, src/components/vc/VcExportPanel.tsx
  • src/app/wallet/WalletContent.tsx, AddCredentialPanel.tsx, CredentialCard.tsx, SignForVerifierPanel.tsx
  • src/components/access/AccessPanel.tsx, AdmitForm.tsx, MemberList.tsx
  • src/services/domain/enrolment-service.ts, src/services/domain/document-service.ts
  • blockchain/contracts/v03/HolderRegistry.sol, blockchain/contracts/zk/CertichainAccessGate.sol

Tests​

  • Rendered tests: src/app/student/StudentPageV03.test.tsx, AcceptInvitationPanel.test.tsx, MyCredentialsPanel.test.tsx, OpenDocumentPanel.test.tsx, ApplyKeyUpdate.test.tsx, SharePanel.test.tsx, SharedDocumentPanel.test.tsx, MyShareCodePanel.test.tsx, MakeDisclosurePanel.test.tsx; src/app/wallet/WalletContent.test.tsx
  • Contracts: blockchain/test/v03/HolderRegistry.test.ts
  • E2E: e2e/journeys/invite-and-inbox.journey.ts, delivery.journey.ts, encrypted-documents.journey.ts, share-and-replace.journey.ts, selective-disclosure.journey.ts, mobile-wallet.journey.ts, access-proof.journey.ts, manage-student-link.journey.ts