Skip to content

feat(vc2): implement VC 2.0 support - #2827

Open
rmlearney-digicatapult wants to merge 12 commits into
openwallet-foundation:mainfrom
rmlearney-digicatapult:feature/vc2-spec-alignment
Open

feat(vc2): implement VC 2.0 support#2827
rmlearney-digicatapult wants to merge 12 commits into
openwallet-foundation:mainfrom
rmlearney-digicatapult:feature/vc2-spec-alignment

Conversation

@rmlearney-digicatapult

@rmlearney-digicatapult rmlearney-digicatapult commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Apologies I couldn't break this into smaller units for review but it wouldn't have been functional.

Large core element of fully spec-compliant VC Data Model 2.0.

This PR introduces:

W3cV2 Model Changes for VC 2.0

  • Refined JSON model shapes
  • Updated verify result envelope
  • New shape detectors and guards for enveloped credentials and presentations for routing
  • Fixed type error for enveloped_verifiable_presentation_type
  • New codec file to extract conversion functions out of W3cV2EnvelopedVerifiablePresentation.ts and break a circular imports with the Jwt and SdJwt models

W3cV2 JWT & SD-JWT alignment to VC-JOSE-COSE

  • Deterministic header/media-type routing, credential subject authentication
  • Compact JWT envelope types have cty/type checks
  • SD-JWT VC2 handlers with enforced challenge/domain binding
  • Removed old jwt-vc-presentation-profile.ts
  • VC 2.0 Verifiable Presentation Handling

Full VC 2.0 + VC-JOSE-COSE multi-format nested VC/VP compliance

  • Outer envelope decoded and dispatched to format-specific service based on typed-matched presentation class (jwt, sd-jwt, di), not string matches
  • Recursive JSON-LD tree walk extracting, dispatching and verifying all internal combinations of VC, Enveloped VC (jwt/sd-jwt outer) and Enveloped VP (jwt/sd-jwt outer) to comply with VC 2.0 and VC-JOSE-COSE
  • Fully tested with 18-combination matrix in matrixVpFixture.ts

VC 2.0 Routing & API

  • W3cV2CredentialService as full-featured top-level router capable of dispatching jwt, sd-jwt, di credential types
  • Extended service options for multi-format support and DI sign/verify
  • Wired DI VC support into API
  • Extracted shared JWT utility helpers from service layer into v2-jwt-utils.ts
  • Centralised VC 2.0 @context and credential validity period validators into validators.ts

JSON-LD Contexts for VC 2.0

  • New bundled context files & hashes per VC 2.0 and DI 1.0 specifications

Data Integrity v1.0 Handling

  • New data-integrity-v1 handler using w3c-di proof module for VC 2.0 semantics
  • @context compliance checks, proof purpose & challenge validation in VC subsystem
  • DI credential models
  • DI error code mapping
  • DI credential signing/verification
  • Full test coverage with production-like credential fixture in fixtures/credo-di-vc.ts

Credential Record

  • Updated W3cV2CredentialRecord.ts to handle DI + cryptosuite tagging
  • Schema extensions and database migrations

DCQL, PEX, OIDC

  • Guards and hardening for di_* paths because not yet supported

@rmlearney-digicatapult
rmlearney-digicatapult requested a review from a team as a code owner June 11, 2026 13:25
@changeset-bot

changeset-bot Bot commented Jun 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2b67bae

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 18 packages
Name Type
@credo-ts/core Patch
@credo-ts/drizzle-storage Patch
@credo-ts/openid4vc Patch
@credo-ts/askar-to-drizzle-storage-migration Patch
@credo-ts/action-menu Patch
@credo-ts/anoncreds Patch
@credo-ts/askar Patch
@credo-ts/cheqd Patch
@credo-ts/didcomm Patch
@credo-ts/drpc Patch
@credo-ts/hedera Patch
@credo-ts/indy-vdr Patch
@credo-ts/node Patch
@credo-ts/question-answer Patch
@credo-ts/react-native Patch
@credo-ts/redis-cache Patch
@credo-ts/tenants Patch
@credo-ts/webvh Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@rmlearney-digicatapult
rmlearney-digicatapult force-pushed the feature/vc2-spec-alignment branch from 6686ca6 to c2533bf Compare June 11, 2026 13:25
@rmlearney-digicatapult

Copy link
Copy Markdown
Contributor Author

