Verifiable Credentials (W3C VCDM 2.0)

Issue and verify W3C Verifiable Credentials (VC Data Model 2.0, a W3C Recommendation) secured per "Securing Verifiable Credentials using JOSE and COSE" (VC-JOSE-COSE, also a W3C Recommendation). A verifiable credential is a tamper-evident, cryptographically-signed set of claims an issuer makes about a subject — a diploma, a membership, a license, an age assertion.

Two securing mechanisms are supported, both putting the credential itself (not a JWT/CWT claims wrapper) as the signed payload: JOSE produces a compact JWS with the vc+jwt media type (typ header "vc+jwt"), signed with the classical ES256 / 384 / 512 or EdDSA JOSE algorithms; COSE produces a COSE_Sign1 (application/vc+cose) over b.cose, adding ML-DSA-87 (PQC-forward) to that set. b.vc.verify auto-detects the form from the input (a compact-JWS string vs. COSE_Sign1 bytes).

b.vc.issue(credential, opts) validates the credential against the VCDM 2.0 structural rules (the credentials/v2 context first, a VerifiableCredential type, an issuer, a credential subject) and signs it. b.vc.verify(secured, opts) verifies the signature (the algorithm allowlist is mandatory; the JOSE none algorithm is always refused), re-checks the structural rules, and enforces the validFrom / validUntil validity window. This is the W3C model and is distinct from the IETF SD-JWT VC at b.auth.sdJwtVc.

b.vc.issue(credential, opts) #

experimental0.12.39gdprsoc2
{
  {
    securing:   string,   // "jose" (compact JWS) | "cose" (COSE_Sign1)
    alg:        string,   // JOSE: ES256/384/512 | EdDSA. COSE: + ML-DSA-87
    privateKey: object,   // matching KeyObject or PEM
    kid:        string,   // optional key id (header)
    cty:        string,   // optional JOSE cty (e.g. "vc")
  }
}

Validate a credential against the VCDM 2.0 structural rules and secure it. securing: "jose" returns a compact JWS string (media type vc+jwt) signed with an ES256/384/512 or EdDSA key; securing: "cose" returns COSE_Sign1 bytes (media type application/vc+cose) over b.cose, which also accepts "ML-DSA-87". The credential itself is the signed payload — no JWT/CWT claims wrapper is added.

var jws = await b.vc.issue(credential, { securing: "jose", alg: "ES256", privateKey: key });
// → a compact JWS string with typ "vc+jwt"

b.vc.verify(secured, opts) #

experimental0.12.39gdprsoc2
{
  {
    algorithms:      string[],  // required — accepted alg names (allowlist)
    publicKey:       object,    // verification key (KeyObject / PEM)
    keyResolver:     function,  // (header) → key  (alternative to publicKey)
    expectedIssuer:  string,    // require the credential issuer (id) to match
    at:              Date,      // validity instant (default: now); must be a valid Date
  }
}

Verify a secured verifiable credential and return the credential. The securing form is auto-detected (a compact-JWS string vs. COSE_Sign1 bytes); the algorithm allowlist is mandatory and the JOSE none algorithm is always refused. After the signature, the VCDM 2.0 structural rules are re-checked and the validFrom / validUntil window is enforced against opts.at (default: now).

var out = await b.vc.verify(jws, { algorithms: ["ES256"], publicKey: issuerPub, expectedIssuer: "did:example:123" });
// → { credential, securing: "jose", alg: "ES256", issuer: "did:example:123" }

b.vc.present(opts) #

experimental0.12.42gdprsoc2
{
  {
    credentials: array,    // secured VCs (compact-JWS strings or COSE_Sign1 bytes)
    holder:      string,   // the presenter (a DID or other id)
    securing:    string,   // "jose" | "cose"
    alg:         string,   // JOSE: ES256/384/512 | EdDSA. COSE: + ML-DSA-87
    privateKey:  object,   // the holder's key
    kid:         string,   // optional key id
    nonce:       string,   // optional verifier challenge (embedded + checked)
    audience:    string,   // optional intended verifier (embedded + checked)
  }
}

Build and sign a W3C Verifiable Presentation: a holder-signed envelope wrapping one or more secured credentials (each enveloped per VC-JOSE-COSE). securing and the algorithms match b.vc.issue (compact JWS vp+jwt, or COSE_Sign1 application/vp+cose). Supply nonce / audience for holder-binding / replay protection — they are embedded in the signed presentation and checked at verification.

var vp = await b.vc.present({ credentials: [jws], holder: holderDid, securing: "jose", alg: "ES256", privateKey: holderKey, nonce: challenge });

b.vc.verifyPresentation(secured, opts) #

experimental0.12.42gdprsoc2
{
  {
    algorithms:      string[],  // required — holder-signature alg allowlist
    publicKey:       object,    // the holder verification key
    keyResolver:     function,  // (header) → holder key
    expectedHolder:  string,    // require presentation holder to match
    nonce:           string,    // require embedded nonce to match
    audience:        string,    // require embedded audience to match
    verifyCredentials: boolean, // verify each enveloped VC via b.vc.verify
    credentialOpts:  object,    // opts passed to b.vc.verify for each VC
  }
}

Verify a Verifiable Presentation: the holder signature (auto-detected jose / cose, mandatory algorithm allowlist, JOSE none refused), the VCDM structure, and the embedded nonce / audience / expectedHolder when given. With verifyCredentials: true each enveloped credential is verified through b.vc.verify (using opts.credentialOpts) and returned.

var out = await b.vc.verifyPresentation(vp, {
  algorithms: ["ES256"], publicKey: holderKey, nonce: challenge,
  verifyCredentials: true, credentialOpts: { algorithms: ["ES256"], publicKey: issuerKey },
});
// → { presentation, holder, credentials: [verified VCs], securing, alg }

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