Distributed backends for multi-instance deployments live in a separate module, github.com/thuongh2/go-security-redis, so go-security’s own go.mod never gains a Redis client — only applications that actually need Redis pay that dependency cost. That module is not part of this repository; this page documents the contracts it must satisfy, per docs/INTEGRATION.md, so you know what to expect from it (or what to implement yourself against any other backend — Postgres, DynamoDB, etc.).

Installation

Why a separate module

Adding a Redis client to go-security’s go.mod would force every application using go-security to pull it in, even ones that use Postgres or an in-memory store. The separate module depends on go-security in one direction only; import it in your app, not in go-security itself.

Adapter contracts

An adapter is just a Go type implementing one of go-security’s existing store/repository interfaces — there is no Redis-specific type in go-security itself. Four contracts matter for a distributed deployment: A non-atomic IncrAndExpire (read the count, then write count+1 and an expiry as two separate round trips) is a rate-limit-bypass vulnerability: an attacker parallelizes requests and each one reads the stale count before any write lands, letting far more than the configured limit through. Implement it as a single Lua script or pipeline:
Note there is no separate OAuth2 “state store”: the OAuth2 login flow stores its in-flight authorization request (state, PKCE verifier, nonce) as an attribute on the same session.Session that session.Store already persists (see oauth2.LoginConfig.Store). Implementing session.Store over Redis covers OAuth2 state for free — there is no oauth2.WithStateStore or similar option to configure separately.

Wiring an adapter in

For lockout, a Redis-backed Store drops straight into the same Policy/GuardProvider wiring documented in lockout — nothing else changes:
ratelimit is different: NewTokenBucketLimiter is in-process only, and ratelimit.Store has no built-in bridge to ratelimit.Limiter/Middleware in this repo — nothing here converts a Store into something securityhttp.WithRateLimit or ratelimit.Middleware can consume. An adapter module that wants a distributed rate limiter therefore implements ratelimit.Limiter itself (Allow/AllowN) with Redis fixed-window logic inside, using the ratelimit.Store shape (and StoreConformance) to prove that inner logic is correct — it is a correctness contract for the adapter’s internals, not a plug-in point wired up elsewhere in go-security.

Proving an adapter: the conformance harness

Both ratelimit and lockout export a test harness so an adapter proves parity with the in-memory reference — atomic increment (no lost updates under concurrency), window/lock TTL honored, and reset — in the adapter module’s own CI:
The bundled ratelimit.MemoryStore and lockout.MemoryStore pass these same harnesses — they are the executable definition of each contract, not just prose.

Connection pooling

Reuse a single Redis client across every adapter; a well-behaved client is thread-safe and manages its own pool. Configure pool size and credentials once at the client level, not per adapter.

See also

  • docs/INTEGRATION.md — Step 6 and “Adapter contracts” for the full spec this page summarizes.
  • ratelimitratelimit.Store, ratelimit.StoreConformance.
  • lockoutlockout.Store, lockout.StoreConformance.