Files
skills/docs/foundation/flow/cbor/src/cose/jwk.md
2026-05-29 08:20:56 +01:00

2.5 KiB

jwk

Purpose

Round-trip converter between RFC 9052 COSE_Key instances and RFC 7517 JWK shapes. WebAuthn attestation flows often need to hand a public key to a WebCrypto-style verifier that consumes JWK; conversely, server-issued JWK-formatted keys may need to land in a CBOR-encoded COSE structure. The two conversions preserve every field that has a defined cross-format mapping.

Features

  • coseKeyToJwk(key) — accepts any CoseKey discriminant (EC2, OKP, RSA, Symmetric) and emits the matching JWK (EC, OKP, RSA, oct).
  • jwkToCoseKey(jwk) — reverse mapping with full byte-string round-trip.
  • Byte-string fields use RFC 4648 §5 base64url encoding without padding.
  • kid is treated as UTF-8 bytes on the COSE side and a string on the JWK side; conversion is lossy only if a non-UTF-8 kid is in play (rare, and RFC 9052 §3.1 documents the convention).
  • alg round-trips through a fixed COSE↔JWK label table so the typed algorithm lands consistently on either side.

Usage: Basic Example

import { coseKeyToJwk, jwkToCoseKey } from "@suaveplan/cbor/cose";

const jwk = coseKeyToJwk(coseKey);
const back = jwkToCoseKey(jwk);

Usage: Advanced Example

import { decodeCoseKey, coseKeyToJwk } from "@suaveplan/cbor/cose";

// Attestation key from CTAP2
const cose = decodeCoseKey(attestationKeyBytes);
const jwk = coseKeyToJwk(cose);

// Hand off to WebCrypto
const cryptoKey = await crypto.subtle.importKey(
  "jwk",
  jwk,
  { name: "ECDSA", namedCurve: "P-256" },
  false,
  ["verify"],
);

API Reference

  • coseKeyToJwk(key: CoseKey): Jwk — discriminator-aware conversion to JWK.
  • jwkToCoseKey(jwk: Jwk): CoseKey — reverse conversion.
  • Jwk = Ec2Jwk | OkpJwk | RsaJwk | SymmetricJwk (typed union).

Throws CborError(UNEXPECTED_TYPE) for incompatible curves (EC2 with a non-P curve, OKP with a non-Ed/X curve), unknown JWK alg strings, and malformed base64url input via the underlying atob.

Implementation Notes

base64url encoding is implemented inline with btoa/atob rather than pulling in @suaveplan/crypto-utils so this module stays free of crypto deps. Standard base64 padding (=) is stripped on output and re-padded on input — the RFC 4648 §5 spec allows omission of padding and major JWK producers do strip it. RSA JWKs use lowercase param names (dp, dq, qi) per RFC 7518 §6.3.2; COSE_Key uses the labels from RFC 8230 §4 (-6, -7, -8). The bridge preserves the field-by-field correspondence.