gose

Package Version Hex Docs

A Gleam implementation of JOSE (JSON Object Signing and Encryption) standards:

Project Goals

Installation

gleam add gose

Platform support

Browser JavaScript is not supported.

Supported Algorithms

All algorithms below apply to both raw JWS/JWE operations and JWT signing and encryption.

JWS Signing

FamilyAlgorithms
HMACHS256, HS384, HS512
RSA PKCS#1 v1.5RS256, RS384, RS512
RSA-PSSPS256, PS384, PS512
ECDSAES256 (P-256), ES384 (P-384), ES512 (P-521), ES256K (secp256k1)
EdDSAEd25519, Ed448

JWE Key Management

FamilyAlgorithms
Directdir
AES Key WrapA128KW, A192KW, A256KW
AES-GCM Key WrapA128GCMKW, A192GCMKW, A256GCMKW
ChaCha20 Key WrapC20PKW, XC20PKW
RSARSA1_5, RSA-OAEP, RSA-OAEP-256
ECDH-ESECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW, ECDH-ES+C20PKW, ECDH-ES+XC20PKW
PBES2PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW

JWE Content Encryption

FamilyAlgorithms
AES-GCMA128GCM, A192GCM, A256GCM
AES-CBC + HMACA128CBC-HS256, A192CBC-HS384, A256CBC-HS512
ChaCha20C20P (ChaCha20-Poly1305), XC20P (XChaCha20-Poly1305)

Quick Start

JWT - Creating and Verifying Tokens

import gleam/dynamic/decode
import gleam/option.{None}
import gleam/time/duration
import gleam/time/timestamp
import gose/jwa
import gose/jwk
import gose/jwt

pub fn main() {
  // Generate a symmetric key for HS256
  let key = jwk.generate_hmac_key(jwa.HmacSha256)
  let now = timestamp.system_time()

  // Create claims
  let claims =
    jwt.claims()
    |> jwt.with_subject("user123")
    |> jwt.with_issuer("my-app")
    |> jwt.with_expiration(timestamp.add(now, duration.hours(1)))

  // Sign the JWT
  let assert Ok(signed) = jwt.sign(jwa.JwsHmac(jwa.HmacSha256), claims, key)

  // Serialize to compact format
  let token = jwt.serialize(signed)

  // Verify and validate
  let assert Ok(verifier) =
    jwt.verifier(jwa.JwsHmac(jwa.HmacSha256), [key], jwt.default_validation())
  let assert Ok(verified) = jwt.verify_and_validate(verifier, token, now)

  // Decode verified claims
  let decoder = decode.field("sub", decode.string, decode.success)
  let assert Ok("user123") = jwt.decode(verified, decoder)
}

JWS - Signing Data

import gose/jwa
import gose/jwk
import gose/jws
import kryptos/eddsa

pub fn main() {
  // Generate an Ed25519 key
  let key = jwk.generate_eddsa(eddsa.Ed25519)
  let payload = <<"hello world":utf8>>

  // Create and sign
  let assert Ok(signed) =
    jws.new(jwa.JwsEddsa)
    |> jws.sign(key, payload)

  // Serialize to compact format
  let assert Ok(token) = jws.serialize_compact(signed)

  // Parse and verify using a Verifier
  let assert Ok(parsed) = jws.parse_compact(token)
  let assert Ok(verifier) = jws.verifier(jwa.JwsEddsa, [key])
  let assert Ok(True) = jws.verify(verifier, parsed)
}

JWE - Encrypting Data

import gose/jwa
import gose/jwe
import gose/jwk

pub fn main() {
  // Generate a 256-bit key for direct encryption with AES-256-GCM
  let key = jwk.generate_enc_key(jwa.AesGcm(jwa.Aes256))
  let plaintext = <<"sensitive data":utf8>>

  // Encrypt using direct key encryption
  let assert Ok(encrypted) =
    jwe.new_direct(jwa.AesGcm(jwa.Aes256))
    |> jwe.encrypt(key, plaintext)

  // Serialize to compact format
  let assert Ok(token) = jwe.serialize_compact(encrypted)

  // Parse and decrypt with algorithm pinning
  let assert Ok(parsed) = jwe.parse_compact(token)
  let assert Ok(decryptor) = jwe.key_decryptor(jwa.JweDirect, jwa.AesGcm(jwa.Aes256), [key])
  let assert Ok(decrypted) = jwe.decrypt(decryptor, parsed)
  // decrypted == <<"sensitive data":utf8>>
}

Error Handling

The library uses a two-tier error design:

GoseError — used by JOSE primitives (JWS, JWE, JWK):

VariantWhen It Occurs
ParseErrorInvalid base64 encoding, malformed JSON, wrong token format
CryptoErrorSignature verification failure, decryption failure, key derivation error
InvalidStateWrong key type for algorithm, missing required header, incompatible parameters

JwtError — used by JWT and encrypted JWT modules:

VariantWhen It Occurs
TokenExpiredToken’s exp claim is in the past
TokenNotYetValidToken’s nbf claim is in the future
IssuerMismatchToken’s iss doesn’t match expected issuer
AudienceMismatchToken’s aud doesn’t match expected audience
InvalidSignatureJWS signature verification failed
DecryptionFailedJWE decryption failed
JoseError(GoseError)Underlying JOSE operation failed (key validation, signing, etc.)
See JwtError type for all variants

Limitations

Documentation

Full API documentation is available at hexdocs.pm/gose.

Search Document