Why Revocation Matters
Credentials may need to be invalidated before their expiry date. A university might rescind a degree, an employer might terminate employment, or a government might suspend a license. The credentialStatus property enables verifiers to check the current status of a credential.
Issuer Controlled
Only the issuer can change credential status. Holders cannot self-revoke.
Privacy Preserving
Status lists use herd privacy - checking one status reveals nothing about others.
Efficient Checking
Bitstring compression allows thousands of status entries in a single fetch.
Multiple Purposes
Support for revocation, suspension, and custom status messages.
Bitstring Status List
The BitstringStatusListEntry mechanism uses a compressed bitstring where each credential is assigned an index. A bit value of 1 means the credential has the status (e.g., revoked), while 0 means it doesn't.
Credential with Status
Each credential includes a credentialStatus property pointing to its position in a status list.
{
"@context": [
"https://www.w3.org/ns/credentials/v2"
],
"id": "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c5",
"type": ["VerifiableCredential", "UniversityDegreeCredential"],
"issuer": "did:example:issuer",
"validFrom": "2024-01-01T00:00:00Z",
"credentialSubject": {
"id": "did:example:holder",
"degree": {
"type": "BachelorDegree",
"name": "Computer Science"
}
},
"credentialStatus": {
"id": "https://example.edu/status/24#94567",
"type": "BitstringStatusListEntry",
"statusPurpose": "revocation",
"statusListIndex": "94567",
"statusListCredential": "https://example.edu/status/24"
}
}Status List Credential
The status list itself is a verifiable credential containing a compressed bitstring in the encodedList property.
{
"@context": [
"https://www.w3.org/ns/credentials/v2"
],
"id": "https://example.edu/status/24",
"type": ["VerifiableCredential", "BitstringStatusListCredential"],
"issuer": "did:example:issuer",
"validFrom": "2024-01-01T00:00:00Z",
"credentialSubject": {
"id": "https://example.edu/status/24#list",
"type": "BitstringStatusList",
"statusPurpose": "revocation",
"encodedList": "H4sIAAAAAAAAA-3BMQ0AAADCIJ..."
}
}Key Properties
- statusListIndex
- Position of this credential in the bitstring
- statusListCredential
- URL of the status list credential to fetch
- statusPurpose
- What the status bit indicates (revocation, suspension)
- encodedList
- GZIP-compressed, base64-encoded bitstring
Status Purposes
Different status purposes indicate different meanings when the bit is set. A credential can reference multiple status lists for different purposes.
| Purpose | Meaning | Use Case |
|---|---|---|
| revocation | Credential has been permanently revoked and should not be accepted | Degree rescinded, license permanently revoked |
| suspension | Credential is temporarily invalid but may be reinstated | License suspended, membership on hold |
| message | Signal specific information without invalidating credential | Request for contact, pending update notification |
Verification Flow
When verifying a credential with status, the verifier must check the status list.
1 Extract Status Entry
Get statusListCredential URL and statusListIndex from the credential's credentialStatus property.
2 Fetch Status List
Retrieve the status list credential from the URL. Cache appropriately to reduce network requests and improve privacy.
3 Verify Status List Credential
Verify the status list credential's signature and check it was issued by the same issuer as the original credential.
4 Decode and Check Bitstring
Base64 decode, GZIP decompress the encodedList, then check the bit at the specified index.
5 Apply Status
If bit is 1, apply the statusPurpose (reject if revoked, warn if suspended).
async function checkStatus(credential) {
const status = credential.credentialStatus;
if (!status) return { valid: true };
// Fetch status list (with caching)
const statusList = await fetch(status.statusListCredential);
// Verify status list credential
await verifyCredential(statusList);
// Decode bitstring
const bits = gunzip(base64Decode(statusList.credentialSubject.encodedList));
// Check bit at index
const index = parseInt(status.statusListIndex);
const isSet = (bits[Math.floor(index / 8)] >> (index % 8)) & 1;
return {
valid: isSet === 0,
purpose: status.statusPurpose,
status: isSet ? status.statusPurpose : 'active'
};
}Privacy Considerations
While bitstring status lists provide herd privacy (fetching the list doesn't reveal which credential is being checked), there are still privacy considerations to address.
Issuer Tracking
Issuer could log status checks to track when credentials are used
Mitigation: Use privacy proxies, cache status lists, or third-party status services
Verifier Correlation
Multiple verifiers could correlate activity via status list index
Mitigation: Use unlinkable status mechanisms or randomized indices
Status List Size
Small status lists may reveal information about issuer volume
Mitigation: Use appropriately sized lists with padding
Timing Analysis
Status check timing could reveal credential usage patterns
Mitigation: Implement background caching with random refresh intervals
Privacy Best Practices
- Cache status lists aggressively
- Use CDNs or proxies for status fetching
- Randomize status check timing
- Consider offline status verification
Caching Strategy
- Respect HTTP cache headers
- Pre-fetch during idle time
- Balance freshness vs privacy
- Consider local status caches