Skip to content

feat: add PEX support for OID4VP presentations - #370

Open
romitshah02 wants to merge 2 commits into
Sunbird-RC:mainfrom
romitshah02:pex-support
Open

romitshah02 wants to merge 2 commits into
Sunbird-RC:mainfrom
romitshah02:pex-support

Conversation

@romitshah02

@romitshah02 romitshah02 commented Aug 24, 2026 •

Copy link
Copy Markdown
Contributor

Description

Adds DIF Presentation Exchange (PEX) v2.0 support to oid4vc-service's OID4VP verifier flow, as an alternative query language to the existing DCQL-only implementation. Enables live VP round trips against wallets (e.g. Inji) that implement PEX but not DCQL. Also fixes real holder-binding and key-selection bugs surfaced by testing against a live wallet, and adds JsonWebSignature2020 proof verification + local did:jwk resolution to credentials-service.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Refactor / Technical Debt
  • Test case addition/update

Microservice(s) Affected

  • oid4vc-service
  • credentials-service

Changes

oid4vc-service — PEX support:

  • New PexService (pex.service.ts): full DIF PEX v2.0 evaluator — input_descriptors[].constraints.fields path/filter matching, format restriction, submission_requirements (pick/all, from/from_nested)
  • New shared jsonpath.util.ts: minimal JSONPath subset (dot/bracket segments, numeric indices) used by both PexService and descriptor-map resolution
  • oid4vp.service.ts: VpTxn.queryMode: 'dcql' | 'pex' — request accepts presentation_definition as a mutually-exclusive alternative to dcql_query; submitResponse() branches per mode; per-credential verification extracted into a shared verifyPresentationEntry() used by both DCQL and PEX loops
  • resolveDescriptorMapEntry(): resolves descriptor_map[].path / path_nested chains against the wallet's vp_token
  • normalizePexVpToken(): absorbs PEX's vp_token shape (raw presentation, not always JSON, unlike DCQL's always-object shape)

Bug fixes (found via live wallet testing):

  • resolveDescriptorMapEntry() no longer descends into path_nested when the outer format is ldp_vp — descending discarded the outer VP's holder-binding proof and exposed only the embedded VC's static issuance-time proof
  • Holder DID comparison strips the verification-method #fragment (did:jwk:...#0 vs the bare DID) before comparing to credentialSubject.id
  • oid4vci.service.ts: issuer metadata now advertises EdDSA in proof_types_supported.jwt.proof_signing_alg_values_supported (previously ES256 only) — some wallets hardcode Ed25519 for presentation-signing independent of their issuance-time key selection, so the issuer must advertise EdDSA for that key to ever be selectable at issuance

credentials-service:

  • verifyCredential() dispatches to a new verifyPresentation() path when type includes VerifiablePresentation, instead of only ever treating the body as a bare VC
  • New jws2020.util.ts: hand-rolled JsonWebSignature2020 Linked-Data proof verifier (URDNA2015 canonicalization + detached JWS per RFC7797) — no installed suite covers this proof type
  • New self-contained-did.util.ts: local did:jwk resolution (public key is the DID's own base64url JWK payload, no network lookup)

Notes

  • No new runtime dependency — PEX evaluator is hand-rolled, mirroring DcqlService's existing non-library approach
  • No schema/DB change, no new top-level API route — presentation_definition is an additive, mutually-exclusive alternative field on the existing POST /vp/request body
  • Three behavior changes affect pre-existing DCQL callers, not just new PEX requests (detailed in the design doc): QR/qr_data link is now returned by-value instead of always by-reference; issued VC @context now rewrites internalUrl → publicUrl for all issuance; ldp_vc plain-VP-object holder binding is stricter (credentialSubject.id must equal the VP's holder, not merely exist)

@romitshah02 romitshah02 changed the title Pex support feat: add PEX support for OID4VP presentations Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant