Microsoft Entra / Credential Status
Revocation Is the Hard Part
Issuing is easy; keeping credentials current without leaking who asked is the challenge.
Issuing verifiable credentials is straightforward: define a claim, sign it, return it to the holder. Revocation is harder: you need to detect when a credential should no longer be accepted, ideally without creating a surveillance channel that reveals who asked and when.
The failure mode
A verifier calls a central revocation endpoint for every check. The endpoint sees who asked (IP or key), when, for which credential ID, and what outcome occurred. Even if the credential is privacy-preserving, the revocation lookup becomes a “phone home” channel that leaks context. Users and regulators won’t love that.
What I learned
Understand the revocation design space
Status list (offline)
The issuer publishes a privacy-preserving list of credential status values (for example, a bitstring status list) that verifiers fetch periodically. Verification checks against the local list.
Online status check
The verifier queries a status endpoint per credential. Freshness improves; privacy worsens.
Holder stapling
The holder obtains a fresh status attestation and presents it along with the credential. The verifier checks the stapled proof without contacting the issuer per verification.
Short-lived credentials:
Expire credentials quickly so revocation windows are short. This reduces reliance on revocation checks.
Privacy-preserving lists: batch and compress
A status list can represent many credentials without revealing individual identities. Verifiers download the list on a schedule (e.g., every policy-defined freshness window), cache it locally, and check bits/entries offline. Lists can be partitioned or hashed to limit list size.
Stapling shifts “phone home” to holder flow
With stapling, the holder requests a status proof from the issuer (or a delegated service) at a cadence, then presents it to verifiers. This avoids per-verification lookups by verifiers but still requires the holder to contact the issuer on some schedule. The privacy difference is who calls whom and when.
Short-lived credentials reduce time at risk
If credentials expire quickly, revocation needs are less acute. This shifts load from revocation infrastructure to issuance (more frequent renewals). Combine with holder stapling to keep verification fast and private.
Model cache freshness and failure modes
Verifiers should track the freshness of status lists. If a list is too old (e.g., beyond your policy window), treat the result as “unverifiable” rather than “accepted,” and prompt re-fetch or stapling. Distinguish “cache stale” from “revoked.”
Avoid per-ID URLs in logs
If you must hit an online status endpoint, avoid logging per-ID lookups in a way that identifies a particular holder or verifier. Aggregate metrics instead. Keep any necessary identifiers hashed or pseudonymous.
Distinguish revocation from expiry and audience
Revocation says “this specific credential is no longer valid.” Expiry says “credentials of this type are only valid until T.” Audience says “this verifier is permitted to consume the claim.” Don’t overload revocation with other policy failures.
Illustrative status-list freshness check
from dataclasses import dataclass
from datetime import datetime, timezone
@dataclass(frozen=True)
class StatusSnapshot:
fetched_at: datetime
bits: bytes
def is_fresh(snapshot: StatusSnapshot, max_age_seconds: int) -> bool:
age = datetime.now(timezone.utc) - snapshot.fetched_at
return age.total_seconds() <= max_age_seconds
# Choose the freshness window from policy and operational requirements.
# Stale status should have an explicit outcome, such as "unverifiable".
Trade-offs and failure modes
Trade-offs
Offline lists vs freshness: Lists preserve privacy but can be stale. Address with frequent, batched updates.
Stapling vs issuer load: Stapling shifts calls to holders; issuer still handles periodic status proofs. Load is manageable with caching and rate limits.
Short-lived credentials vs user friction: Frequent renewals add UX overhead. Balance with clear prompts and automated refresh flows.
Failure modes
“Phone home”: Per-verification lookups leak context. Solution: offline lists or stapling.
“Stale cache”: Verifiers use outdated lists. Solution: freshness checks and policy windows that treat stale as “unverifiable.”
“Revocation conflation”: Treating expiry or audience failure as revocation. Solution: separate policy checks.
Try it yourself
Implement an offline status list with a freshness window. Treat stale lists as “unverifiable.”
Add holder stapling to your demo: the holder fetches a status proof and presents it alongside the credential.
Track performance for offline list checks vs online status calls. Compare privacy and tail behavior.