gose/jwk

JSON Web Key (JWK) - RFC 7517

This module provides key management for JOSE operations. It supports symmetric keys (octet sequences) and asymmetric keys (RSA, EC, EdDSA).

Example

import gleam/json
import gose/jwk
import kryptos/ec

// Generate an EC key and attach metadata
let key =
  jwk.generate_ec(ec.P256)
  |> jwk.with_kid("my-signing-key")

// Serialize to JSON
let json_string = jwk.to_json(key)
  |> json.to_string()

// Parse from a JSON string
let assert Ok(parsed) = jwk.from_json(json_string)
let assert Ok("my-signing-key") = jwk.kid(parsed)

Duplicate Member Names

Per RFC 7517 Section 4, JWK member names must be unique. This implementation relies on gleam_json for parsing, which uses the first value when duplicate member names are present. Subsequent duplicates are ignored.

Unsupported Parameters

X.509 certificate chain parameters (RFC 7517 Section 4.6-4.9) are not supported:

JWKs containing any of these parameters are rejected with a ParseError during parsing. These parameters are not emitted during serialization.

Types

Algorithm union type for JWK alg field. A key can specify either a JWS signing algorithm or a JWE encryption algorithm.

pub type Alg {
  Jws(jwa.JwsAlg)
  Jwe(jwa.JweAlg)
}

Constructors

A JSON Web Key.

Use constructor functions like from_octet_bits, from_der, from_pem, or generate_* to create keys.

pub opaque type Jwk

Key Operations parameter.

Identifies the operation(s) for which the key is intended.

pub type KeyOp {
  Sign
  Verify
  Encrypt
  Decrypt
  WrapKey
  UnwrapKey
  DeriveKey
  DeriveBits
}

Constructors

  • Sign

    Compute digital signature or MAC

  • Verify

    Verify digital signature or MAC

  • Encrypt

    Encrypt content

  • Decrypt

    Decrypt content and validate decryption

  • WrapKey

    Encrypt key

  • UnwrapKey

    Decrypt key and validate decryption

  • DeriveKey

    Derive key

  • DeriveBits

    Derive bits not to be used as a key

Key type identifier (kty parameter).

pub type KeyType {
  OctKeyType
  RsaKeyType
  EcKeyType
  OkpKeyType
}

Constructors

  • OctKeyType

    Symmetric key (oct)

  • RsaKeyType

    RSA key

  • EcKeyType

    Elliptic Curve key

  • OkpKeyType

    Octet Key Pair (EdDSA, XDH)

Public Key Use parameter.

Indicates whether the key is for signing or encryption.

pub type KeyUse {
  Signing
  Encrypting
}

Constructors

  • Signing

    Key is used for signature operations

  • Encrypting

    Key is used for encryption operations

Values

pub fn alg(key: Jwk) -> Result(Alg, Nil)

Get the algorithm (alg) parameter.

Parameters

  • key - The JWK to query.

Returns

Ok(Alg) with the algorithm, or Error(Nil) if no algorithm was set on the key.

pub fn alg_from_string(s: String) -> Result(Alg, gose.GoseError)

Parse an algorithm from its RFC string representation.

Parameters

  • s - The RFC algorithm name (e.g. "RS256", "A128KW").

Returns

Ok(Alg) with the parsed algorithm, or Error(ParseError) if the string is not a recognized algorithm name.

pub fn alg_to_string(alg: Alg) -> String

Convert an algorithm (JWS or JWE) to its RFC string representation.

Parameters

  • alg - The algorithm variant to convert.

Returns

The RFC string name (e.g. "RS256", "A128KW").

pub fn decoder() -> decode.Decoder(Jwk)

Return a decoder for JWK values.

This lets you compose JWK decoding inside larger decode pipelines, for example with decode.field, decode.list, or json.parse.

Returns

A Decoder(Jwk) that succeeds on valid JWK JSON objects and fails on anything else.

Example

// Parse a JWK directly from a JSON string
let assert Ok(key) = json.parse(json_string, jwk.decoder())

// Use inside a larger decoder
use key <- decode.field("signing_key", jwk.decoder())
pub fn ec_curve(key: Jwk) -> Result(ec.Curve, gose.GoseError)

Get the curve used by an EC key.

Returns an error if the key is not an EC key.

