better_auth-redis-storage
Redis secondary storage package for Better Auth Ruby.
This gem tracks the server-side behavior of upstream @better-auth/redis-storage
pinned at Better Auth v1.6.9. The Ruby gem versions independently from the
upstream npm package; BetterAuth::RedisStorage::VERSION is the Ruby gem
version.
Installation
Add the gem and require the package before configuring auth:
gem "better_auth-redis-storage"
require "redis"
require "better_auth/redis_storage"
redis = Redis.new(url: ENV.fetch("REDIS_URL"))
auth = BetterAuth.auth(
secret: ENV.fetch("BETTER_AUTH_SECRET"),
database: :memory,
secondary_storage: BetterAuth.redis_storage(client: redis)
)
The canonical Ruby form is also supported:
storage = BetterAuth::RedisStorage.new(client: redis)
For upstream-shaped call sites, use BetterAuth.redis_storage(client: redis) or
the camelCase class alias:
storage = BetterAuth::RedisStorage.redisStorage(client: redis)
Configuration
storage = BetterAuth::RedisStorage.new(
client: redis,
key_prefix: "better-auth:",
scan_count: nil
)
client must respond to get, set, setex, del, and keys. It should
also respond to scan when scan_count: is configured. This matches the
interfaces exposed by the redis and redis-namespace gems.
key_prefix defaults to "better-auth:". Passing nil falls back to the
default. Any other value, including the empty string, is honored verbatim.
Redis databases are not isolation boundaries for shared clients; applications
sharing a Redis instance should use distinct prefixes.
scan_count is a Ruby-only opt-in for large Redis databases. By default the gem
uses KEYS "#{key_prefix}*" to match upstream exactly. Set scan_count: to a
positive count such as 100, 500, or 1000 to use SCAN instead:
storage = BetterAuth::RedisStorage.new(client: redis, scan_count: 500)
Behavior
The storage object implements the Better Auth secondary storage contract:
storage.get(key)
storage.set(key, value, ttl = nil)
storage.delete(key)
storage.list_keys
storage.clear
listKeys is available as a camelCase alias for upstream parity.
TTL handling for set(key, value, ttl):
| TTL value | Redis command |
|---|---|
nil, non-numeric strings, 0, negative numbers |
set(prefixed_key, value) |
Positive Integer |
setex(prefixed_key, ttl, value) |
Positive Float |
setex(prefixed_key, ttl.to_i, value) |
Positive numeric String |
setex(prefixed_key, ttl.to_i, value) |
set, delete, and clear return nil, mirroring upstream's Promise<void>
contract in Ruby form. Tests and applications should assert stored values via
get rather than relying on truthy return values.
clear intentionally differs from upstream when there are no matching keys:
upstream calls del(...keys) even when keys is empty, while this Ruby gem
skips del to avoid Redis ERR wrong number of arguments for 'del'.
Better Auth Usage
secondary_storage is used by Better Auth for session payload storage,
active-session indexes, verification values, and rate limiting when
rate_limit: { storage: "secondary-storage" } is configured.
auth = BetterAuth.auth(
secret: ENV.fetch("BETTER_AUTH_SECRET"),
database: :memory,
secondary_storage: BetterAuth.redis_storage(client: redis),
rate_limit: { storage: "secondary-storage", enabled: true }
)
Custom secondary storage backends should implement:
get(key)set(key, value, ttl = nil)delete(key)- Optional:
list_keysorlistKeys - Optional:
clear
Testing
The normal unit suite skips real Redis unless explicitly enabled:
bundle exec rake test
Run the Redis integration suite with:
REDIS_INTEGRATION=1 REDIS_URL=redis://localhost:6379/15 bundle exec rake test:integration