CBOR Web Token (CWT)

RFC 8392 CBOR Web Token — the CBOR-native counterpart to JWT, a signed claims set for constrained / IoT, FIDO attestation, and verifiable-credential contexts. A CWT is a COSE_Sign1 (b.cose) whose payload is a deterministically-encoded CBOR claims map (b.cbor) — this module composes both and layers the standard-claim handling on top.

b.cwt.sign(claims, opts) accepts a friendly claims object; the standard claims are mapped to their RFC 8392 §3.1.1 integer labels (iss=1, sub=2, aud=3, exp=4, nbf=5, iat=6, cti=7) and any other key is kept verbatim. b.cwt.verify(cwt, opts) verifies the COSE signature (delegating the mandatory algorithm allowlist to b.cose.verify), decodes the claims, and enforces the time + identity claims: a passed exp, a future nbf, an iss / aud mismatch against the expected values are each refused.

Signing algorithms follow b.cose: the classical ES256/384/512 + EdDSA (final COSE ids, interoperable today) and ML-DSA-87 (PQC-forward). The optional CWT CBOR tag (61, RFC 8392 §6) wraps the COSE_Sign1 when opts.tagged is set; verify accepts tagged and untagged input.

b.cwt.sign(claims, opts) #

stable0.12.34
{
  {
    alg:        string,   // COSE signing alg (ES256 / EdDSA / ML-DSA-87 / …)
    privateKey: object,   // signing key (per b.cose.sign)
    kid?:       string,   // COSE kid header
    tagged?:    boolean,  // wrap in CWT CBOR tag 61 (default false)
    externalAad?: Buffer, // bound into the COSE signature
  }
}

Sign a claims set into a CWT (a COSE_Sign1 over the CBOR-encoded claims). Standard claims are mapped to their integer labels; custom claims (string or integer keys) are kept as given. exp / nbf / iat must be integer NumericDates (seconds since the epoch).

var cwt = await b.cwt.sign(
  { iss: "issuer.example", sub: "device-42", exp: Math.floor(Date.now()/1000) + 3600, scope: "telemetry" },
  { alg: "ES256", privateKey: ecKey, kid: "k1" });

b.cwt.verify(cwt, opts) #

stable0.12.34
{
  {
    algorithms:       string[],  // required — accepted COSE algs (allowlist)
    publicKey?:       object,    // verification key (per b.cose.verify)
    keyResolver?:     function,
    expectedIssuer?:  string,    // require iss === this
    expectedAudience?: string,   // require aud to include this
    clockSkewSec?:    number,    // default 60
    now?:             number,    // override clock (ms) for testing
    externalAad?:     Buffer,
  }
}

Verify a CWT and return its claims. The COSE signature is checked via b.cose.verify (mandatory algorithms allowlist), then the standard time / identity claims are enforced: a passed exp (with clockSkewSec tolerance), a not-yet-valid nbf, and — when requested — an iss / aud mismatch are refused. Accepts a CWT-tag-61-wrapped or bare COSE_Sign1.

var out = await b.cwt.verify(cwt, { algorithms: ["ES256"], publicKey: pub, expectedIssuer: "issuer.example" });
// → { claims: { iss, sub, exp, scope }, raw: Map, protectedHeaders: Map }

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