A Verifiable Credential Example, Annotated Field by Field
A typical verifiable credential is a JSON document with an @context, a type such as EmploymentCredential, an issuer, validity dates, a credentialSubject holding the claims, a credentialStatus entry for revocation, and a proof carrying the issuer's signature. Below is a complete W3C VC Data Model 2.0 example, annotated, with the presentation and verification steps.
The example credential
Here is an employment credential that a former employer might issue to a backend engineer when they leave. It follows the W3C Verifiable Credentials Data Model 2.0, which became a W3C Recommendation on 15 May 2025, and is secured with a Data Integrity proof. Domains use the reserved .example suffix, and the long key and signature values are shortened, so treat it as a teaching copy rather than something to paste into production.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"id": "urn:uuid:4a1c7f0e-2b8d-4c6a-9e51-7d3f0b2a9c11",
"type": ["VerifiableCredential", "EmploymentCredential"],
"issuer": {
"id": "did:web:issuer.example",
"name": "Example Labs"
},
"validFrom": "2026-06-30T00:00:00Z",
"validUntil": "2031-06-30T00:00:00Z",
"name": "Employment record",
"description": "Confirms role and dates of employment at Example Labs.",
"credentialSubject": {
"id": "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH",
"employment": {
"role": "Senior Backend Engineer",
"startDate": "2022-03-01",
"endDate": "2026-06-30"
}
},
"credentialSchema": {
"id": "https://issuer.example/schemas/employment.json",
"type": "JsonSchema"
},
"credentialStatus": {
"id": "https://issuer.example/status/3#94567",
"type": "BitstringStatusListEntry",
"statusPurpose": "revocation",
"statusListIndex": "94567",
"statusListCredential": "https://issuer.example/status/3"
},
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "eddsa-rdfc-2022",
"created": "2026-06-30T09:12:44Z",
"verificationMethod": "did:web:issuer.example#key-1",
"proofPurpose": "assertionMethod",
"proofValue": "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGes..."
}
}
Field by field
Every property below is defined by the W3C specification or its companion specs. Only four are required: @context, type, issuer, and credentialSubject. A credential also needs a securing mechanism, here the embedded proof, before anyone can call it verifiable.
@context
The first entry must be https://www.w3.org/ns/credentials/v2, which defines the core vocabulary. The second entry is the spec's examples context. It defines no individual terms of its own: it maps anything otherwise undefined into an examples vocabulary, which is the only reason EmploymentCredential, employment, and role resolve here at all. The spec says that URL is for demonstrations only and not for pilot or production systems: a real issuer publishes its own context at a stable URL that defines those terms properly.
id
An optional, globally unique identifier for this credential. A UUID URN is common. Leaving it out is allowed and can reduce correlation, because a fixed id is something a verifier could track across uses.
type
Must include VerifiableCredential. The second value, EmploymentCredential, tells software what kind of claims to expect. Types are how a verifier decides which business rules to apply.
issuer
Required. Either a URL or an object with an id. Here it is a did:web identifier, which resolves to a DID document hosted at https://issuer.example/.well-known/did.json, tying the issuer's keys to a domain it controls. The name is for display only and proves nothing by itself.
validFrom and validUntil
Both optional. They replaced issuanceDate and expirationDate from version 1.1. They describe when the claims are meant to be valid, not when the proof was created; that sits in proof.created.
name and description
Optional labels for wallets to display. No security weight.
credentialSubject
Required. The claims themselves. The id is the subject's identifier, here a did:key the candidate controls, which lets the candidate later prove the credential is theirs. Everything else inside is issuer-defined data: role and dates, not salary or performance, because a credential should carry only what verifiers need.
credentialSchema
Optional. Points to a JSON Schema so a verifier can reject malformed claims early. The spec requires both an id URL and a type.
credentialStatus
Optional but important for hiring. A BitstringStatusListEntry, defined in the W3C Bitstring Status List Recommendation, says: fetch the list at statusListCredential and read the bit at position 94567. A set bit with statusPurpose revocation means the issuer has withdrawn the credential. Other purposes include suspension, which is reversible.
proof
The issuer's signature. type is DataIntegrityProof, cryptosuite names the algorithm suite (eddsa-rdfc-2022 is an EdDSA suite), verificationMethod names the exact key, proofPurpose assertionMethod says the key is being used to make claims, and proofValue holds the multibase-encoded signature over the rest of the document.
What the candidate sends: a verifiable presentation
A hiring team rarely receives the bare credential. The candidate's wallet wraps it in a verifiable presentation and signs that wrapper with the candidate's own key:
{
"@context": ["https://www.w3.org/ns/credentials/v2"],
"type": ["VerifiablePresentation"],
"holder": "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH",
"verifiableCredential": [ "...the signed credential above, unchanged..." ],
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "eddsa-rdfc-2022",
"verificationMethod": "did:key:z6MkpTHR8VNs...#z6MkpTHR8VNs...",
"proofPurpose": "authentication",
"challenge": "8f2b6c1e-one-time-value-from-the-verifier",
"domain": "https://careers.employer.example",
"proofValue": "z3FXQjecWufY46yg5abdVZsXqLhxhueuSoZgNSARiKBk..."
}
}
Three details do the work. holder matches the credentialSubject id, so the person presenting is the person the claims are about. proofPurpose is authentication rather than assertionMethod, because the candidate is proving control of a key, not making claims. challenge and domain are values the verifier supplied for this session; Data Integrity defines them to stop a captured presentation being replayed somewhere else.
What the verifier checks, in order
- Shape. Parse the JSON, confirm the v2 context comes first, confirm the type values, and optionally validate the claims against credentialSchema.
- Issuer key. Resolve did:web:issuer.example, find key-1, and confirm it is listed under assertionMethod in the DID document. A key listed only for authentication should not be accepted for issuing.
- Issuer signature. Recompute the signed data and check proofValue against that public key. Any edited character, such as a changed endDate, breaks the check.
- Validity window. Confirm the current time falls between validFrom and validUntil.
- Status. Fetch the status list credential, verify its own proof, and read bit 94567. The list covers many credentials, so the fetch does not reveal which one is being checked.
- Presentation. Verify the holder's signature, confirm challenge and domain match what this verifier issued, and confirm holder equals credentialSubject.id.
- Validation. Decide whether this issuer is trusted to make employment claims. The specification separates this business judgement from cryptographic verification.
What the example does not prove
The specification states plainly that verifiability does not imply the claims are true. This credential proves that whoever controls issuer.example signed a statement that the subject held a role between two dates. It does not prove the engineer was good at the job, or that issuer.example is a real company rather than a domain registered last week. That last gap is why step 7 exists, and why teams that accept credentials keep a list of issuers they trust for each kind of claim.
Variations you will meet
- Version 1.1 credentials use the https://www.w3.org/2018/credentials/v1 context with issuanceDate and expirationDate. Many systems still emit them.
- JOSE or COSE secured credentials carry the same claims but are signed as a JWT or CBOR envelope instead of an embedded proof block, under the W3C VC JOSE COSE specification.
- SD-JWT credentials hash each claim so the holder can reveal only some of them, for example dates without the job title.
- Open Badges 3.0, from 1EdTech, builds course and skill badges on the verifiable credentials data model, so badge platforms can emit credentials shaped much like this one.
Frequently asked questions
- Which fields are required in a verifiable credential?
- Under VC Data Model 2.0, a credential must have @context with the v2 context first, a type that includes VerifiableCredential, an issuer, and a credentialSubject. To be verifiable it also needs a securing mechanism, either an embedded proof such as Data Integrity or an envelope such as JOSE or COSE. Everything else, including id, validFrom, validUntil, credentialStatus, and credentialSchema, is optional.
- What is the difference between a credential and a presentation?
- A credential is the issuer's signed statement about a subject. A presentation is what the holder sends to a verifier: one or more credentials wrapped together, usually signed with the holder's own key and bound to a challenge the verifier supplied. The credential proves who made the claim; the presentation proves the person sending it controls the subject's key and is not replaying an old copy.
- Does credentialSubject.id have to be a DID?
- No. The specification allows any URL as an identifier, and the subject id can be left out entirely, which makes the credential a bearer credential that whoever holds it can present. DIDs are common because they give the holder a key to sign presentations with. For hiring, a subject id the candidate can prove control of is much more useful than a bearer credential.
- Can the examples context be used in a real deployment?
- No. The W3C specification says https://www.w3.org/ns/credentials/examples/v2 exists to demonstrate examples and should not be used in pilot or production systems. Issuers are expected to publish their own context at a stable URL that defines their custom terms, so verifiers interpret fields such as role or startDate the same way the issuer intended.