Skip to content
Registry StackDocsDevelopment (unreleased)

Enable SD-JWT VC

For the assertion provider and consumer or verifier

View as Markdown

If you operate an Evidence project and one assertion definition must answer as an SD-JWT VC, you decide two things once the representation is permitted: which values a holder may keep or drop, and whether the response is bound to the holder’s key. You continue in first-evidence-assertion/adult-status, the project from Request evidence as an SD-JWT VC, with Evidence Gateway stopped and its state cleaned.

A definition answers as SD-JWT VC only when sd-jwt-vc is in its representations and in the grant a caller acts under. That caller then sends Accept: application/dc+sd-jwt and receives the same assertion, serialized as an SD-JWT VC; a caller whose grant lacks it still receives signed JWS. Two choices change what that caller can do with the response:

  • The disclosure shape decides which values the holder can present separately.
  • The subject binding decides who the response means something to: the relying party that requested it (audience-scoped), or whoever proves possession of the holder’s key (holder-bound). A holder-bound definition has no signed JWS representation, so every caller must send holder keys.

Each output travels as a disclosure, a salted claim the holder may keep or drop. An output without sdJwtVc is one disclosure named by its concept URI, which is what adult, a boolean, needs.

To present the fields of a structured value separately, give that output an sdJwtVc block. The output then appears under claim, a unique name of at most 64 characters, and each direct field becomes its own disclosure; a nested object stays one. top-level is the only disclosure value. Only a reviewed-structured-value output may declare sdJwtVc; on any other type rstack evidence check refuses with output-projection-type, because a scalar has no fields to split.

adult-status declares subjectBinding: audience-scoped, and the project checks clean:

Terminal window
rstack evidence check . --target local-target.yaml
0 errors, 0 warnings in 1 file

Declare holder-bound instead, and keep only sd-jwt-vc:

evidence.yaml
subjectBinding: audience-scoped
subjectBinding: holder-bound
representations:
- signed-jws
- sd-jwt-vc
Terminal window
rstack evidence check . --target local-target.yaml
each complete grant must stay inside every definition ceiling

The definition is now a ceiling its grants exceed: both adult-status grants in dev-authority.yaml still permit an audience-scoped JWS. Narrow the standalone-service grant, then the age-checker-service one:

dev-authority.yaml
representations:
- signed-jws
- sd-jwt-vc
subjectBinding: audience-scoped
subjectBinding: holder-bound
dev-authority.yaml
- age-checker-service
grants:
- definition: adult-status
purpose: age-check
audienceFrom: authenticated-requester
representations:
- signed-jws
subjectBinding: audience-scoped
- sd-jwt-vc
subjectBinding: holder-bound
Terminal window
rstack evidence check . --target local-target.yaml
Evidence project check: complete
Project: .
Target: local-target.yaml
0 errors, 0 warnings in 1 file

A request for adult-status now carries holderKeys. Each key becomes the cnf claim of its response and scopes the subject binding, and the response names no audience. A caller that still asks for signed JWS is refused before any source is contacted. The relying party checks the holder’s key-binding JWT against the cnf key with evidence verify-presentation.

An SD-JWT VC response is a second encoding of the same stateless assertion, so Registry Evidence keeps no issuance session, status list, or revocation for it. The frozen SD-JWT VC profile pins RFC 9901 and SD-JWT VC draft 18. Relying parties verify against keys they pinned themselves; /.well-known/jwt-vc-issuer is discovery, not a trust anchor. A deployment target may cap formats with responseFormats; see the configuration reference.

Deliver to a wallet