gose/cose/cwt

CBOR Web Token (CWT) RFC 8392

CWT is the CBOR equivalent of JWT, providing claims-based tokens using COSE for signing and verification.

Example

import gleam/time/duration
import gleam/time/timestamp
import gose/algorithm
import gose/cose/cwt
import gose/key
import kryptos/ec

let signing_key = key.generate_ec(ec.P256)
let now = timestamp.system_time()
let exp = timestamp.add(now, duration.hours(1))

let claims = cwt.new()
  |> cwt.with_subject("user123")
  |> cwt.with_issuer("my-app")
  |> cwt.with_expiration(exp)

let assert Ok(token) =
  cwt.sign(
    claims,
    alg: algorithm.Ecdsa(algorithm.EcdsaP256),
    key: signing_key,
  )

let assert Ok(verifier) =
  cwt.verifier(algorithm.Ecdsa(algorithm.EcdsaP256), keys: [signing_key])
let assert Ok(verified) = cwt.verify_and_validate(verifier, token:, now:)
let verified_claims = cwt.verified_claims(verified)

Phantom Types

Cwt(state) uses a phantom type to track verification state:

Types

A CWT parameterized by verification state.

pub opaque type Cwt(state)

The set of claims carried by a CWT (registered + custom).

pub opaque type CwtClaims

Errors from CWT operations, covering both COSE-layer failures and claim validation.

pub type CwtError {
  CoseError(gose.GoseError)
  InvalidSignature
  MalformedToken(reason: String)
  TokenExpired(expired_at: timestamp.Timestamp)
  TokenNotYetValid(valid_from: timestamp.Timestamp)
  IssuerMismatch(expected: String, actual: option.Option(String))
  AudienceMismatch(
    expected: String,
    actual: option.Option(List(String)),
  )
  MissingExpiration
  DecryptionFailed(reason: String)
  InvalidClaim(reason: String)
}

Constructors

  • CoseError(gose.GoseError)

    An error from the underlying COSE layer (signing, verification, decryption, key validation).

  • InvalidSignature

    The COSE_Sign1 signature did not verify against any of the provided keys.

  • MalformedToken(reason: String)

    The token could not be parsed (invalid CBOR, unexpected claim types, etc.).

  • TokenExpired(expired_at: timestamp.Timestamp)

    The exp claim is in the past.

  • TokenNotYetValid(valid_from: timestamp.Timestamp)

    The nbf claim is in the future.

  • IssuerMismatch(expected: String, actual: option.Option(String))

    The iss claim does not match the expected issuer.

  • AudienceMismatch(
      expected: String,
      actual: option.Option(List(String)),
    )

    The aud claim does not contain the expected audience.

  • MissingExpiration

    The exp claim is required by the verifier but absent.

  • DecryptionFailed(reason: String)

    COSE decryption failed (wrong key, corrupted ciphertext, etc.).

  • InvalidClaim(reason: String)

    A claim value is invalid (empty audience list, etc.).

Phantom type for a CWT that has been parsed but not yet verified.

pub type Unverified

Phantom type for a CWT whose signature and claims have been validated.

pub type Verified

Holds algorithm, keys, and validation options for verifying a CWT.

pub opaque type Verifier

Values

pub fn audience(claims: CwtClaims) -> Result(List(String), Nil)

Read the audience claim as a list of strings.

pub fn cti(claims: CwtClaims) -> Result(BitArray, Nil)

Read the CWT ID.

pub fn custom_claim(
  claims: CwtClaims,
  key key: cbor.Value,
) -> Result(cbor.Value, Nil)

Look up a custom claim by its CBOR key.

pub fn expiration(
  claims: CwtClaims,
) -> Result(timestamp.Timestamp, Nil)

Read the expiration time as a timestamp.

pub fn issued_at(
  claims: CwtClaims,
) -> Result(timestamp.Timestamp, Nil)

Read the issued-at time as a timestamp.

pub fn issuer(claims: CwtClaims) -> Result(String, Nil)

Read the issuer claim.

pub fn new() -> CwtClaims

Create an empty set of CWT claims.

pub fn not_before(
  claims: CwtClaims,
) -> Result(timestamp.Timestamp, Nil)

Read the not-before time as a timestamp.

pub fn sign(
  claims: CwtClaims,
  alg alg: algorithm.DigitalSignatureAlg,
  key key: key.Key(BitArray),
) -> Result(BitArray, CwtError)

Sign a set of claims as a COSE_Sign1-wrapped CWT, returning the serialized CBOR bytes.

pub fn subject(claims: CwtClaims) -> Result(String, Nil)

Read the subject claim.

pub fn verified_claims(cwt: Cwt(Verified)) -> CwtClaims

Extract the validated claims from a verified CWT.

pub fn verifier(
  alg: algorithm.DigitalSignatureAlg,
  keys keys: List(key.Key(BitArray)),
) -> Result(Verifier, CwtError)

Build a CWT verifier pinned to a single signature algorithm and one or more keys.

pub fn verify_and_validate(
  verifier: Verifier,
  token token: BitArray,
  now now: timestamp.Timestamp,
) -> Result(Cwt(Verified), CwtError)

Parse, verify the signature, and validate claims in one step.

pub fn with_audience(
  claims: CwtClaims,
  audience: String,
) -> CwtClaims

Set a single audience (aud, label 3) claim.

pub fn with_audience_validation(
  verifier: Verifier,
  audience: String,
) -> Verifier

Require the token’s aud claim to include the given audience.

pub fn with_audiences(
  claims: CwtClaims,
  audiences: List(String),
) -> Result(CwtClaims, CwtError)

Set multiple audiences (aud, label 3) as an array.

pub fn with_clock_skew(
  verifier: Verifier,
  seconds: Int,
) -> Verifier

Set the allowed clock skew in seconds (default: 60). Tokens are accepted up to seconds past exp or before nbf.

pub fn with_cti(claims: CwtClaims, cti: BitArray) -> CwtClaims

Set the CWT ID (cti, label 7) claim.

pub fn with_custom_claim(
  claims: CwtClaims,
  key key: cbor.Value,
  value value: cbor.Value,
) -> Result(CwtClaims, CwtError)

Add a custom (non-registered) claim keyed by an arbitrary CBOR value.

Returns an error if the key collides with a registered CWT label (1-7). If the key already exists in custom claims, the value is replaced.

pub fn with_expiration(
  claims: CwtClaims,
  exp: timestamp.Timestamp,
) -> CwtClaims

Set the expiration time (exp, label 4) claim.

pub fn with_issued_at(
  claims: CwtClaims,
  iat: timestamp.Timestamp,
) -> CwtClaims

Set the issued-at time (iat, label 6) claim.

pub fn with_issuer(
  claims: CwtClaims,
  issuer: String,
) -> CwtClaims

Set the issuer (iss, label 1) claim.

pub fn with_issuer_validation(
  verifier: Verifier,
  issuer: String,
) -> Verifier

Require the token’s iss claim to match the given issuer.

pub fn with_not_before(
  claims: CwtClaims,
  nbf: timestamp.Timestamp,
) -> CwtClaims

Set the not-before time (nbf, label 5) claim.

pub fn with_require_expiration(
  verifier: Verifier,
  required: Bool,
) -> Verifier

Control whether the exp claim is required (default: True).

pub fn with_subject(
  claims: CwtClaims,
  subject: String,
) -> CwtClaims

Set the subject (sub, label 2) claim.

Search Document