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:
x5u- X.509 URLx5c- X.509 Certificate Chainx5t- X.509 Certificate SHA-1 Thumbprintx5t#S256- X.509 Certificate SHA-256 Thumbprint
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
-
Jws(jwa.JwsAlg)JWS signing algorithm
-
Jwe(jwa.JweAlg)JWE key encryption algorithm
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
-
SignCompute digital signature or MAC
-
VerifyVerify digital signature or MAC
-
EncryptEncrypt content
-
DecryptDecrypt content and validate decryption
-
WrapKeyEncrypt key
-
UnwrapKeyDecrypt key and validate decryption
-
DeriveKeyDerive key
-
DeriveBitsDerive bits not to be used as a key
Key type identifier (kty parameter).
pub type KeyType {
OctKeyType
RsaKeyType
EcKeyType
OkpKeyType
}
Constructors
-
OctKeyTypeSymmetric key (oct)
-
RsaKeyTypeRSA key
-
EcKeyTypeElliptic Curve key
-
OkpKeyTypeOctet Key Pair (EdDSA, XDH)
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- ABitArraycontaining 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 bytesAes192→ 24 bytesAes256→ 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 bytesAesGcm(Aes192)→ 24 bytesAesGcm(Aes256)→ 32 bytesAesCbcHmac(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 bytesXChaCha20Poly1305→ 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 bytesHmacSha384→ 48 bytesHmacSha512→ 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:
Signis mapped toVerifyDecryptandUnwrapKeyare 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:
Signinguse impliesSignand/orVerifyoperationsEncryptinguse impliesEncrypt,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 (SigningorEncrypting).
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.