I implemented tree-walking support for VP-within-VP (per VC-JOSE-COSE) but it appears this is not directly supported by VC 2.1 at this time (w3c/vc-data-model#1633)

I will remove this functionality for VC 2.0 spec compliance.

@rmlearney-digicatapult
rmlearney-digicatapult marked this pull request as draft June 28, 2026 18:24
@jrhender

jrhender commented Jul 2, 2026

Copy link
Copy Markdown

This PR would close #2196

Signed-off-by: rmlearney-digicatapult <robert.learney@digicatapult.org.uk>
Signed-off-by: rmlearney-digicatapult <robert.learney@digicatapult.org.uk>
Signed-off-by: rmlearney-digicatapult <robert.learney@digicatapult.org.uk>
Signed-off-by: rmlearney-digicatapult <robert.learney@digicatapult.org.uk>
Signed-off-by: rmlearney-digicatapult <robert.learney@digicatapult.org.uk>
Signed-off-by: rmlearney-digicatapult <robert.learney@digicatapult.org.uk>
@rmlearney-digicatapult
rmlearney-digicatapult marked this pull request as ready for review August 4, 2026 15:37
@dosubot

dosubot Bot commented Aug 4, 2026

Copy link
Copy Markdown

📄 Knowledge review

Dosu skipped reviewing this PR because your organization has used its 200 included credits for the month. Your usage will reset on 2026-09-01. To have Dosu review this PR before then, ask your organization admin to upgrade to a pro account.


Leave Feedback Ask Dosu about credo-ts Add Dosu to your team

@rmlearney-digicatapult

rmlearney-digicatapult commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

Tests all passing locally with Docker :(

Looks like the E2E and Drizzle errors are arising from indy-pool building on Bionic which is EOL so package server potentially down

Failed to fetch http://security.ubuntu.com/ubuntu/dists/bionic-security/InRelease Connection failed [IP: 91.189.92.23 80]

@rmlearney-digicatapult

Copy link
Copy Markdown
Contributor Author

Design question: This is currently a strict spec-compliant implementation. Do we want to extend options to allow user to inject custom documentLoader into the module at init?

The implementation also currently uses direct native fetch in W3cV2DataIntegrityContextValidator.ts but this is also the case for existing vc/jsonld/nativeDocumentLoader.ts and nativeDocumentLoader.native.ts

I could modify all of these sites to use injected fetch plus wrapper.

@TimoGlastra

Copy link
Copy Markdown
Contributor

Ideally we use the custom fetch from whenever possible. We didn't use it because the document loader didn't support it.

@genaris genaris left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @rmlearney-digicatapult ! I left some comments and minor suggestions but overall I think it's a great addition. I'd like to see it soon in main and that's why I'm submitting my approval!

}

async function getContextBytes(contextUrl: string): Promise<Uint8Array> {
const response = await fetch(contextUrl, {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beware on using bare fetch (use the one from agent dependencies, either directly or through the fetchWithTimeout utility method).

Comment on lines +277 to +281
signerId = presentation.resolvedPresentation.holderId
if (!signerId) {
validationResults.isValid = false
return validationResults
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If holder is not present (optional in VCDM 2.0), wouldn't this always fail?

let cachedContextValidationDocumentLoader: DocumentLoader | undefined

async function getContextValidationDocumentLoader(): Promise<DocumentLoader> {
if (cachedContextValidationDocumentLoader) return cachedContextValidationDocumentLoader

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it intended to have this scoped document loader (cached on module-owned variable)? I mean, is it fine to have a separate loader configured for W3CCredentialsModule? There we can define a custom loader that wouldn't be used here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

W3cV2CredentialsModule.ts declares W3cV2CredentialsModuleConfigOptions inline and stores this.options. Its direct 1.1 sibling does it conventionally:

export class W3cCredentialsModule implements Module {
  public readonly config: W3cCredentialsModuleConfig
  public constructor(config?: W3cCredentialsModuleConfigOptions) {
    this.config = new W3cCredentialsModuleConfig(config)
  }

Related: W3cV2DataIntegrityContextValidator.configure() is a mutable setter on an @injectable() class, called once at registration. A config class passed to the constructor would match the codebase and remove the mutable-singleton shape.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The directory's v1 means Data Integrity 1.0, but adding that suffix does not make it "future proof", since the classes within it do only include the "V2" that corresponds to the VCDM 2.0. I think we can simply leave the directory as data-integrity and, in case a future major revision of DI is created, we can rename the classes to take into account the DI version (if actually needed).

rmlearney-digicatapult and others added 4 commits August 27, 2026 20:07
Signed-off-by: rmlearney-digicatapult <robert.learney@digicatapult.org.uk>
Signed-off-by: rmlearney-digicatapult <robert.learney@digicatapult.org.uk>
Signed-off-by: rmlearney-digicatapult <robert.learney@digicatapult.org.uk>
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.

4 participants