-
Notifications
You must be signed in to change notification settings - Fork 0
SD JWT VC
SD-JWT VC lets
an issuer mark claims as selectively disclosable: the holder later presents
only the claims it chooses, and proves possession of the key the credential
was bound to (cnf) with a Key Binding JWT over the verifier's aud +
nonce.
from openvc.keys import Ed25519SigningKey
from openvc.proof.sd_jwt import SdJwtVcProofSuite
issuer = Ed25519SigningKey.generate(kid="https://issuer.example#key-1")
holder = Ed25519SigningKey.generate(kid="holder-key-1")
suite = SdJwtVcProofSuite()
# Issue: given_name and age are selectively disclosable; cnf binds the holder key.
sd_jwt = suite.issue(
{"iss": "https://issuer.example", "given_name": "Ada",
"family_name": "Lovelace", "age": 36},
signing_key=issuer, disclosable=["given_name", "age"],
holder_jwk=holder.public_jwk(), vct="https://credentials.example/identity")
# Present: the holder signs a KB-JWT over this verifier's aud + nonce.
presentation = suite.create_presentation(
sd_jwt, holder_key=holder, audience="https://verifier.example", nonce="n-123")
# Verify: issuer signature, disclosure digests, KB-JWT, aud/nonce, vct.
result = suite.verify(
presentation, public_key_jwk=issuer.public_jwk(),
audience="https://verifier.example", nonce="n-123", require_key_binding=True,
expected_vct="https://credentials.example/identity")
print(result.vct, result.key_bound, result.claims["given_name"])The pipeline also accepts SD-JWT presentations directly —
verify_credential(presentation, ...) detects the format and resolves the
issuer key from iss (see
Resolving issuer keys).
An issuer can pin the credential type's published
Type Metadata
document with vct#integrity; the verifier resolves the document, checks the
hash, and validates the disclosed claims against the type's claims metadata
(paths + mandatory):
import base64
import hashlib
import json
from openvc.keys import Ed25519SigningKey
from openvc.proof.sd_jwt import SdJwtVcProofSuite
from openvc.type_metadata import validate_type_metadata
VCT = "https://credentials.example.com/education_credential/v1"
type_metadata = {
"vct": VCT,
"name": "Example Education Credential",
"claims": [
{"path": ["name"], "sd": "always", "mandatory": True},
{"path": ["degree"], "sd": "always"},
],
}
metadata_bytes = json.dumps(type_metadata).encode()
integrity = "sha256-" + base64.b64encode(hashlib.sha256(metadata_bytes).digest()).decode()
issuer = Ed25519SigningKey.generate(kid="https://issuer.example#key-1")
holder = Ed25519SigningKey.generate(kid="holder-key-1")
suite = SdJwtVcProofSuite()
issued = suite.issue(
{"iss": "https://issuer.example", "vct#integrity": integrity,
"name": "Ada Lovelace", "degree": "Mathematics"},
signing_key=issuer, vct=VCT, disclosable=["name", "degree"],
holder_jwk=holder.public_jwk())
verified = suite.verify(issued, public_key_jwk=issuer.public_jwk())
result = validate_type_metadata(
verified.claims, vct=verified.vct,
vct_integrity=verified.claims.get("vct#integrity"),
resolve=lambda url: {VCT: metadata_bytes}[url]) # in-memory; real: fetch by URL
print(result.documents[0]["name"], [c["path"] for c in result.claims])In production, resolve Type Metadata over the network with the SSRF-guarded
default — openvc.resolvers.default_type_metadata_resolver — instead of the
in-memory lambda above.
If a credential's credentialStatus (or credentialSchema) must be
enforceable, do not list it in disclosable: a holder could simply omit
the disclosure and the verifier would never see the pointer. Fail-closed
status only works for claims the holder cannot withhold — the same applies to
ecdsa-sd-2023's mandatory pointers (see the
Security model).
📖 Published automatically from the wiki/ directory of the main repository — edits made directly on the wiki are overwritten by the next sync. To change a page, open a PR against wiki/. Every python block on these pages is executed by CI. · API reference · LGPL-3.0-or-later
Start
Proof formats
Verifying in practice
- Presentations & OpenID4VP
- Resolving issuer keys
- Relying-party certificates
- Credential schemas
- Status lists
- Trust anchors: EU TL & EBSI
- Async verification
Walkthroughs
Operating
Reference