Decentralized Identifiers (DID) and Verifiable Credentials
User controlled identifiers plus portable, signed claims. How DIDs resolve, how credentials are issued and verified, and how these building blocks fit with wallets, apps, security, and compliance.
Introduction: Portable identity that you actually control
A Decentralized Identifier (DID) is a globally unique identifier you control that resolves to a DID document listing public keys and optional service endpoints. Control comes from keys, not from a platform account. A Verifiable Credential (VC) is a signed JSON document where an issuer asserts facts about a subject (for example, “email verified”, “over 18”, “completed course”, “KYC checked”). A holder stores credentials in a wallet and later creates a verifiable presentation tailored to a verifier’s request. The verifier checks signatures and status without needing to ping the issuer every time.
1) DIDs: formats and methods
A DID is a URI with a method prefix that defines how to create, read, update, and deactivate identifiers and their documents. Control flows from possession of private keys referenced in the DID document. Popular methods include:
did:pkh
(public key hash): binds a DID to a chain specific address (for example,did:pkh:eip155:1:0xabc…
). Proof of control is a wallet signature. No on chain writes are required; resolution is deterministic from the address and chain id.did:ethr
(registry backed): anchors key material and delegates in an Ethereum registry. You can rotate keys, add controllers, or publish services via transactions. Useful when you want audit trails on chain.did:web
(web hosted): resolves tohttps://domain/.well-known/did.json
or path baseddid:web:domain:users:alice
ashttps://domain/users/alice/did.json
. Enterprises like it because it maps to domain control and existing TLS governance.did:key
(self describing): encodes the public key directly inside the DID. Zero external infrastructure. Great for ephemeral, pairwise, or air gapped use.did:ion
and other Sidetree based methods: batch key operations on top of public ledgers, enabling scalable, anchor based DIDs with decentralized checkpoints.
DID document anatomy. A DID document lists verification methods (public keys), their relationships (authentication, assertion, key agreement, capability invocation), optional controllers, and service endpoints (for example, DIDComm inbox or OIDC). Keys can be JWKs or multibase encodings. Method rules define how to rotate or revoke them.
{ "@context": ["https://www.w3.org/ns/did/v1"], "id": "did:web:example.com", "verificationMethod": [{ "id": "did:web:example.com#owner", "type": "EcdsaSecp256k1VerificationKey2019", "controller": "did:web:example.com", "publicKeyJwk": {"kty":"EC","crv":"secp256k1","x":"...","y":"..."} }], "authentication": ["did:web:example.com#owner"], "assertionMethod": ["did:web:example.com#owner"], "service": [{ "id": "#messaging", "type": "DIDCommMessaging", "serviceEndpoint": "https://example.com/inbox" }] }
2) Verifiable credentials: model and formats
A VC is a tamper evident container for claims issued by an issuer about a subject. The subject is often a DID but can be another identifier like a phone number or email. The holder stores VCs and later creates a verifiable presentation for a verifier, binding disclosure to a fresh challenge and audience.
- Roles: Issuer signs the VC and publishes status; Holder curates and presents; Verifier checks signatures, schema, trust policy, and status without contacting the issuer each time.
- Signature families:
- JWT VC (JWS based). Familiar to OAuth and OIDC stacks. Compact, widely supported.
- Data Integrity proofs (Linked Data Proofs). JSON LD with canonicalization and suites like Ed25519, ECDSA, and BBS+. Enables selective disclosure at the field level.
- Anonymous credentials (for example, BBS+ and AnonCreds). Support unlinkable presentations and predicates like “age over 18” without revealing the birth date.
- Trust model: verifiers whitelist issuers for specific claim types (for example, which issuers can attest “KYC verified”). Trust registries or policy engines can encode these rules.
// Minimal VC (illustrative) { "@context": ["https://www.w3.org/ns/credentials/v2"], "type": ["VerifiableCredential","CourseCompletion"], "issuer": "did:web:university.example", "credentialSubject": { "id": "did:pkh:eip155:1:0xabc...", "course": "Blockchain 101", "result": "pass" }, "issuanceDate": "2025-01-01T12:00:00Z", "credentialStatus": { "id": "https://university.example/status/2025/01/list#12345", "type": "StatusList2021Entry", "statusPurpose": "revocation", "statusListIndex": "12345", "statusListCredential": "https://university.example/status/2025/01/list" }, "proof": {"type":"EcdsaSecp256k1Signature2019","jws":"..."} }
// Verifiable Presentation (holder binds to audience and nonce) { "type": ["VerifiablePresentation"], "holder": "did:pkh:eip155:1:0xabc...", "verifiableCredential": [ /* embedded or referenced VC(s) */ ], "proof": { "type": "EcdsaSecp256k1Signature2019", "challenge": "nonce-from-verifier", "domain": "login.example.com", "created": "2025-01-03T10:21:00Z", "jws": "..." } }
3) Issuance flows (wallet and server)
Issuance is how a wallet obtains a credential from an issuer. There are several patterns, from developer friendly to enterprise grade:
A) OpenID for Verifiable Credential Issuance (OIDC4VCI)
Modern issuers expose an OAuth inspired API. A wallet receives a credential offer (for example, a QR code) describing credential types and grant options, exchanges an authorization code or a pre authorized code for a token, and calls the credential endpoint to receive a signed VC. Benefits: standard client authentication, consent screens, and enterprise logging.
- Credential offer: wallet scans a QR or deep link.
- Grant: authorization code flow or pre authorized code (for kiosk style issuance).
- Token: wallet obtains an access token and proof of possession parameters.
- Credential: wallet calls issuer with a proof of key possession and receives the VC.
B) Self Issued OpenID Provider (SIOP) and Presentation Exchange
The wallet acts as an OpenID provider for the user. Useful when you want to integrate with existing OIDC relying parties with minimal changes. A verifier sends a request object specifying claims and acceptable credential types; the wallet responds with a presentation that satisfies the request.
C) Aries and DIDComm ecosystems
Agent to agent messaging (DIDComm) with credential issuance, connection protocols, and trust frameworks. These flows are well suited for bilateral and enterprise workflows, with transport level encryption and long running conversations.
4) Presentation and verification
Presentations turn stored credentials into proof useful to a relying party. Standard patterns reduce code and improve safety.
OpenID for Verifiable Presentations (OpenID4VP)
The verifier posts a request object specifying acceptable credential types, schemas, and proof requirements. The wallet creates a presentation that satisfies the constraints, binds it to a fresh nonce and audience, and returns it over a back channel or front channel. The verifier then:
- Checks the presentation signature and freshness (challenge and audience).
- Resolves the issuer DID document and verifies the embedded VC proof.
- Consults status lists to ensure the credential is not revoked or suspended.
- Validates schema version and claim constraints, then maps to application roles.
Sign In with Ethereum (SIWE) plus VCs
Authenticate control of a wallet with a SIWE message, then authorize access with one or more VCs. This blends familiar Web3 patterns with privacy centric attributes. Always bind the VC presentation to the same SIWE nonce to prevent relay attacks.
// Pseudo-verifier flow assert(verifySIWE(message, signature)); // wallet control for (const vc of presentation.credentials) { const didDoc = resolve(vc.issuer); assert(verifyVCSignature(vc.proof, didDoc)); assert(checkStatus(vc) === "good"); assert(validateSchema(vc)); } assert(presentation.proof.challenge === siweNonce); assert(presentation.proof.domain === expectedAudience);
5) Revocation, expiry, and status lists
Credentials need lifecycle controls. Verifiers should be able to detect a revoked credential offline and at scale without calling the issuer on every login.
- StatusList2021 style lists: efficiently encode thousands of revocation states as a bitstring inside a signed VC. Each credential references an index in the list. Verifiers fetch the list periodically and check bits locally.
- Event logs: append only feeds of revocation events. Simple to reason about but can leak issuance timing and volumes.
- Expiry fields: include
validFrom
andvalidUntil
so verifiers can enforce freshness and reduce reliance on revocation for predictable lifecycle changes. - Suspension versus revocation: support temporary suspension for incident response, separate from permanent revocation.
6) Privacy and anti correlation design
Credential ecosystems fail if they become surveillance tools. Build privacy in by default.
- Pairwise DIDs: use a distinct DID for each verifier. Wallets can derive pairwise identifiers from a master seed, similar to payment address derivation.
- Selective disclosure: prefer BBS+ or SD JWT techniques so holders reveal only required attributes. For numeric attributes, use predicates (for example, “age over 18”).
- Presentation binding: every presentation must include a fresh nonce and an audience string to prevent relay and limit replay across sites.
- Collection minimization: verifiers should request the minimum attributes and avoid storing raw VC blobs when a simple boolean suffices.
- Issuer non tracking: offline verification via status lists avoids pinging issuers and leaking usage patterns.
- Wallet fingerprinting resistance: standardize flows and headers; avoid unique network beacons that let verifiers correlate users across sessions.
7) Wallet UX and developer patterns
Good wallets make power safe. Good developer patterns make integration predictable.
- Clear consent screens: show issuer name, credential types, and fields. Provide links to policy and revocation support.
- Backup and recovery: encrypt credentials at rest and offer cloud or local backups that do not leak to issuers. For regulated credentials, provide export for audits with user consent.
- Key management: support hardware signing or secure elements on device. Expose an easy path to rotate keys while preserving continuity via updated DID documents.
- Offline mode: allow presentations to be prepared offline and submitted when connectivity returns. Cache status lists with signature checks.
- Developer ergonomics: publish simple SDKs for issuance and verification, plus example policy files and test vectors. Favor deterministic error codes over vague failures.
8) Bridging to Web2 systems
Most organizations already use SSO, SAML, and OAuth. You can adopt DIDs and VCs without rewiring everything.
- OIDC facade: wrap VC verification behind an OpenID provider that issues familiar ID tokens with claims derived from verified VCs.
- Attribute mapping: map VC fields to application roles (for example, “vc.role=maintainer” maps to “repo:write”). Maintain a policy file so audits are clear.
- Trust registries: maintain allowlists of issuers trusted for claim types. Version and sign these registries to avoid silent drift.
- Audit trails: log verification outcomes and key ids used, not raw personal data. Retain only what is necessary for incident review.
9) Using DIDs and VCs with on chain apps
On chain contracts cannot verify JSON signatures directly without heavy gas costs. Practical approaches:
- Off chain verify, on chain attest: perform VC checks in a backend or a decentralized attestation service. Emit an on chain attestation that a subject satisfied policy P at time T, signed by an attestor set.
- Minimal on chain signals: couple VCs with public, non sensitive SBT style indicators when you need contract readable flags. Keep private details off chain.
- did:pkh bridge: map DIDs to addresses using
did:pkh
so SIWE proof of control ties cleanly to a DID used in VCs.
10) Multi chain and method choice
There is no one perfect DID method. Choose based on governance, risk, and developer surface area.
- Wallet first apps:
did:pkh
keeps things simple and works across EVM and other chains that can sign challenges. No registry to manage. - Enterprise portals:
did:web
aligns with domain governance and change control already in place. Ensure you have a plan for hosting and rotation. - On chain audit needs:
did:ethr
gives you transaction anchored history for key changes and delegates. - Ephemeral or pairwise:
did:key
is light weight and avoids external dependencies. - Large scale ecosystems:
did:ion
and similar methods scale key operations and offer strong decentralization properties.
did:pkh
for wallet login, add did:web
for issuers, and graduate to registries or Sidetree methods when you need stronger rotation governance or ecosystem interoperability guarantees.11) Developer cookbook (snippets and checklists)
Verifier checklist
- Require SIWE or equivalent proof of control for wallet sessions.
- Accept presentations bound to your audience and a fresh nonce.
- Resolve issuer DID docs and pin acceptable key ids and algorithms.
- Check status lists locally; refresh on a timer or cache miss.
- Validate schema versions; fail closed on unknown or missing fields.
- Store only derived attributes or decisions, not full credentials.
Issuer checklist
- Publish human readable policy and support contacts.
- Version credential schemas and proofs; include integrity fields.
- Operate signer keys behind HSM or MPC; rotate with documented ceremonies.
- Offer status lists for revocation and suspension; sign and timestamp them.
- Implement OIDC4VCI if you expect broad wallet support.
Sample SIWE message
example.com wants you to sign in with your Ethereum account: 0xAbC... URI: https://example.com Version: 1 Chain ID: 1 Nonce: 5xJcN2Rk Issued At: 2025-01-03T10:21:00Z Expiration Time: 2025-01-03T10:26:00Z
12) Operations and threat model
Identity is a high value target. Treat DID and VC infrastructure like payments or production keys.
- Key compromise: protect issuer keys with HSM or MPC, enforce four eyes approvals, and publish rotation timelines. Verifiers must track acceptable key ids and dates.
- Phishing: presentation requests should display clear relying party names and scopes. Wallets must show what will be disclosed before the user clicks accept.
- Availability: cache DID documents and status lists, serve them from redundant locations, and monitor freshness. Your verifier should continue functioning during transient issuer outages.
- Schema drift: version schemas and detect unexpected fields. Attackers may try to smuggle malicious data into claim slots.
- Policy drift: store signed trust registries so what you accept today is auditable tomorrow. Changes should require review.
- Privacy incidents: design for minimum retention, support credential revocation and reissue, and offer redress processes.
13) Case studies and anti patterns
Exchange onboarding. A regulated exchange issues a “KYC verified” VC after traditional checks. Daily logins use SIWE plus a presentation proving only “over 18” and “KYC verified.” Status lists support instant suspensions during investigations. Result: fewer resubmissions, better privacy, quicker incident response.
University credentials. A university issues completion credentials and a second credential for continuing education status that expires annually. Employers verify offline. Result: applicants own their records, and verifiers do not need to email registrars.
DAO contributor roles. A DAO accepts presentations that prove “maintainer” and “security steward” without leaking real identities. Admin bots check these before processing upgrade proposals. Result: high assurance gating with transparent policy.
Anti patterns to avoid
- Static screenshots of credentials in support tickets. Always verify signatures and status.
- Presentations without nonce or audience. These can be replayed or relayed to other sites.
- Relying on live issuer APIs to decide validity. This leaks usage and creates a single point of failure.
- Collecting entire VCs when a boolean decision would suffice. Store least privilege facts.
- One DID for everything. Without pairwise DIDs, correlation grows quickly.
14) Frequently asked questions
Do I need a blockchain to use DIDs and VCs?
No. Methods like did:web
and did:key
need only HTTPS hosting or none at all. Some methods anchor changes on chain for auditability, but it is optional.
Can I rotate keys without breaking users?
Yes. Update the DID document with new verification methods per the method rules, deprecate old keys, and set a transition window. Verifiers should accept both during the overlap.
What about lost wallets?
For holders, credentials are data that can be backed up and restored to a new device. For issuers, publish reissue policies and mark old credentials revoked, then issue fresh ones.
Do verifiers need to talk to issuers?
Not for standard checks. Resolve the issuer DID document and consult signed status lists. Contact issuers only for dispute resolution or unusual cases.
15) Glossary
- DID: a decentralized identifier that resolves to a DID document under a method.
- DID document: JSON that lists keys, relationships, controllers, and services.
- VC: verifiable credential, a signed container for claims about a subject.
- VP: verifiable presentation, a holder assembled proof bound to a nonce and audience.
- Status list: a signed list encoding credential revocation or suspension states.
- Selective disclosure: revealing only the fields required for a transaction.
- Pairwise DID: a unique DID per counterparty to avoid correlation.
Quick check
- What does a DID resolve to and why is that important for rotation?
- Name two VC signature families and a reason you might pick each.
- How can a verifier check revocation without contacting the issuer on every request?
- Why must presentations include both a challenge and an audience?
- When would you choose did:pkh versus did:web for a production app?
Show answers
- A DID resolves to a DID document listing keys and services; rotation updates that document so verifiers learn new keys without changing identifiers.
- JWT VC (fits OAuth stacks, compact) and Data Integrity proofs (JSON LD, selective disclosure via BBS+).
- Use signed status lists such as bitstring lists, fetched and verified locally on a schedule.
- To prevent replay and relay, and to scope the proof to a specific relying party.
- did:pkh for wallet centric login with minimal infra; did:web when the issuer is anchored to a domain with enterprise change control.
Go deeper
- W3C DID Core and method registries
- W3C Verifiable Credentials Data Model
- Sign In with Ethereum (SIWE) and OpenID profiles for VCs
- Topics to practice: trust registries, status list rotation, pairwise DID derivation, and OIDC4VCI credential offers
Next: multisig wallets and MPC practical shared control for teams and vaults.