Parameters

  • key - The JWK to query.

Returns

Ok(ec.Curve) with the EC curve, or Error(InvalidState) if the key is not an EC key.

pub fn ec_public_key(
  key: Jwk,
) -> Result(ec.PublicKey, gose.GoseError)

Extract the EC public key.

Works with both EC private keys (extracts the public component) and EC public keys.

Returns an error if the key is not an EC key.

Parameters

  • key - The JWK to query.

Returns

Ok(ec.PublicKey) with the EC public key, or Error(InvalidState) if the key is not an EC key.

pub fn ec_public_key_coordinates(
  key: Jwk,
) -> Result(#(BitArray, BitArray), gose.GoseError)

Get the x and y coordinates from an EC public key.

The coordinates are returned as raw big-endian bytes, padded to the coordinate size for the curve.

Returns an error if the key is not an EC key.

Parameters

  • key - The EC key to extract coordinates from.

Returns

Ok(#(BitArray, BitArray)) with the (x, y) coordinate pair, or Error(InvalidState) if the key is not an EC key.

pub fn ec_public_key_from_coordinates(
  curve: ec.Curve,
  x x: BitArray,
  y y: BitArray,
) -> Result(Jwk, gose.GoseError)

Create an EC public key from curve and x,y coordinates (big-endian bytes).

Parameters

  • curve - The EC curve (P256, P384, P521, Secp256k1).
  • x - The x coordinate as big-endian bytes.
  • y - The y coordinate as big-endian bytes.

Returns

Ok(Jwk) with an EC public key, or Error(GoseError) if the coordinates are invalid for the curve.

pub fn eddsa_curve(
  key: Jwk,
) -> Result(eddsa.Curve, gose.GoseError)

Get the curve used by an EdDSA key.

Returns an error if the key is not an EdDSA key.

Parameters

  • key - The JWK to query.

Returns

Ok(eddsa.Curve) with the EdDSA curve, or Error(InvalidState) if the key is not an EdDSA key.

pub fn eddsa_public_key(
  key: Jwk,
) -> Result(eddsa.PublicKey, gose.GoseError)

Extract the EdDSA public key.

Works with both EdDSA private keys (extracts the public component) and EdDSA public keys.

Returns an error if the key is not an EdDSA key.

Parameters

  • key - The JWK to query.

Returns

Ok(eddsa.PublicKey) with the EdDSA public key, or Error(InvalidState) if the key is not an EdDSA key.

pub fn from_der(der: BitArray) -> Result(Jwk, gose.GoseError)

Create a key from DER-encoded data.

Auto-detects key type (RSA, EC, EdDSA, XDH) and format (PKCS#1, PKCS#8, SPKI). Supports both private and public keys.

Parameters

  • der - The DER-encoded key bytes.

Returns

Ok(Jwk) with the parsed key, or Error(ParseError) if the DER data is not a recognized key format.

pub fn from_eddsa_bits(
  curve: eddsa.Curve,
  private_bits: BitArray,
) -> Result(Jwk, gose.GoseError)

Create an EdDSA key pair from raw private key bytes.

The public key is derived from the private key. This is the inverse of to_octet_bits for EdDSA private keys.

Parameters

  • curve - The EdDSA curve (Ed25519 or Ed448).
  • private_bits - The raw private key bits.

Returns

Ok(Jwk) with an EdDSA private key and derived public key, or Error(ParseError) if the bits are invalid for the given curve.

pub fn from_eddsa_public_bits(
  curve: eddsa.Curve,
  public_bits: BitArray,
) -> Result(Jwk, gose.GoseError)

Create an EdDSA public key from raw bytes.

This is the inverse of to_octet_bits for EdDSA public keys.

Parameters

  • curve - The EdDSA curve (Ed25519 or Ed448).
  • public_bits - The raw public key bits.

Returns

Ok(Jwk) with an EdDSA public key, or Error(ParseError) if the bits are invalid for the given curve.

pub fn from_json(json_str: String) -> Result(Jwk, gose.GoseError)

Parse a JWK from JSON.

Parameters

  • json_str - A JSON string containing the JWK.

Returns

Ok(Jwk) with the parsed key, or Error(ParseError) if the JSON is invalid or not a recognized JWK.

pub fn from_json_bits(
  json_bits: BitArray,
) -> Result(Jwk, gose.GoseError)

Parse a JWK from JSON provided as a BitArray.

Parameters

  • json_bits - A BitArray containing the JSON-encoded JWK.

Returns

Ok(Jwk) with the parsed key, or Error(ParseError) if the JSON is invalid or not a recognized JWK.

pub fn from_octet_bits(
  secret: BitArray,
) -> Result(Jwk, gose.GoseError)

Create a symmetric key from raw bytes.

Used for HMAC signing (HS256/384/512) and direct encryption. Returns an error if the secret is empty.

Parameters

  • secret - The raw key bytes.

Returns

Ok(Jwk) with a symmetric key wrapping the provided bytes, or Error(InvalidState) if the secret is empty.

Example

let secret = crypto.strong_random_bytes(32)
let assert Ok(key) = jwk.from_octet_bits(secret)
pub fn from_pem(pem: String) -> Result(Jwk, gose.GoseError)

Create a key from PEM-encoded data.

Auto-detects key type (RSA, EC, EdDSA, XDH) and format (PKCS#1, PKCS#8, SPKI). Supports both private and public keys.

Parameters

  • pem - The PEM-encoded key string.

Returns

Ok(Jwk) with the parsed key, or Error(ParseError) if the PEM data is not a recognized key format.

pub fn from_xdh_bits(
  curve: xdh.Curve,
  private_bits: BitArray,
) -> Result(Jwk, gose.GoseError)

Create an XDH key pair from raw private key bytes.

The public key is derived from the private key. This is the inverse of to_octet_bits for XDH private keys.

Parameters

  • curve - The XDH curve (X25519 or X448).
  • private_bits - The raw private key bits.

Returns

Ok(Jwk) with an XDH private key and derived public key, or Error(ParseError) if the bits are invalid for the given curve.

pub fn from_xdh_public_bits(
  curve: xdh.Curve,
  public_bits: BitArray,
) -> Result(Jwk, gose.GoseError)

Create an XDH public key from raw bytes.

This is the inverse of to_octet_bits for XDH public keys.

Parameters

  • curve - The XDH curve (X25519 or X448).
  • public_bits - The raw public key bits.

Returns

Ok(Jwk) with an XDH public key, or Error(ParseError) if the bits are invalid for the given curve.

pub fn generate_aes_kw_key(size: jwa.AesKeySize) -> Jwk

Generate a symmetric key for AES Key Wrap.

The key size is derived from the AES variant:

  • Aes128 → 16 bytes
  • Aes192 → 24 bytes
  • Aes256 → 32 bytes

Parameters

  • size - The AES key size.

Returns

A Jwk containing a symmetric key of the correct size.

pub fn generate_chacha20_kw_key() -> Jwk

Generate a symmetric key for ChaCha20-Poly1305 Key Wrap (C20PKW / XC20PKW).

Always generates a 32-byte key, as both ChaCha20 and XChaCha20 use 256-bit keys.

Returns

A Jwk containing a 32-byte symmetric key.

pub fn generate_ec(curve: ec.Curve) -> Jwk

Generate a new EC key pair for the given curve.

Supported curves: P256, P384, P521, Secp256k1.

Parameters

  • curve - The EC curve to use.

Returns

A Jwk containing the generated EC private key.

pub fn generate_eddsa(curve: eddsa.Curve) -> Jwk

Generate a new EdDSA key pair for the given curve.

Supported curves: Ed25519, Ed448.

Parameters

  • curve - The EdDSA curve to use.

Returns

A Jwk containing the generated EdDSA private key.

pub fn generate_enc_key(enc: jwa.Enc) -> Jwk

Generate a symmetric key for JWE content encryption.

The key size is derived from the encryption algorithm:

  • AesGcm(Aes128) → 16 bytes
  • AesGcm(Aes192) → 24 bytes
  • AesGcm(Aes256) → 32 bytes
  • AesCbcHmac(Aes128) → 32 bytes (16 + 16 for MAC)
  • AesCbcHmac(Aes192) → 48 bytes (24 + 24 for MAC)
  • AesCbcHmac(Aes256) → 64 bytes (32 + 32 for MAC)
  • ChaCha20Poly1305 → 32 bytes
  • XChaCha20Poly1305 → 32 bytes

Parameters

  • enc - The content encryption algorithm.

Returns

A Jwk containing a symmetric key of the correct size.

pub fn generate_hmac_key(alg: jwa.HmacAlg) -> Jwk

Generate a symmetric key for HMAC signing.

The key size is derived from the algorithm:

  • HmacSha256 → 32 bytes
  • HmacSha384 → 48 bytes
  • HmacSha512 → 64 bytes

Parameters

  • alg - The HMAC algorithm variant.

Returns

A Jwk containing a symmetric key of the correct size.

pub fn generate_rsa(bits: Int) -> Result(Jwk, gose.GoseError)

Generate a new RSA key pair with the given key size in bits.

Parameters

  • bits - The RSA key size in bits (e.g. 2048, 4096).

Returns

Ok(Jwk) with the generated RSA key pair, or Error(CryptoError) if key generation fails.

pub fn generate_xdh(curve: xdh.Curve) -> Jwk

Generate a new XDH key pair for key agreement.

Supported curves: X25519, X448.

Parameters

  • curve - The XDH curve to use.

Returns

A Jwk containing the generated XDH private key.

pub fn key_ops(key: Jwk) -> Result(List(KeyOp), Nil)

Get the key operations parameter.

Parameters

  • key - The JWK to query.

Returns

Ok(List(KeyOp)) with the operations, or Error(Nil) if no operations were set on the key.

pub fn key_type(key: Jwk) -> KeyType

Get the key type (kty) for this key.

Parameters

  • key - The JWK to query.

Returns

The KeyType variant (OctKeyType, RsaKeyType, EcKeyType, or OkpKeyType).

pub fn key_use(key: Jwk) -> Result(KeyUse, Nil)

Get the public key use parameter.

Parameters

  • key - The JWK to query.

Returns

Ok(KeyUse) with the use (Signing or Encrypting), or Error(Nil) if no use was set on the key.

pub fn kid(key: Jwk) -> Result(String, Nil)

Get the key ID (kid) parameter.

Parameters

  • key - The JWK to query.

Returns

Ok(String) with the key ID, or Error(Nil) if no key ID was set on the key.

pub fn octet_key_size(key: Jwk) -> Result(Int, gose.GoseError)

Get the size of an octet (symmetric) key in bytes.

Returns an error if the key is not an octet key.

Parameters

  • key - The octet key to measure.

Returns

Ok(Int) with the key size in bytes, or Error(InvalidState) if the key is not an octet key.

pub fn public_key(key: Jwk) -> Result(Jwk, gose.GoseError)

Extract the public key from an asymmetric key.

For private keys, extracts the corresponding public key. For public keys, returns the key unchanged.

When extracting a public key, key_ops are filtered to public-safe operations:

  • Sign is mapped to Verify
  • Decrypt and UnwrapKey are removed (private-only)
  • Other operations are preserved

Parameters

  • key - The JWK to extract the public key from.

Returns

Ok(Jwk) with the public key, or Error(InvalidState) if the key is a symmetric octet key.

Example

let private_key = jwk.generate_ec(ec.P256)
let assert Ok(pub_key) = jwk.public_key(private_key)
pub fn rsa_public_key(
  key: Jwk,
) -> Result(rsa.PublicKey, gose.GoseError)

Extract the RSA public key.

Works with both RSA private keys (extracts the public component) and RSA public keys.

Returns an error if the key is not an RSA key.

Parameters

  • key - The JWK to query.

Returns

Ok(rsa.PublicKey) with the RSA public key, or Error(InvalidState) if the key is not an RSA key.

pub fn thumbprint(
  key: Jwk,
  algorithm: hash.HashAlgorithm,
) -> Result(String, gose.GoseError)

Compute the JWK Thumbprint (RFC 7638).

The thumbprint is a base64url-encoded hash of the canonical JSON representation containing only the required public key members. Private keys produce the same thumbprint as their corresponding public keys.

RFC 7638 specifies SHA-256 as the default hash, but allows other algorithms.

Parameters

  • key - The key to compute the thumbprint for.
  • algorithm - The hash algorithm to use (e.g. hash.Sha256).

Returns

Ok(String) with the base64url-encoded thumbprint, or Error(CryptoError) if the hash algorithm is not supported.

Example

let key = jwk.generate_ec(ec.P256)
let assert Ok(thumbprint) = jwk.thumbprint(key, hash.Sha256)
pub fn to_der(key: Jwk) -> Result(BitArray, gose.GoseError)

Serialize a JWK to DER format.

Supports RSA, EC, EdDSA, and XDH keys (both private and public). Uses PKCS#8 for private keys and SPKI for public keys.

Parameters

  • key - The JWK to serialize.

Returns

Ok(BitArray) with the DER-encoded key, or Error(InvalidState) if the key is a symmetric octet key or serialization fails.

pub fn to_json(key: Jwk) -> json.Json

Serialize a JWK to its JSON representation.

Parameters

  • key - The JWK to serialize.

Returns

A json.Json value representing the key in JWK JSON format.

pub fn to_octet_bits(
  key: Jwk,
) -> Result(BitArray, gose.GoseError)

Export the raw bytes of a key.

Supported key types:

  • Octet keys: returns the secret bytes
  • EdDSA/XDH private keys: returns the private key bytes (d)
  • EdDSA/XDH public keys: returns the public key bytes (x)

Parameters

  • key - The JWK to export.

Returns

Ok(BitArray) with the raw key bytes, or Error(InvalidState) for RSA and EC keys which have no single-value byte representation.

pub fn to_pem(key: Jwk) -> Result(String, gose.GoseError)

Serialize a JWK to PEM format.

Supports RSA, EC, EdDSA, and XDH keys (both private and public). Uses PKCS#8 for private keys and SPKI for public keys.

Parameters

  • key - The JWK to serialize.

Returns

Ok(String) with the PEM-encoded key, or Error(InvalidState) if the key is a symmetric octet key or serialization fails.

pub fn with_alg(key: Jwk, alg: Alg) -> Jwk

Set the algorithm (alg) metadata parameter on a key.

Parameters

  • key - The JWK to update.
  • alg - The algorithm to associate with the key.

Returns

A new Jwk with the alg parameter set.

pub fn with_key_ops(
  key: Jwk,
  ops: List(KeyOp),
) -> Result(Jwk, gose.GoseError)

Set the key operations parameter.

Per RFC 7517, the values should be consistent with key_use if both are present:

  • Signing use implies Sign and/or Verify operations
  • Encrypting use implies Encrypt, Decrypt, WrapKey, UnwrapKey, DeriveKey, DeriveBits

Returns an error if the list is empty or if the operations are incompatible with the key’s existing key_use.

Parameters

  • key - The JWK to update.
  • ops - The list of key operations to allow.

Returns

Ok(Jwk) with the operations parameter set, or Error(InvalidState) if the list is empty, contains duplicates, or is incompatible with key_use.

pub fn with_key_use(
  key: Jwk,
  use_: KeyUse,
) -> Result(Jwk, gose.GoseError)

Set the public key use parameter.

Returns an error if the key already has key_ops that are incompatible with the specified use, or if the use is incompatible with the key type per RFC 8037 (EdDSA keys can only be used for signing, XDH keys can only be used for encryption).

Parameters

  • key - The JWK to update.
  • use_ - The intended use (Signing or Encrypting).

Returns

Ok(Jwk) with the use parameter set, or Error(InvalidState) if the use is incompatible with key_ops or key type.

pub fn with_kid(key: Jwk, kid: String) -> Jwk

Set the key ID (kid) metadata parameter on a key.

Parameters

  • key - The JWK to update.
  • kid - The key identifier string.

Returns

A new Jwk with the kid parameter set.

pub fn xdh_curve(key: Jwk) -> Result(xdh.Curve, gose.GoseError)

Get the curve used by an XDH key.

Returns an error if the key is not an XDH key.

Parameters

  • key - The JWK to query.

Returns

Ok(xdh.Curve) with the XDH curve, or Error(InvalidState) if the key is not an XDH key.

pub fn xdh_public_key(
  key: Jwk,
) -> Result(xdh.PublicKey, gose.GoseError)

Extract the XDH public key (X25519/X448).

Works with both XDH private keys (extracts the public component) and XDH public keys.

Returns an error if the key is not an XDH key.

Parameters

  • key - The JWK to query.

Returns

Ok(xdh.PublicKey) with the XDH public key, or Error(InvalidState) if the key is not an XDH key.

Search Document