NAME

PAGI::Middleware::Session::Store::Cookie - Encrypted client-side session store

SYNOPSIS

use PAGI::Middleware::Session::Store::Cookie;

my $store = PAGI::Middleware::Session::Store::Cookie->new(
    secret => 'at-least-32-bytes-of-secret-key!',
);

DESCRIPTION

Stores session data encrypted in the client cookie itself using AES-256-GCM (authenticated encryption). No server-side storage is needed.

The set() method returns the encrypted blob (not the session ID). The get() method accepts the encrypted blob and returns the decoded session data, or undef if decryption/verification fails.

Limitations: Cookie size is limited to ~4KB. Large sessions will fail. Session revocation requires server-side state (e.g., a blocklist).

Note: This module will be extracted to a separate CPAN distribution in a future release.

METHODS

new

my $store = PAGI::Middleware::Session::Store::Cookie->new(
    secret => 'at-least-32-bytes-of-secret-key!',
);

Creates a new cookie session store. The secret parameter is required and is used to derive the AES-256 encryption key via SHA-256.

get

my $data = await $store->get($encrypted_blob);

Decrypts and decodes the blob. Returns a Future resolving to the session hashref, or undef if the blob is invalid, tampered, or cannot be decoded.

set

my $transport_value = await $store->set($id, $data);

Encrypts the session data and returns a Future resolving to the encrypted blob. This blob is what gets passed to State::inject() for storage in the response cookie. Nothing is stored server-side.

delete

await $store->delete($id);

No-op for cookie stores (client manages cookie lifetime). Returns a Future resolving to 1.

SECURITY

Session data is encrypted with AES-256-GCM, which provides both confidentiality (data cannot be read) and authenticity (data cannot be tampered with). The encryption key is derived from the secret via SHA-256.

Each encryption uses a random 12-byte IV, so the same session data produces different ciphertext each time.

IV Generation

The encryption IV is generated from /dev/urandom when available (all modern Unix/Linux/macOS systems). On systems without /dev/urandom, the module falls back to Perl's rand(), which is not cryptographically secure -- a runtime warning is emitted in this case. If you are running on such a system, install Crypt::URandom and the module will use it automatically.

Note: A predictable IV does not compromise the confidentiality or authenticity of AES-GCM (the key is still required), but it may allow an attacker to detect when the same session data is re-encrypted, which leaks information about session changes.

HTTP cookies are limited to approximately 4KB by most browsers. Large session data will produce cookies that exceed this limit and be silently rejected by the browser. Keep session data small.

AUTHORS

John Napiorkowski

OpenAI Codex

Anthropic Claude

LICENSE

This software is Copyright (c) 2026 by John Napiorkowski.

This is free software, licensed under:

The Artistic License 2.0 (GPL Compatible)

For the full license text, see:

https://www.perlfoundation.org/artistic-license-20.html

SEE ALSO

PAGI::Middleware::Session::Store - Base store interface

PAGI::Middleware::Session - Session management middleware