Build a verifier
You run the relying-party side — a bar, an airport, a website. You ask the resident's wallet to present just what you need, then verify the proof, over the same VCALM exchange loop the wallet speaks.
You'll do exactly 3 things
- Expose an interaction URL that advertises
vcapi. - When the wallet POSTs to start, respond with a
verifiablePresentationRequestfor only the fields you need. - Receive the
verifiablePresentationand verify its proof, challenge, and domain.
1. Request only what you need
Don't ask for the whole license. Request a single attribute — here, proof of age — so the resident reveals nothing more:
{
"verifiablePresentationRequest": {
"query": [{
"type": "QueryByExample",
"credentialQuery": [{
"reason": "Please prove you are over 21 to continue.",
"example": {
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/vc/mdl/v1"
],
"type": "Iso18013DriversLicenseCredential"
},
"trustedIssuer": [{
"required": true,
"issuer": "did:web:dmv.state.example"
}]
}]
}],
"challenge": "3182bdea-63d9-11ea-b6de-3b7c1404d57f",
"domain": "checkout.example"
}
}
With selective disclosure, a well-built wallet returns a derived proof of
"over 21" — not the birthdate itself. The challenge and
domain stop a captured presentation from being replayed.
2. Receive the presentation
The wallet POSTs the signed presentation back to the same exchange URL:
{
"verifiablePresentation": {
"@context": ["https://www.w3.org/ns/credentials/v2"],
"type": ["VerifiablePresentation"],
"holder": "did:example:resident123",
"verifiableCredential": [{ "...": "derived proof: age_over_21 = true" }],
"proof": {
"challenge": "3182bdea-63d9-11ea-b6de-3b7c1404d57f",
"domain": "checkout.example",
"...": "holder signature"
}
}
}
3. Verify the proof
Before you trust the result, check all of the following:
- The presentation proof is valid and the
challenge/domainmatch what you sent. - The credential's proof is valid and the issuer is the DMV you trust.
- The license is not revoked or suspended — check its status.
- The license is unexpired and the disclosed claim answers your request.
That's it
A conformant relying-party verifier is this exchange: request, receive, verify. The cryptographic verification is your verifier instance's job — the coordinator just runs the exchange.
Prefer a library to raw HTTP?
Verifier-side helpers live in Digital Bazaar's Bedrock VC modules. A dogfooded standalone VCALM client is planned; until it ships, the HTTP flow above is the supported path.