Skip to content
Registry StackDocsv0.46.0

Request evidence as an SD-JWT VC

For the assertion provider and consumer or verifier

View as Markdown

If your relying parties expect a Selective Disclosure JWT Verifiable Credential (SD-JWT VC), permit that representation for adult-status, then request and verify one. You continue in the project from Assert a role-bound relationship, with the source and Registry Evidence still running, and finish by stopping both and reading the audit.

Outcome
A verified SD-JWT VC adult-status response, a refused tampered copy, and the audit of the request.
Time
About 10 minutes
Level
Local development with synthetic data
Prerequisites
The project, source, and Registry Evidence left running by Assert a role-bound relationship

Registry Evidence reads the project only as it starts. In first-evidence-assertion/adult-status, stop it while you change the project; the source keeps running:

Terminal window
rstack evidence dev stop .
Local Evidence stopped

A definition’s representations lists the encodings it may emit. Add sd-jwt-vc to adult-status:

evidence.yaml
subjectBinding: audience-scoped
representations:
- signed-jws
- sd-jwt-vc
observationTimezone: Asia/Bangkok

Add it to the adult-status grant too:

dev-authority.yaml
- standalone-service
grants:
- definition: adult-status
purpose: age-check
audienceFrom: authenticated-requester
representations:
- signed-jws
- sd-jwt-vc
subjectBinding: audience-scoped

Both lists must name it. The grant belongs to the standalone-service profile, so every client on that profile, tutorial-client and example-caller alike, may now ask for the SD-JWT VC representation. Check the project:

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

Start Registry Evidence again with the same ports, so it loads the changed definition and grant:

Terminal window
rstack evidence dev start . \
--target local-target.yaml \
--evidence-port 18080 \
--issuer-port 8082
Evidence ready at http://127.0.0.1:18080

Name the representation with --response-format, send the SD-JWT VC media type, and verify the response:

Terminal window
rstack evidence request prepare adult-status \
--client tutorial-client \
--purpose age-check \
--subject subject:record-id=adult \
--response-format sd-jwt-vc \
--name adult-status-vc
rstack evidence api /v1/evidence \
--client tutorial-client \
--input .evidence/requests/adult-status-vc/request.json \
--accept application/dc+sd-jwt \
--output adult-status.sd-jwt-vc
rstack evidence verify adult-status.sd-jwt-vc \
--context .evidence/requests/adult-status-vc/verification.json \
--output adult-status-vc.verified.json
VERIFIED

Print the value as you did for the signed JWS:

Terminal window
jq '{supportsRequirement, supportedValues}' adult-status-vc.verified.json
{
"supportsRequirement": "urn:example:requirement:adult-status:v1",
"supportedValues": [
{
"providesValueFor": "urn:example:concept:adult-status:v1",
"value": true
}
]
}

The representation changes the encoding, not the answer.

Each claim travels as a disclosure after a ~, and the signature covers its digest. Change one byte of the first disclosure in a copy:

Terminal window
python3 - <<'PY'
from pathlib import Path
parts = Path("adult-status.sd-jwt-vc").read_text().strip().split("~")
parts[1] = ("A" if parts[1][0] != "A" else "B") + parts[1][1:]
Path("adult-status-tampered.sd-jwt-vc").write_text("~".join(parts) + "\n")
PY

Verification refuses the copy:

Terminal window
rstack evidence verify adult-status-tampered.sd-jwt-vc \
--context .evidence/requests/adult-status-vc/verification.json \
--output adult-status-tampered.verified.json
evidencectl: Evidence response verification failed

Registry Evidence wrote an audit event before it read the source and another before the response left. rstack evidence audit show reads them only from a stopped session, so stop it and show the last operation, your SD-JWT VC request:

Terminal window
rstack evidence dev stop .
rstack evidence audit show --last-operation
ACCESS AUTHORIZED adult-status age-check requester=<pseudonym>
DISCLOSURE RELEASED adult

A pseudonymous requester was authorized for adult-status under age-check, and the adult output was released. The value is not shown.

dev clean removes the stopped session’s generated state, including those audit files. The project, its keys, and its clients stay:

Terminal window
rstack evidence dev clean .
Removed stopped local Evidence state

Press Ctrl+C in the source’s terminal to stop the source.

Request Evidence from your application