OpenID4VP (verifier)

This module is the verifier counterpart to b.auth.oid4vci. The relying party (verifier) builds an authorization request asking the wallet for one or more verifiable presentations; the wallet replies with a vp_token carrying the SD-JWT VC presentations plus a presentation_submission (legacy Presentation Exchange 2.0) OR no submission when DCQL is used.

DCQL (OpenID4VP 1.0 §6) is the JSON-shaped query language that replaces Presentation Exchange's JSONPath-soup. Two top-level keys:

credentials: [ { id: "id-card", format: "vc+sd-jwt", meta: { vct_values: ["https://example.com/vct/identity"] }, claims: [ { path: ["given_name"] }, { path: ["birthdate"], values: ["1990-01-15"] }, ], }, ], credential_sets: [ { options: [["id-card"], ["passport"]], required: true }, ]

The verifier-side primitives:

b.auth.oid4vp.verifier.create({ ... }) .createRequest({ dcql, audience, nonce, responseUri }) .verifyResponse({ vpToken, dcql, audience, nonce }) .matchDcql(presentations, dcql) // structural-only check

verifyResponse composes b.auth.sdJwtVc.verify (with requireKeyBinding: true and the DCQL-claim filter applied to the disclosed-claim set), then runs matchDcql to confirm the wallet's selection satisfies the query.

b.auth.oid4vp.matchDcql(presentations, dcql) #

stable0.8.62

Structural matcher: confirms the wallet's selected presentations (each with its DCQL id + verified claims) satisfy the DCQL query. Returns { valid, matched, errors }. Operators wanting to implement their own verifier transport call this directly after SD-JWT VC verification.

Claim path pointers follow OpenID4VP 1.0 §7.1.1: a string segment selects an object property, a non-negative integer indexes an array, and a null segment matches any element of the array at that depth (e.g. ["degrees", null, "type"] matches the type claim of any element in the degrees array). A null segment applied to a non-array node is a non-match.

var match = b.auth.oid4vp.matchDcql([
  { id: "id-card", format: "vc+sd-jwt", claims: { vct: "...", given_name: "Alice" } }
], dcqlQuery);
if (!match.valid) throw new Error(match.errors.join(", "));

b.auth.oid4vp.verifier.create(opts) #

stable0.8.62
{
  {
    clientId:           string,     // required
    responseUri:        string,     // where the wallet POSTs vp_token (RP-side)
    issuerKeyResolver:  fn(header)→keyOrJwk,  // resolves SD-JWT VC issuer signing key
    audience?:          string,     // override aud claim (defaults to clientId)
    keyAttestationVerifier?: fn,
  }
}

Build an OID4VP verifier. Returns helpers for emitting an authorization request with a DCQL query and parsing the wallet's signed vp_token response.

var verifier = b.auth.oid4vp.verifier.create({
  clientId:          "verifier-1",
  responseUri:       "https://verifier.example/vp",
  issuerKeyResolver: async function (header) { return jwksByKid[header.kid]; },
});

b.auth.oid4vp.verifier.createRequest(opts) #

0.8.62
{
  {
    dcql:           object,      // DCQL query — required
    responseMode?:  string,      // default "direct_post"
    nonce?:         string,
    state?:         string,
    aud?:           string,
  }
}

Build the OID4VP authorization request body. Operators sign + post the JWT (via PAR) or render it as an openid4vp:// deep-link.

var rv = verifier.createRequest({
  dcql: {
    credentials: [{ id: "id-card", format: "vc+sd-jwt", claims: [{ path: ["given_name"] }] }],
  },
});
// → { request, nonce, state }

b.auth.oid4vp.verifier.verifyResponse(opts) #

0.8.62
{
  {
    vpToken:                object|string,
    dcql:                   object,
    nonce:                  string,
    requireKeyAttestation?: boolean,
  }
}

Parse the wallet's vp_token response, verify each SD-JWT VC presentation (signature + KB-JWT + nonce + audience), and run the DCQL matcher. Returns { valid, presentations: [{ id, claims, ... }], matched, errors }

The vp_token may be a single string OR an array of strings. The legacy Presentation Exchange presentation_submission is accepted but not consumed — DCQL is the canonical query path.

var result = await verifier.verifyResponse({
  vpToken: req.body.vp_token,
  dcql:    storedDcql,
  nonce:   storedNonce,
});
// → { valid, presentations, matched, errors }

Last updated 2026-08-08T16:39:49.652Z by seeder.