Skip to content

feat(security): persistent OAuth2 token store — Redis + Postgres (v26.06.69)#96

Merged
ancongui merged 1 commit into
mainfrom
feat/persistent-token-store
Jun 7, 2026
Merged

feat(security): persistent OAuth2 token store — Redis + Postgres (v26.06.69)#96
ancongui merged 1 commit into
mainfrom
feat/persistent-token-store

Conversation

@ancongui
Copy link
Copy Markdown
Contributor

@ancongui ancongui commented Jun 7, 2026

Fixes the audit's multi-instance production blocker: the OAuth2 authorization server's TokenStore was in-memory only (refresh tokens lost on restart; no cross-instance revocation). Now pluggable via pyfly.security.oauth2.token-store.provider:

  • RedisTokenStore (redis) — JSON values with TTL = refresh-token lifetime (self-evicting); fast distributed revocation.
  • PostgresTokenStore (postgres) — durable/auditable rows; lazy idempotent table create; table name validated against injection.
  • memory (default) unchanged.

Hexagonal: Redis client / SQLAlchemy engine obtained in the composition root + injected; adapters import no driver at module scope. Validated against real Redis + real Postgres (testcontainers: store/find/upsert/revoke). Unit + integration tests. Gates: mypy --strict (636), ruff+format, full suite 3938.

…gres) + bump v26.06.69

The authz server's TokenStore was InMemoryTokenStore only -> refresh tokens lost on restart + no
cross-instance revocation (multi-instance production blocker, per the ports/adapters audit). Now
pluggable via pyfly.security.oauth2.token-store.provider=memory|redis|postgres:
- RedisTokenStore (security/adapters/redis_token_store.py): JSON + EX ttl (refresh-token lifetime).
- PostgresTokenStore (security/adapters/postgres_token_store.py): durable table, lazy idempotent
  create, table-name validated. Lazy injected AsyncEngine.
Hexagonal: drivers obtained in the composition root + injected; no module-scope driver imports.

Tests: tests/security/test_persistent_token_store.py (unit, fake clients) + tests/integration/
test_token_store_integration.py (real Redis + real Postgres). Gates: mypy --strict (636), ruff +
format, full suite 3938 passed.
@ancongui ancongui merged commit 8bee9b5 into main Jun 7, 2026
5 checks passed
@ancongui ancongui deleted the feat/persistent-token-store branch June 7, 2026 19:02
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.

1 participant