What is a Decentralized Identifier (DID)?

A DID is a globally unique identifier that does not require a centralized registration authority. The W3C DID Core 1.0 Specification defines a generic format: did:<method>:<method-specific-id>.

Each DID resolves to a DID Document — a JSON object that lists the public keys and service endpoints associated with the identifier. The method part of the DID determines how resolution happens.

Why did:web?

The did:web method resolves a DID by fetching a JSON document over HTTPS. did:web:issuer.example.com resolves to https://issuer.example.com/.well-known/did.json. It uses infrastructure organizations already operate (DNS + TLS + a web server) instead of requiring a blockchain or distributed ledger.

Honest comparison of common DID methods

MethodAnchorCostHonest tradeoff
did:webDNS + HTTPSFree (you already pay for the domain)Trust collapses to whoever controls the domain & cert. Not "decentralized" in the Web3 sense. Easy to deploy, easy to seize.
did:keyThe public key itselfFreeSelf-contained, no resolution network needed. Cannot rotate keys without changing the DID. Good for ephemeral subjects.
did:ionBitcoin (Sidetree)Bitcoin tx fees, complex node opsCensorship-resistant, but resolution requires running a Sidetree node or trusting one. Microsoft scaled back operational support in 2024.
did:ethrEthereumGas to register/updateDecentralized in the ledger sense; depends on Ethereum's continued operation and gas economics. Public ledger means analytics on identity activity.
did:plcBluesky's central directoryFreeUsed by ATProto/Bluesky. Despite being called decentralized, the directory is operated by one company. Honest about the centralization.

did:web resolution in plain English

  1. Verifier sees a credential signed by did:web:issuer.example.com.
  2. Verifier converts the DID to a URL: https://issuer.example.com/.well-known/did.json (path-style: did:web:issuer.example.com:users:alicehttps://issuer.example.com/users/alice/did.json).
  3. Verifier GETs that JSON. The DID document lists public keys.
  4. Verifier finds the key referenced in the credential's proof.verificationMethod and checks the signature.

The honest centralization concern

did:web is not decentralized in the cryptographic-anchor sense. If example.com's DNS is hijacked, the cert is mis-issued, or the registrar suspends the domain, the DID fails (or gets silently replaced). did:web buys you DID-spec compatibility and credential portability; it does not buy you censorship resistance. For a security-engineering audience that's fine — just don't oversell it.

What a Verifiable Credential (VC) is

A Verifiable Credential (W3C VC Data Model 2.0) is a tamper-evident JSON-LD document that an issuer signs about a subject. The minimal shape:

  • @context — JSON-LD vocabularies (always includes https://www.w3.org/ns/credentials/v2)
  • type — array starting with VerifiableCredential
  • issuer — the issuer's DID
  • validFrom / validUntil — ISO 8601 timestamps (VC 2.0 renamed issuanceDate/expirationDate)
  • credentialSubject — the claims about the holder
  • proof — cryptographic signature (Data Integrity, JWS, etc.)

What this demo does and does not do

Demo doesDemo does NOT do
  • Generate Ed25519 / RSA / P-256 keys in the browser
  • Build a syntactically valid did.json document
  • Issue a VC 2.0 JSON-LD credential
  • Sign it with compact JWS (header.payload.signature)
  • Verify a signature against the in-memory public key
  • Bundle multiple VCs into a Verifiable Presentation
  • Actually publish did.json to a server
  • Resolve a real did:web over the network
  • Check revocation status (StatusList2021, etc.)
  • Validate JSON-LD @context URIs
  • Implement the Data Integrity Proof spec exactly (uses simplified JWS)
  • Persist keys (lost on refresh — intentional)

Where to go next

Generate a did:web DID Document

Pick a key type and a domain. The browser generates a real keypair via crypto.subtle.generateKey(), exports the public half to JWK, and embeds it in a sample did.json document. The private key stays in memory only for this tab session.

Resolved DID

DID
URL

Public key (JWK)

did.json document

In production you would host this exact JSON at the URL above. Here it stays in memory.

Ed25519 in crypto.subtle is supported in Chrome 113+, Firefox 130+ and Safari 17+. Older browsers will fall back to RSA-2048 automatically with a status message.

Issue a Verifiable Credential 2.0

Build a W3C VC 2.0 credential and sign it with the keypair generated in the DID Document tab. Signing uses compact JWS (header.payload.signature base64url-encoded). The header's kid points back to the issuer's verification method.

Claims

Key/value pairs that go inside credentialSubject.

Unsigned VC

Signed VC (with proof block)

This demo signs with a single JWS over the canonicalized JSON payload (sorted keys). The Data Integrity proof spec defines a specific canonicalization (URDNA2015) and proof format that is more involved; production verifiers expect that exact format. Treat this as a teaching scaffold, not a conformant issuer.

Verify a Signed Credential

Paste a signed VC produced by the Issue tab (or from another instance of this page). The verifier checks the JWS signature against the public key currently loaded in the DID Document tab, then inspects the credential structure.

Inspection

What this verifier does

  • Parses the credential JSON and pulls the proof.jws field
  • Reconstructs the signing payload (canonicalized credential without the proof block)
  • Calls crypto.subtle.verify() using the in-memory public key
  • Checks validFrom ≤ now ≤ validUntil
  • Reports whether the credential's issuer matches the DID Document's id

What it does NOT do

  • Fetch the issuer's did.json over HTTPS (no network calls in this demo)
  • Walk a key-rotation history
  • Check StatusList2021 / Bitstring Status List for revocation
  • Validate every @context URI resolves
  • Run JSON-LD canonicalization (URDNA2015) the way Data Integrity Proofs require

Skill Portfolio — Verifiable Presentation

A Verifiable Presentation (VP) is a wrapper a holder builds to share one or more credentials with a verifier. It can be signed by the holder (proving possession of the subject DID) and embed the issuer-signed VCs verbatim. This tab demonstrates the bundling pattern.

Credentials in this portfolio

Use Add to portfolio on the Issue tab to add credentials, or paste raw VC JSON below.

Verifiable Presentation JSON

In a real holder wallet, the VP would also be signed by the holder's key (proving the presenter controls the subject DID). This demo emits an unsigned VP for clarity — the issuer-signed VCs inside still carry their own signatures, which is what the verifier checks.