SD_JWT_VC). It is a signed JSON Web Token with one extra idea: claims can be hidden behind fingerprints, so the holder can reveal some and withhold others without breaking the issuer’s signature.
The structure
An SD-JWT is a chain of parts separated by~:
At issuance, the holder receives the issuer-signed JWT and every disclosure. At presentation, the holder sends the JWT, only the disclosures the verifier asked for, and a fresh holder signature.
The issuer-signed JWT
The JWT header names the algorithm (RS256 or ES256), the type dc+sd-jwt, and the signing key as a DID URL such as did:web:issuer.example#key-1.
The payload carries:
Claims the issuer did not mark as hideable sit in the payload in plain view.
How a claim is hidden and revealed
The issuer decides which claims are hideable, per credential type (itsdisclosureFrame). In direct issuance, every top-level claim is hideable by default. Nested claims such as address.city can be hidden individually.
A worked example for the claim tier: Gold:
Why it is safe:
- The issuer’s signature still holds. It covers the fingerprints, so revealing or withholding a disclosure does not touch the signed part.
- A revealed value cannot be faked. A different value produces a different fingerprint that is not in
_sd. - A hidden value cannot be guessed. Without the random salt, a verifier cannot fingerprint candidate values, such as every tier name, and look for a match.
isOver18 claim or uses Iden3.
How holder binding works
Holder binding stops a copied credential from being presented by someone else.- At issuance, AIR gives the issuer the user’s public signing key (EC P-256), and the issuer writes it into
cnf.jwkbefore signing. Every AIR-issued credential has it, on both on-demand and direct issuance. - At presentation, the verifier sends a one-time challenge (nonce). The user’s device signs a key-binding JWT (
kb+jwt,ES256) with the matching private key. It contains:nonce: the verifier’s challenge, so the presentation cannot be replayedaud: the verification program ID, so it cannot be reused for another programiat: when it was signed, so stale presentations can be rejectedsd_hash: a SHA-256 of the JWT and the exact disclosures sent, so none can be added or removed
- The verifier checks the key-binding JWT against
cnf.jwkfrom the issuer-signed JWT.
How verifiers find the issuer’s keys
The issuer’s identity isdid:web:<issuer host>. A verifier turns it into a URL, https://<issuer host>/.well-known/did.json, fetches the DID document, and takes the public keys listed under assertionMethod. It selects the one named by the JWT header’s kid.
The same keys are also published as SD-JWT VC issuer metadata at /.well-known/jwt-vc-issuer. No central registry, and no call to AIR, is involved. Verifiers should still accept only issuers on their own allowlist.
How status is published
The credential carries two hooks for revocation:nonce, the revocation number, which a verifier can look up at the issuer’s revocation status endpoint.status.status_list, when the issuer publishes an IETF Token Status List: a partition URL and a bit position. The list is a JWT signed with the same issuer key.
Standards
Trade-offs
For the exact token format and a backend implementation, see Verify with SD-JWT.