Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

[English](https://fastapi-cachex.readthedocs.io/en/latest/) | [繁體中文](https://fastapi-cachex.readthedocs.io/zh-tw/latest/)

A high-performance caching extension for FastAPI: a server-side response cache with `Cache-Control` and `ETag` support, application-level caching, and optional session management.
A high-performance caching extension for FastAPI: a server-side response cache with `Cache-Control` and `ETag` support, and application-level caching.

**Documentation:** <https://fastapi-cachex.readthedocs.io/en/latest/> — guides and the full API reference.

Expand All @@ -26,9 +26,9 @@ A high-performance caching extension for FastAPI: a server-side response cache w
your own code, with compute-on-miss `get_or_set()` and atomic store-if-absent `add()`.
- **Backends** — in-memory, Redis and Memcached, with atomic counters,
one-shot values and locks.
- **Sessions (optional)** — HMAC-signed or JWT session tokens over headers,
bearer tokens or cookies, with sliding expiration and IP/User-Agent binding.
- **OAuth state** — one-time state tokens for CSRF protection in OAuth/OIDC flows.
- **Sessions and OAuth state (deprecated)**: signed session tokens and one-time
OAuth state tokens. Both are deprecated in 0.4.0 and removed in 0.5.0; see
[where to move](https://fastapi-cachex.readthedocs.io/en/latest/MIGRATING_0_4/#session-state-deprecated).

## Installation

Expand Down Expand Up @@ -105,7 +105,7 @@ async def report(cache: AppCache):
- [Application cache](https://fastapi-cachex.readthedocs.io/en/latest/APP_CACHE/) — `CacheManager`
- [Backends](https://fastapi-cachex.readthedocs.io/en/latest/BACKENDS/) — choosing and configuring a backend, atomic primitives
- [Distributed lock](https://fastapi-cachex.readthedocs.io/en/latest/LOCK/) — `CacheLock` for multi-process mutual exclusion
- [Session management](https://fastapi-cachex.readthedocs.io/en/latest/SESSION/), [OAuth state](https://fastapi-cachex.readthedocs.io/en/latest/STATE/) (one-shot OAuth/CSRF state tokens) and [JWT claims](https://fastapi-cachex.readthedocs.io/en/latest/JWT_CLAIMS/)
- Deprecated, removed in 0.5.0: [Session management](https://fastapi-cachex.readthedocs.io/en/latest/SESSION/), [OAuth state](https://fastapi-cachex.readthedocs.io/en/latest/STATE/) (one-shot OAuth/CSRF state tokens) and [JWT claims](https://fastapi-cachex.readthedocs.io/en/latest/JWT_CLAIMS/)
- [Cache flow](https://fastapi-cachex.readthedocs.io/en/latest/CACHE_FLOW/) — what happens inside a cached request
- [Runnable examples](https://github.com/allen0099/FastAPI-CacheX/tree/master/examples) — one complete app per feature, each covered by the test suite
- [API reference](https://fastapi-cachex.readthedocs.io/en/latest/api/http-caching/)
Expand Down
3 changes: 3 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ still there.

A fix ships as a new 0.3.x patch release; earlier releases are not patched.

`fastapi_cachex.session` and `fastapi_cachex.state` are deprecated in 0.4.0.
They get security fixes during 0.4.x and none after 0.5.0 removes them.

## Reporting a vulnerability

Please do **not** open a public issue, pull request or discussion for a
Expand Down
8 changes: 8 additions & 0 deletions changelog.d/420.deprecated.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
**Sessions and OAuth state are deprecated and will be removed in 0.5.0.**
FastAPI-CacheX is narrowing to HTTP and application caching. Importing
`fastapi_cachex.session` or `fastapi_cachex.state`, or reading one of their
names from the `fastapi_cachex` package, emits a `FutureWarning`; a plain
`import fastapi_cachex` does not. The names are no longer in
`fastapi_cachex.__all__`. Both packages get security fixes only until 0.5.0;
"Sessions and OAuth state are deprecated" in the 0.4.0 migration guide says
where to move.
3 changes: 3 additions & 0 deletions docs/JWT_CLAIMS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# JWT Claims: Implementation Notes and Extension Guide

> [!WARNING]
> **Deprecated.** `fastapi_cachex.session` is deprecated in 0.4.0 and removed in 0.5.0 ([#420](https://github.com/allen0099/FastAPI-CacheX/issues/420)). Importing it emits a `FutureWarning`. [Migrating to 0.4.0](MIGRATING_0_4.md#session-state-deprecated) says where to move.

## Overview

FastAPI-CacheX's JWT token serializer implements a minimal set of JWT claims to carry session tokens securely. This document explains:
Expand Down
72 changes: 40 additions & 32 deletions docs/MIGRATING_0_4.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,62 @@ Every warning below names the setting to change and links to its issue. `FutureW

| Change | Issue | Warned in 0.3.9 | Section |
|--------|-------|-----------------|---------|
| Sessions and OAuth state deprecated, removed in 0.5.0 | [#420](https://github.com/allen0099/FastAPI-CacheX/issues/420) | No (0.4.0 warns: `FutureWarning`) | [Sessions and OAuth state are deprecated](#session-state-deprecated) |
| Session cookie defaults to `__Host-session` with `Secure` | [#256](https://github.com/allen0099/FastAPI-CacheX/issues/256) | `FutureWarning` | [Session cookie](#session-cookie) |
| Contradictory `__Host-` / `__Secure-` cookie settings are rejected | [#256](https://github.com/allen0099/FastAPI-CacheX/issues/256) | `UserWarning` (`FutureWarning` when `cookie_name` is left at its default, under the middleware only) | [Session cookie](#session-cookie) |
| Explicit `login()` / `logout()`, read-only `Session.user` | [#256](https://github.com/allen0099/FastAPI-CacheX/issues/256) | No | [Login and logout](#login-logout) |
| `get_or_set()` locks by default | [#280](https://github.com/allen0099/FastAPI-CacheX/issues/280) | `FutureWarning` | [get_or_set lock](#get-or-set-lock) |
| `get_session_manager` resolves through `SessionManagerProxy` | [#131](https://github.com/allen0099/FastAPI-CacheX/issues/131) | `FutureWarning` | [get_session_manager](#get-session-manager) |
| `token_source_priority` names every token source; a list without `"cookie"` disables the cookie | [#75](https://github.com/allen0099/FastAPI-CacheX/issues/75) | `FutureWarning` | [Token sources](#token-source-priority) |
| Dropped: `get_session_manager` resolving through `SessionManagerProxy` | [#131](https://github.com/allen0099/FastAPI-CacheX/issues/131) | `FutureWarning` (0.4.0 no longer warns) | [get_session_manager](#get-session-manager) |
| Dropped: `token_source_priority` naming every token source | [#75](https://github.com/allen0099/FastAPI-CacheX/issues/75) | `FutureWarning` (0.4.0 no longer warns) | [Token sources](#token-source-priority) |
| `add_routes()` requires `dependencies`, no content preview by default | [#298](https://github.com/allen0099/FastAPI-CacheX/issues/298) | `UserWarning` (only when `dependencies` is left out) | [Monitoring routes](#add-routes) |
| Redis `encoding` option removed | [#126](https://github.com/allen0099/FastAPI-CacheX/issues/126) | `DeprecationWarning` (`RuntimeWarning` for a value other than UTF-8) | [Redis encoding](#redis-encoding) |
| JWT HMAC secrets shorter than the hash output are rejected | [#129](https://github.com/allen0099/FastAPI-CacheX/issues/129) | `UserWarning` | [JWT secret length](#jwt-secret) |
| `SessionMiddleware` removed | [#69](https://github.com/allen0099/FastAPI-CacheX/issues/69) | `DeprecationWarning` | [SessionMiddleware](#session-middleware) |
| `BackendProxy.get_backend()` / `set_backend()` removed | [#70](https://github.com/allen0099/FastAPI-CacheX/issues/70) | `DeprecationWarning` | [BackendProxy](#backend-proxy) |
| `CacheError` removed | [#130](https://github.com/allen0099/FastAPI-CacheX/issues/130) | `DeprecationWarning` | [CacheError](#cache-error) |
| Redis `clear_pattern()` prefix-stripped retry removed | [#125](https://github.com/allen0099/FastAPI-CacheX/issues/125) | `DeprecationWarning` | [Redis clear_pattern](#redis-clear-pattern) |
| `SessionConfig.use_bearer_token` removed | [#377](https://github.com/allen0099/FastAPI-CacheX/issues/377) | `DeprecationWarning` | [Token sources](#token-source-priority) |
| `SessionConfig.use_bearer_token` stays deprecated, removed in 0.5.0 | [#377](https://github.com/allen0099/FastAPI-CacheX/issues/377) | `DeprecationWarning` | [Token sources](#token-source-priority) |
| `UserSessionDep` requires a user | [#127](https://github.com/allen0099/FastAPI-CacheX/issues/127) | No | [UserSessionDep](#user-session-dep) |
| `memcache` extra removed | [#202](https://github.com/allen0099/FastAPI-CacheX/issues/202) | No | [memcache extra](#memcache-extra) |
| `BaseCacheBackend.delete()` returns `bool` | [#71](https://github.com/allen0099/FastAPI-CacheX/issues/71) | No | [delete() return value](#backend-delete) |
| `CacheEntry.headers` becomes a tuple of pairs | [#105](https://github.com/allen0099/FastAPI-CacheX/issues/105) | No | [Repeated headers](#cache-entry-headers) |
| HTTP cache key format | [#271](https://github.com/allen0099/FastAPI-CacheX/issues/271), [#270](https://github.com/allen0099/FastAPI-CacheX/issues/270), [#269](https://github.com/allen0099/FastAPI-CacheX/issues/269), [#266](https://github.com/allen0099/FastAPI-CacheX/issues/266), [#265](https://github.com/allen0099/FastAPI-CacheX/issues/265), [#72](https://github.com/allen0099/FastAPI-CacheX/issues/72) | No | [Cache keys](#cache-keys) |
| Conditional session writes | [#128](https://github.com/allen0099/FastAPI-CacheX/issues/128) | No | [Session writes](#session-writes) |

## Sessions and OAuth state are deprecated {#session-state-deprecated}

`fastapi_cachex.session` and `fastapi_cachex.state` are deprecated in 0.4.0 and removed in 0.5.0 ([#420](https://github.com/allen0099/FastAPI-CacheX/issues/420), [#421](https://github.com/allen0099/FastAPI-CacheX/issues/421)). FastAPI-CacheX is narrowing to HTTP and application caching. Session handling and OAuth state are security-sensitive, and libraries built for them maintain them better. 0.3.9 did not announce this, so both packages keep working throughout 0.4.x and get security fixes only.

Importing either package, or reading one of their names from `fastapi_cachex` (such as `fastapi_cachex.SessionConfig`), emits a `FutureWarning` that points at the importing line. `import fastapi_cachex` on its own does not warn, and neither do `@cache`, `CacheManager`, `CacheLock` or the backends. The session and state names are no longer in `fastapi_cachex.__all__`, so `from fastapi_cachex import *` stops providing them. Until you migrate, import them by name.

Where to move:

| You use | Move to |
|---------|---------|
| `FastAPICacheXSessionMiddleware` with cookie sessions | Starlette's `SessionMiddleware` keeps small session data in a signed cookie. If sessions must live on the server (large data, server-side revocation), use a server-side session library, for example `starsessions`. |
| Session tokens in a header or `Authorization: Bearer` for an API | The access tokens of your authentication stack, for example OAuth 2 bearer tokens verified with a JWT library. |
| `StateManager` for the OAuth/OIDC `state` | Your OAuth client library. Authlib's Starlette integration, for example, creates and checks `state` and `nonce` for you; it keeps them in `request.session`, so it needs Starlette's `SessionMiddleware`. |
| `CacheManager`, `CacheLock`, `@cache` | Nothing to do: they are not deprecated. |

Sessions and states already in the backend need no cleanup; they expire on their own TTL.

To silence the warning while you migrate, filter it before the first import:

```python
import warnings

warnings.filterwarnings(
"ignore", message="fastapi_cachex.session is deprecated", category=FutureWarning
)
warnings.filterwarnings(
"ignore", message="fastapi_cachex.state is deprecated", category=FutureWarning
)
```

## Sessions {#sessions}

These changes still apply if you keep using sessions during 0.4.x.

### Session cookie defaults {#session-cookie}

0.4.0 changes two `SessionConfig` defaults ([#256](https://github.com/allen0099/FastAPI-CacheX/issues/256)): `cookie_name` becomes `"__Host-session"` (from `"session"`) and `cookie_https_only` becomes `True` (from `False`). Browsers accept a `__Host-` cookie only when it is `Secure`, has `Path=/` and no `Domain`, and never from a subdomain, which removes the usual way to plant a session cookie. Two consequences:
Expand Down Expand Up @@ -116,23 +149,7 @@ await login(request, SessionUser(user_id=user_id))

### get_session_manager {#get-session-manager}

`get_session_manager` (and `SessionManagerDep`, `ClientIPDep` and `rotate_session_id()`, which use it) currently returns the manager the middleware stored on `app.state`. 0.4.0 resolves it through `SessionManagerProxy` only, like `BackendProxy` and `CacheManagerProxy` ([#131](https://github.com/allen0099/FastAPI-CacheX/issues/131)). In 0.3.9 it emits a `FutureWarning`, once per app, when the proxy holds no manager or a different one.

Before:

```python
session_manager = SessionManager(backend, config)
app.add_middleware(FastAPICacheXSessionMiddleware, session_manager=session_manager)
```

After:

```python
session_manager = SessionManager(backend, config)
SessionManagerProxy.set(session_manager)
# The middleware picks the manager up from the proxy.
app.add_middleware(FastAPICacheXSessionMiddleware)
```
0.3.9 announced that 0.4.0 would resolve `get_session_manager` (and `SessionManagerDep`, `ClientIPDep` and `rotate_session_id()`, which use it) through `SessionManagerProxy` only ([#131](https://github.com/allen0099/FastAPI-CacheX/issues/131)), and emitted a `FutureWarning`. Since sessions are deprecated ([#420](https://github.com/allen0099/FastAPI-CacheX/issues/420)), 0.4.0 does not make this change. It keeps returning the manager the middleware stored on `app.state` and no longer warns. If you already call `SessionManagerProxy.set()`, keeping it is harmless.

### UserSessionDep {#user-session-dep}

Expand Down Expand Up @@ -196,19 +213,10 @@ SessionConfig(

### Token sources {#token-source-priority}

In 0.4.0, `SessionConfig.token_source_priority` names every token source ([#75](https://github.com/allen0099/FastAPI-CacheX/issues/75)). `FastAPICacheXSessionMiddleware` resolves the token by walking the list, `"cookie"` may appear anywhere in it, and the default becomes `["header", "bearer", "cookie"]`, which is the order used today. A list without `"cookie"` means no cookie: the middleware neither reads nor sets it, and a session created for a request without a token sends its token in the `header_name` response header. That is how an API-only app turns the cookie off.

In 0.3.9, `"cookie"` is accepted as the last entry (where the cookie is read today, so it changes nothing yet), and `FastAPICacheXSessionMiddleware` emits a `FutureWarning` when the list was set explicitly without it. The default list does not warn.

```python
# Before: the cookie is read after these, although the list does not say so
SessionConfig(secret_key=SECRET, token_source_priority=["bearer", "header"])

# After, keeping the cookie (works on 0.3.9 and 0.4.0)
SessionConfig(secret_key=SECRET, token_source_priority=["bearer", "header", "cookie"])
```
0.3.9 announced two changes here. Since sessions are deprecated ([#420](https://github.com/allen0099/FastAPI-CacheX/issues/420)), 0.4.0 makes neither of them:

`use_bearer_token` is removed ([#377](https://github.com/allen0099/FastAPI-CacheX/issues/377)); the list alone decides whether bearer tokens are read. 0.3.9 emits a `DeprecationWarning` when it is passed, whatever its value:
- **`token_source_priority` naming every token source ([#75](https://github.com/allen0099/FastAPI-CacheX/issues/75)) is dropped.** The middleware still reads the session cookie after the header sources whether or not the list names it, and `"cookie"` is still accepted only as the last entry. 0.4.0 no longer emits the `FutureWarning` for a list without `"cookie"`. A list that already ends in `"cookie"` keeps working.
- **`use_bearer_token` is not removed in 0.4.0 ([#377](https://github.com/allen0099/FastAPI-CacheX/issues/377)).** It stays deprecated, still emits a `DeprecationWarning` when it is passed, and is removed in 0.5.0 together with `fastapi_cachex.session`. The list alone decides whether bearer tokens are read:

```python
# Before
Expand Down
31 changes: 11 additions & 20 deletions docs/SESSION.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Session Management Extension

> [!WARNING]
> **Deprecated.** `fastapi_cachex.session` is deprecated in 0.4.0 and removed in 0.5.0 ([#420](https://github.com/allen0099/FastAPI-CacheX/issues/420)). Importing it emits a `FutureWarning`. [Migrating to 0.4.0](MIGRATING_0_4.md#session-state-deprecated) says where to move.

FastAPI-CacheX Session Management provides complete user session handling, including signed
tokens, sliding expiration, and optional IP/User-Agent binding. Session contents always live in
the cache backend; the client only holds a single signed token.
Expand Down Expand Up @@ -64,9 +67,7 @@ keeps the token it gets back and sends it on later requests.
```
<!-- fmt:on -->

The example also registers the manager on `SessionManagerProxy`, where
`get_session_manager` looks for it from 0.4.0 (see
[Migrating to 0.4.0](MIGRATING_0_4.md#get-session-manager)). With the manager
The example also registers the manager on `SessionManagerProxy`. With the manager
there, the middleware can pick it up instead of taking it as an argument. When
`config` is omitted, the middleware uses `session_manager.config`:

Expand Down Expand Up @@ -296,19 +297,13 @@ the expiry reaches that cap no further renewed tokens are issued.
and only falls back to the cookie when none of them yields a token. The response side follows the
token's source (header in, header out; cookie in, `Set-Cookie` out).

Until 0.4.0 the cookie is read whether or not the list names it. `"cookie"` is accepted only as the
last entry, which is where it is read anyway, so listing it changes nothing yet; any other position
raises a `ValidationError`.

In 0.4.0 the list names every token source, and its default becomes `["header", "bearer",
"cookie"]`, the order used today. A list without `"cookie"` then means no cookie at all: the
middleware neither reads nor sets it, and a session created for a request without a token sends
its token in the `header_name` response header ([#75](https://github.com/allen0099/FastAPI-CacheX/issues/75)).
So `FastAPICacheXSessionMiddleware` emits a `FutureWarning` when the list was set explicitly
without `"cookie"`. Add `"cookie"` as the last entry to keep the cookie; the default list does not
warn. See [Migrating to 0.4.0](MIGRATING_0_4.md#token-source-priority).
The cookie is read whether or not the list names it. `"cookie"` is accepted only as the last
entry, which is where it is read anyway, so listing it changes nothing; any other position raises a
`ValidationError`. (0.3.9 announced that 0.4.0 would make the list name every token source; that
change was dropped when sessions were deprecated. See
[Migrating to 0.4.0](MIGRATING_0_4.md#token-source-priority).)

`use_bearer_token` is deprecated and removed in 0.4.0 ([#377](https://github.com/allen0099/FastAPI-CacheX/issues/377)):
`use_bearer_token` is deprecated and removed in 0.5.0 with this package ([#377](https://github.com/allen0099/FastAPI-CacheX/issues/377)):
passing it emits a `DeprecationWarning`. Instead of `use_bearer_token=False`, leave `"bearer"` out
of the list (`token_source_priority=["header", "cookie"]`); `use_bearer_token=True` is the
default and can simply be dropped.
Expand Down Expand Up @@ -642,11 +637,7 @@ from fastapi_cachex.session.dependencies import (

`get_session_manager` returns the manager the middleware stored on `app.state` when it handled
its first request; it responds with `500` if no session middleware has run yet. Using it avoids
importing the manager into your route modules. From 0.4.0 it resolves the manager through
`SessionManagerProxy` instead, so register it there with `SessionManagerProxy.set(manager)`:
until then, `get_session_manager` (and `SessionManagerDep`, `ClientIPDep` and
`rotate_session_id()`, which use it) emits a `FutureWarning` once per app when the proxy holds no
manager or a different one. See [Migrating to 0.4.0](MIGRATING_0_4.md#get-session-manager).
importing the manager into your route modules.

```python
from fastapi_cachex.session import SessionUser
Expand Down
Loading
Loading