gose/encrypted_jwt

Encrypted JWT (JWE-based) - RFC 7519

This module provides encrypted JWT functionality built on top of JWE. Encrypted JWTs protect the claims payload through encryption rather than just signing, ensuring confidentiality in addition to integrity.

Use peek_headers() to inspect a token’s headers without decrypting. Use decrypt_and_validate() to decrypt and validate, producing a EncryptedJwt whose claims can be trusted.

Example

import gleam/dynamic/decode
import gleam/time/duration
import gleam/time/timestamp
import gose/encrypted_jwt
import gose/jwa
import gose/jwk
import gose/jwt

let key = jwk.generate_enc_key(jwa.AesGcm(jwa.Aes256))
let now = timestamp.system_time()

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

let assert Ok(encrypted) = encrypted_jwt.encrypt_with_key(
  claims, jwa.JweDirect, jwa.AesGcm(jwa.Aes256), key)
let token = encrypted_jwt.serialize(encrypted)

// Decrypt and validate using Decryptor (enforces algorithm pinning)
let assert Ok(decryptor) = encrypted_jwt.key_decryptor(
  jwa.JweDirect, jwa.AesGcm(jwa.Aes256), [key], jwt.default_validation())
let assert Ok(verified) = encrypted_jwt.decrypt_and_validate(decryptor, token, now)

// Decode verified claims
let decoder = decode.field("sub", decode.string, decode.success)
let assert Ok(subject) = encrypted_jwt.decode(verified, decoder)

Types

A decryptor that pins the expected algorithms and validates keys.

Create with key_decryptor() or password_decryptor(). The decryptor validates that:

  • Token’s alg header matches the expected key encryption algorithm
  • Token’s enc header matches the expected content encryption algorithm
  • Each key’s use field (if set) is Encrypting
  • Each key’s key_ops field (if set) includes Decrypt or UnwrapKey
pub opaque type Decryptor

A JWT whose plaintext claims are available and have been validated. This type is produced by decrypt_and_validate() after successful decryption and claim verification.

pub opaque type EncryptedJwt

Header fields from an encrypted JWT token, extracted without decrypting.

pub type PeekHeaders {
  PeekHeaders(
    alg: jwa.JweAlg,
    enc: jwa.Enc,
    kid: option.Option(String),
  )
}

Constructors

Values

pub fn alg(jwt: EncryptedJwt) -> jwa.JweAlg

Get the key encryption algorithm (alg) from a verified encrypted JWT.

Parameters

  • jwt - The verified encrypted JWT.

Returns

The JweAlg from the token’s header.

pub fn dangerously_decrypt_and_skip_validation(
  decryptor: Decryptor,
  token: String,
) -> Result(EncryptedJwt, jwt.JwtError)

Decrypt an encrypted JWT, skipping all claim validation.

Warning: This skips expiration, not-before, issuer, and audience checks. Use only when you have a legitimate reason to bypass validation, such as inspecting claims before deciding on validation policy.

Still enforces algorithm pinning for security. Note: kid_policy only applies to key-based decryptors, not password-based decryptors.

Parameters

  • decryptor - A Decryptor created by key_decryptor or password_decryptor.
  • token - The JWE compact serialization string.

Returns

Ok(EncryptedJwt) with the decrypted JWT and accessible claims, Error(JweAlgorithmMismatch(_)) if the token’s algorithms don’t match, or Error(DecryptionFailed(_)) if decryption fails.

pub fn decode(
  jwt: EncryptedJwt,
  decoder: decode.Decoder(a),
) -> Result(a, jwt.JwtError)

Decode an encrypted JWT’s claims using a custom decoder.

This allows extracting claims directly into your own types using gleam/dynamic/decode. The decoder receives the raw claims JSON.

Parameters

  • jwt - A verified (decrypted) encrypted JWT.
  • decoder - A gleam/dynamic/decode decoder for the claims.

Returns

Ok(a) with the decoded claims value, or Error(ClaimDecodingFailed(_)) if decoding fails.

pub fn decrypt_and_validate(
  decryptor: Decryptor,
  token: String,
  now now: timestamp.Timestamp,
) -> Result(EncryptedJwt, jwt.JwtError)

Decrypt an encrypted JWT and validate its claims using a Decryptor.

Checks:

  1. Token’s alg and enc headers match the decryptor’s expected algorithms
  2. Decryption succeeds with one of the decryptor’s keys
  3. Claims pass validation (exp, nbf, iss, aud per options)

When multiple keys are configured:

  • Keys with matching kid are tried first (if token has kid header)
  • kid_policy controls kid header enforcement (see KidPolicy type)
  • With NoKidRequirement, all keys are tried with matching keys prioritized

Parameters

  • decryptor - A Decryptor created by key_decryptor or password_decryptor.
  • token - The JWE compact serialization string.
  • now - The current timestamp for time-based claim validation.

Returns

Ok(EncryptedJwt) with the decrypted and validated JWT, Error(JweAlgorithmMismatch(_)) if the token’s algorithms don’t match the decryptor’s expected algorithms, Error(DecryptionFailed(_)) if decryption fails, or a claim validation error (TokenExpired, TokenNotYetValid, etc.) if claim validation fails.

pub fn enc(jwt: EncryptedJwt) -> jwa.Enc

Get the content encryption algorithm (enc) from a verified encrypted JWT.

Parameters

  • jwt - The verified encrypted JWT.

Returns

The Enc from the token’s header.

pub fn encrypt_with_key(
  claims: jwt.Claims,
  alg: jwa.JweAlg,
  enc: jwa.Enc,
  key key: jwk.Jwk,
) -> Result(EncryptedJwt, jwt.JwtError)

Encrypt claims using a key-based algorithm.

Supports all key-based JWE algorithms: direct symmetric (dir), AES Key Wrap, AES-GCM Key Wrap, RSA-OAEP, and ECDH-ES. PBES2 password-based algorithms return an error — use encrypt_with_password instead.

Sets typ: "JWT" in the header. If the encryption key has a kid, it is included in the JWE header.

Parameters

  • claims - The JWT claims to encrypt.
  • alg - The key encryption algorithm.
  • enc - The content encryption algorithm.
  • key - The encryption key.

Returns

Ok(EncryptedJwt) with the encrypted JWT ready for serialization, or Error(JoseError(_)) if key validation or encryption fails.

pub fn encrypt_with_password(
  claims: jwt.Claims,
  alg: jwa.Pbes2Alg,
  enc: jwa.Enc,
  password password: String,
  kid kid: option.Option(String),
) -> Result(EncryptedJwt, jwt.JwtError)

Encrypt claims using PBES2 password-based encryption.

Sets typ: "JWT" in the header.

Parameters

  • claims - The JWT claims to encrypt.
  • alg - The PBES2 algorithm.
  • enc - The content encryption algorithm.
  • password - The password for key derivation.
  • kid - Optional key ID to include in the header.

Returns

Ok(EncryptedJwt) with the encrypted JWT ready for serialization, or Error(JoseError(_)) if encryption fails.

pub fn key_decryptor(
  alg: jwa.JweAlg,
  enc: jwa.Enc,
  keys keys: List(jwk.Jwk),
  options options: jwt.JwtValidationOptions,
) -> Result(Decryptor, jwt.JwtError)

Create a key-based decryptor for symmetric (dir, AES-KW, AES-GCM-KW) or asymmetric (RSA-OAEP, ECDH-ES) algorithms.

The decryptor pins the expected algorithms. Tokens with different algorithms will be rejected.

Parameters

  • alg - The expected key encryption algorithm.
  • enc - The expected content encryption algorithm.
  • keys - One or more keys for decryption.
  • options - Validation options for JWT claims.

Returns

Ok(Decryptor) configured and ready for use with decrypt_and_validate, or Error(JoseError(_)) if the key list is empty, any key’s use field is set but not Encrypting, or any key’s key_ops doesn’t include Decrypt or UnwrapKey.

pub fn kid(jwt: EncryptedJwt) -> Result(String, Nil)

Get the key ID (kid) from a verified encrypted JWT header.

Security Warning: The kid value comes from the token and is untrusted input. If you use it to look up keys (from a database, filesystem, or key store), you must sanitize it first to prevent injection attacks.

Parameters

  • jwt - The verified encrypted JWT.

Returns

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

pub fn password_decryptor(
  alg: jwa.Pbes2Alg,
  enc: jwa.Enc,
  password password: String,
  options options: jwt.JwtValidationOptions,
) -> Decryptor

Create a password-based decryptor for PBES2 algorithms.

The decryptor pins the expected algorithms. Tokens with different algorithms will be rejected.

Parameters

  • alg - The expected PBES2 algorithm.
  • enc - The expected content encryption algorithm.
  • password - The password for key derivation.
  • options - Validation options for JWT claims.

Returns

A Decryptor configured for use with decrypt_and_validate.

pub fn peek_headers(
  token: String,
) -> Result(PeekHeaders, jwt.JwtError)

Peek at the header fields from a token without decrypting.

Parameters

  • token - The JWE compact serialization string.

Returns

Ok(PeekHeaders) with the algorithm, encryption, and optional key ID from the header, or Error(MalformedToken(_)) if the token cannot be parsed.

pub fn serialize(jwt: EncryptedJwt) -> String

Serialize a decrypted encrypted JWT to compact format.

Parameters

  • jwt - A EncryptedJwt from encrypt_with_key, encrypt_with_password, or decrypt_and_validate.

Returns

The JWE compact serialization string.

Search Document