Metadata-Version: 2.5
Name: flask-enciphers
Version: 3.0.0
Summary: Encrypted session interface for Flask using enciphers
Project-URL: Homepage, https://github.com/mjlad/flask-enciphers
Author: Mejlad Alsubaie
License: Apache-2.0
License-File: LICENSE
Keywords: enciphers,encryption,flask,session
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Flask
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: Topic :: Security :: Cryptography
Requires-Python: >=3.11
Requires-Dist: enciphers<4,>=3
Requires-Dist: flask>=2.0
Requires-Dist: orjson
Description-Content-Type: text/markdown

# flask-enciphers

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

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

> **Version 3.0 note**: requires `enciphers>=3,<4`, including its fix for
> nonce reuse across forked workers. 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
pip install flask-enciphers
```

## Usage

```python
from flask import Flask, session
from flask_enciphers import EnciphersSession

app = Flask(__name__)
EnciphersSession(app)

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

### Application Factory Pattern

```python
from flask_enciphers import EnciphersSession

es = EnciphersSession()

def create_app():
    app = Flask(__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, from `0` to `2**128 - 1` |
| `ENCIPHERS_KEY_ENV` | `str` | None | Name of an environment variable containing the key as a decimal integer |

Configure only one key source. A random 128-bit key is generated only
when both settings are absent or `None`. An explicit integer `0` is
preserved; it is not treated as missing. Invalid key types or values,
invalid environment settings, and conflicting key sources raise an
exception during initialization instead of being silently replaced.

> 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) carries no `expires_at` either, unchanged from before.

## Upgrading from 2.x

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

Keep your existing `ENCIPHERS_KEY` or `ENCIPHERS_KEY_ENV` and
`ENCIPHERS_BACKEND` configuration. The token format is unchanged, so
existing 2.x sessions, including non-expiring tokens created with
`expires_at=0`, remain valid until their original expiry. For correctly
configured keys, no key rotation or session reset is required. Upgrade
every worker to pick up the
upstream nonce-generation fix.

The key configuration check now distinguishes `None` from `0`. Earlier
versions silently generated a random key when `ENCIPHERS_KEY=0` was
set without `ENCIPHERS_KEY_ENV`; those cookies cannot be read using the
now-correctly configured zero key. This exception affects deployments
that relied on that erroneous fallback, not cookies actually encrypted
with key zero (for example, using an environment variable containing `"0"`).

`enciphers` 3 rejects `encrypt(..., expires_at=0)`; use `None` for no
expiry and a positive Unix timestamp for an expiry. This session
interface already passes `None` for non-permanent sessions and the
cookie's expiration timestamp for permanent sessions, so application
session code needs no change. If you call `encrypt` directly, update
any zero expiry arguments. Oversized purposes still raise `ValueError`,
but the error message has changed; this interface uses the default
`"session"` purpose and does not match error messages.

See the upstream [migration guide](https://github.com/mjlad/enciphers#upgrading-from-2x)
for details. Cookies from flask-enciphers 0.1.x remain incompatible;
see [CHANGELOG.md](CHANGELOG.md#upgrading-from-01x).

## Development

Install the package and run the session tests against the installed version:

```bash
python -m pip install -e .
python -m unittest discover -s tests -v
```

## License

Apache-2.0 — Copyright 2026 Mejlad Alsubaie
