Metadata-Version: 2.5
Name: quart-enciphers
Version: 3.0.0
Summary: Encrypted session interface for Quart using enciphers
Project-URL: Homepage, https://github.com/mjlad/quart-enciphers
Author: Mejlad Alsubaie
License: Apache-2.0
License-File: LICENSE
Keywords: enciphers,encryption,quart,session
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Security :: Cryptography
Requires-Python: >=3.11
Requires-Dist: enciphers<4,>=3
Requires-Dist: orjson
Requires-Dist: quart>=0.18
Description-Content-Type: text/markdown

# quart-enciphers

Encrypted session interface for Quart using [enciphers](https://pypi.org/project/enciphers/).

Replaces Quart's default signed cookie session with a fully encrypted one.

> **Version 3.0** requires `enciphers>=3,<4`. Existing 2.x session cookies
> remain readable with the same key and backend. See
> [Upgrading from 2.x](#upgrading-from-2x) and [CHANGELOG.md](CHANGELOG.md).

## Installation

```bash
python -m pip install "quart-enciphers>=3,<4"
```

## Usage

```python
from quart import Quart, session
from quart_enciphers import EnciphersSession

app = Quart(__name__)
EnciphersSession(app)

@app.route("/login")
async def login():
    session["user_id"] = 1
    return "logged in"
```

### Application Factory Pattern

```python
from quart import Quart
from quart_enciphers import EnciphersSession

es = EnciphersSession()

def create_app():
    app = Quart(__name__)
    es.init_app(app)
    return app
```

## Configuration

| Key | Type | Default | Description |
|---|---|---|---|
| `ENCIPHERS_BACKEND` | `str` | `"AES256_GCM"` | `"AES256_GCM"` or `"XCHACHA20_POLY1305"` |
| `ENCIPHERS_KEY` | `int` | random | Secret key, a 128-bit value |
| `ENCIPHERS_KEY_ENV` | `str` | None | Name of an environment variable containing the key as a decimal integer |

Set at most one of `ENCIPHERS_KEY` and `ENCIPHERS_KEY_ENV`, before
calling `EnciphersSession(app)` or `init_app(app)`. Generate a key once
with `secrets.randbits(128)` and persist it for production use.

For example, with `CIPHER_KEY` set to the stored key's decimal value:

```python
from quart import Quart
from quart_enciphers import EnciphersSession

app = Quart(__name__)
app.config["ENCIPHERS_KEY_ENV"] = "CIPHER_KEY"
app.config["ENCIPHERS_BACKEND"] = "AES256_GCM"
EnciphersSession(app)
```

> If no `ENCIPHERS_KEY`/`ENCIPHERS_KEY_ENV` is provided, a random key is
> generated at startup — fine for local development, but every process
> in a real deployment needs to share the same key, or sessions won't
> be portable between them.

## Session expiry

If `session.permanent` is set (giving the cookie an `Expires` attribute), the
same expiry is also bound inside the encrypted token itself — a copy of
the cookie can't be replayed past that point even if a client ignores
the cookie's own expiration. A non-permanent session cookie (the
default) uses `expires_at=None`, so the token has no embedded expiry.

## Upgrading from 2.x

- Upgrade `quart-enciphers` to 3.x; it now requires `enciphers>=3,<4`.
  Update any explicit `enciphers<3` pins in your application as well.
- Keep the same `ENCIPHERS_KEY` (or environment value) and
  `ENCIPHERS_BACKEND`. The token format and key derivation are unchanged,
  so existing 2.x sessions survive the upgrade without a new login.
- Explicit `ENCIPHERS_KEY=0` is now honored; previous releases silently
  replaced it with a random key. Use a persisted random 128-bit key in
  deployments. Sessions created using the old random fallback cannot
  be read with the newly honored zero key.
- The `EnciphersSession` API and configuration keys are unchanged.
  `enciphers` 3 rejects `encrypt(..., expires_at=0)`; this interface
  already passes `None` for non-permanent sessions and Unix timestamps
  for permanent sessions. If your application calls `encrypt` directly,
  replace zero expiries with `None` and review the
  [upstream migration notes](https://github.com/mjlad/enciphers#upgrading-from-2x).
- Upgrade all workers to receive the upstream fix for nonce generation
  after `fork`.

Cookies from `quart-enciphers` 0.1.x are still incompatible and open as
empty sessions; users with those cookies need to log in again.

## Development

```bash
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
python -m pip install -e .
python -m unittest discover -s tests -v
```

Tests exercise both encryption backends with real Quart requests,
including expiry, invalid cookies, and fixed tokens created by
`enciphers` 2.0.0. The 3.0.0 wheel was tested on Python 3.11–3.14.

Build the wheel and source distribution locally with:

```bash
python -m pip install hatchling
python -m hatchling build
```

Artifacts are written to `dist/`.

## License

Apache-2.0 — Copyright 2026 Mejlad Alsubaie
