Build the SD-JWT issuer: for each claim that should be selectively disclosable, generate a disclosure object {salt, claim_name, claim_value}, base64url-encode it, and replace the claim in the JWT payload with an _sd array of SHA-256 digests of the disclosures
Sign the JWT payload (which contains _sd digests, non-disclosable claims, and the _sd_alg field set to 'sha-256') using RS256 or ES256
Concatenate the signed JWT with the disclosure strings separated by ~ to form the full SD-JWT: <jwt>~<disclosure1>~<disclosure2>~
For holder-bound credentials, include a cnf claim in the JWT with the holder's public key; require the holder to append a Key Binding JWT signed with their key when presenting
At verification, recompute SHA-256 of each disclosure, compare against the _sd digests in the payload, and reconstruct the disclosed claims; reject any digest not found in the payload
For SD-JWT VC specifically, ensure the JWT contains vct (credential type) and that iss is a URL whose well-known metadata endpoint (/.well-known/jwt-vc-issuer) publishes the signing key
Known gotchas
SD-JWT was published as RFC 9901 in November 2025; SD-JWT VC (sd-jwt-vc) is a separate draft (draft-ietf-oauth-sd-jwt-vc) still in progress — implementations targeting EUDI wallet must track the sd-jwt-vc draft version adopted by the ARF
The salt in each disclosure must be at least 128 bits of cryptographic randomness; a predictable salt allows a verifier to brute-force undisclosed claim values
Verification must check the _sd_alg claim and use the specified hash algorithm; defaulting to sha-256 without checking the field will break if the issuer uses a different algorithm
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp