Skip to content

Commit 64a2bfd

Browse files
committed
docs: clarify encrypted JWT trust semantics
Encryption provides confidentiality and ciphertext integrity, not issuer authentication. Clarify module docs, type docs, and accessor comments to avoid conflating decryption with signature verification. Recommend sign-then-encrypt for proof of origin.
1 parent 0cc1fc8 commit 64a2bfd

1 file changed

Lines changed: 24 additions & 18 deletions

File tree

src/gose/encrypted_jwt.gleam

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
//// Encrypted JWT (JWE-based) - [RFC 7519](https://www.rfc-editor.org/rfc/rfc7519.html)
22
////
33
//// This module provides encrypted JWT functionality built on top of JWE.
4-
//// Encrypted JWTs protect the claims payload through encryption rather than
5-
//// just signing, ensuring confidentiality in addition to integrity.
4+
//// Encrypted JWTs protect the claims payload through encryption, providing
5+
//// confidentiality and ciphertext integrity. **Encryption alone does not
6+
//// authenticate the issuer** — for asymmetric algorithms (RSA-OAEP, ECDH-ES),
7+
//// anyone with the recipient's public key can produce a valid encrypted token.
8+
////
9+
//// If your application requires proof of origin, use sign-then-encrypt
10+
//// (nested JWT): sign the claims with JWS first, then encrypt the signed
11+
//// token with JWE.
612
////
713
//// Use `peek_headers()` to inspect a token's headers without decrypting.
8-
//// Use `decrypt_and_validate()` to
9-
//// decrypt and validate, producing a `EncryptedJwt` whose claims can be
10-
//// trusted.
14+
//// Use `decrypt_and_validate()` to decrypt and validate claim fields (exp,
15+
//// nbf, iss, aud), producing an `EncryptedJwt` whose claims have been
16+
//// decrypted and validated.
1117
////
1218
//// ## Example
1319
////
@@ -36,11 +42,11 @@
3642
//// // Decrypt and validate using Decryptor (enforces algorithm pinning)
3743
//// let assert Ok(decryptor) = encrypted_jwt.key_decryptor(
3844
//// jwa.JweDirect, jwa.AesGcm(jwa.Aes256), [key], jwt.default_validation())
39-
//// let assert Ok(verified) = encrypted_jwt.decrypt_and_validate(decryptor, token, now)
45+
//// let assert Ok(decrypted) = encrypted_jwt.decrypt_and_validate(decryptor, token, now)
4046
////
41-
//// // Decode verified claims
47+
//// // Decode decrypted and validated claims
4248
//// let decoder = decode.field("sub", decode.string, decode.success)
43-
//// let assert Ok(subject) = encrypted_jwt.decode(verified, decoder)
49+
//// let assert Ok(subject) = encrypted_jwt.decode(decrypted, decoder)
4450
//// ```
4551

4652
import gleam/bit_array
@@ -57,9 +63,9 @@ import gose/jwe
5763
import gose/jwk
5864
import gose/jwt
5965

60-
/// A JWT whose plaintext claims are available and have been validated.
61-
/// This type is produced by `decrypt_and_validate()` after successful
62-
/// decryption and claim verification.
66+
/// A JWT whose claims have been decrypted and whose claim fields (exp, nbf,
67+
/// iss, aud) have been validated. Produced by `decrypt_and_validate()`.
68+
/// Note that encryption provides confidentiality, not issuer authentication.
6369
pub opaque type EncryptedJwt {
6470
EncryptedJwt(
6571
alg: jwa.JweAlg,
@@ -414,7 +420,7 @@ pub fn decrypt_and_validate(
414420
///
415421
/// ## Parameters
416422
///
417-
/// - `jwt` - A verified (decrypted) encrypted JWT.
423+
/// - `jwt` - A decrypted and validated encrypted JWT.
418424
/// - `decoder` - A `gleam/dynamic/decode` decoder for the claims.
419425
///
420426
/// ## Returns
@@ -429,11 +435,11 @@ pub fn decode(
429435
|> result.replace_error(jwt.ClaimDecodingFailed("failed to decode claims"))
430436
}
431437

432-
/// Get the key encryption algorithm (`alg`) from a verified encrypted JWT.
438+
/// Get the key encryption algorithm (`alg`) from a decrypted and validated encrypted JWT.
433439
///
434440
/// ## Parameters
435441
///
436-
/// - `jwt` - The verified encrypted JWT.
442+
/// - `jwt` - The decrypted and validated encrypted JWT.
437443
///
438444
/// ## Returns
439445
///
@@ -442,11 +448,11 @@ pub fn alg(jwt: EncryptedJwt) -> jwa.JweAlg {
442448
jwt.alg
443449
}
444450

445-
/// Get the content encryption algorithm (`enc`) from a verified encrypted JWT.
451+
/// Get the content encryption algorithm (`enc`) from a decrypted and validated encrypted JWT.
446452
///
447453
/// ## Parameters
448454
///
449-
/// - `jwt` - The verified encrypted JWT.
455+
/// - `jwt` - The decrypted and validated encrypted JWT.
450456
///
451457
/// ## Returns
452458
///
@@ -455,15 +461,15 @@ pub fn enc(jwt: EncryptedJwt) -> jwa.Enc {
455461
jwt.enc
456462
}
457463

458-
/// Get the key ID (kid) from a verified encrypted JWT header.
464+
/// Get the key ID (kid) from a decrypted and validated encrypted JWT header.
459465
///
460466
/// **Security Warning:** The `kid` value comes from the token and is untrusted
461467
/// input. If you use it to look up keys (from a database, filesystem, or key
462468
/// store), you must sanitize it first to prevent injection attacks.
463469
///
464470
/// ## Parameters
465471
///
466-
/// - `jwt` - The verified encrypted JWT.
472+
/// - `jwt` - The decrypted and validated encrypted JWT.
467473
///
468474
/// ## Returns
469475
///

0 commit comments

Comments
 (0)