Skip to content

feat(cookie): add AES-256-GCM encrypted cookie support#4818

Open
brunorodmoreira wants to merge 5 commits intohonojs:mainfrom
brunorodmoreira:feat/encrypted-cookie
Open

feat(cookie): add AES-256-GCM encrypted cookie support#4818
brunorodmoreira wants to merge 5 commits intohonojs:mainfrom
brunorodmoreira:feat/encrypted-cookie

Conversation

@brunorodmoreira
Copy link
Copy Markdown

Closes #4817

Summary

  • Add setEncryptedCookie, getEncryptedCookie, generateEncryptedCookie helpers using AES-256-GCM encryption via Web Crypto API
  • Add serializeEncrypted, parseEncrypted low-level utils with EncryptedCookie type
  • API mirrors existing signed cookie pattern (setSignedCookie / getSignedCookie)

Crypto design

Concern Choice
Algorithm AES-256-GCM (crypto.subtle)
Key derivation HKDF-SHA256 with app-specific salt
IV Random 12 bytes per encryption
Auth tag 128-bit (full strength)
AAD Cookie name bound as additional data
Cookie format base64(iv || ciphertext || authTag)

The author should do the following, if applicable

  • Add tests
  • Run tests
  • bun run format:fix && bun run lint:fix to format the code
  • Add TSDoc/JSDoc to document the code

Test plan

  • Round-trip set/get encrypted cookie (single key and all cookies)
  • Missing cookie returns undefined
  • Tampered cookie returns false
  • Wrong secret returns false
  • Copying encrypted value to different cookie name returns false (AAD binding)
  • Secure and host prefix round-trips
  • Cookie options (domain, httpOnly, maxAge, expires, sameSite)
  • generateEncryptedCookie with and without options
  • All 29 existing cookie tests still pass

brunorodmoreira and others added 5 commits March 20, 2026 13:21
Add serializeEncrypted and parseEncrypted to cookie utils using
AES-256-GCM via Web Crypto API with HKDF-SHA256 key derivation.
Add setEncryptedCookie, getEncryptedCookie, generateEncryptedCookie
with full prefix support and comprehensive test coverage.
- Use non-empty HKDF salt for stronger key derivation
- Cache CryptoKey across multiple cookie decryptions
- Bind ciphertext to cookie name via AES-GCM additional data (AAD)
- Use loop-based base64 encoding to avoid stack overflow on large payloads
- Wrap decodeURIComponent in try/catch for malformed cookie values
Copy link
Copy Markdown

@travisbreaks travisbreaks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Crypto implementation in a framework that runs on Cloudflare Workers deserves a careful look. Some observations:

  1. IV uniqueness: 12 random bytes from crypto.getRandomValues() is standard for AES-GCM and provides strong uniqueness guarantees. Good.

  2. HKDF salt: Is the salt hardcoded or configurable? If hardcoded, two different applications using the same master key would derive the same encryption key. A configurable salt (or using the cookie name as salt input) would provide domain separation.

  3. AAD binding: If the cookie name is used as AAD (Additional Authenticated Data), this correctly prevents cookie swapping attacks (moving an encrypted value from cookie A to cookie B). Worth explicitly calling this out in the docs/comments if it is the case.

  4. Workers shared isolate concern: CryptoKey objects cached across requests in Workers share the same isolate. This is fine for encryption keys derived from a static secret, but worth confirming the cache key includes all relevant derivation parameters so different configurations don't accidentally share a CryptoKey.

  5. Timing side-channels: The base64 encoding/decoding path should be constant-time or at least not leak information about the plaintext length beyond what the ciphertext length already reveals. Standard btoa/atob implementations are generally fine here.

  6. Error handling: What happens if decryption fails (tampered ciphertext, wrong key)? AES-GCM will throw, and the behavior should be clearly documented: does it return undefined, throw, or return the raw encrypted value?

Solid implementation overall. The main thing I'd want to see addressed is the salt configurability and the decryption failure behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Add AES-256-GCM encrypted cookie support

2 participants