-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Summary
Add a pluggable QSessionStoreProviderInterface QBit that allows applications to persist full QSession state (including security keys and custom data) between requests and across server restarts.
Background
Issue #334 added customizer support to OAuth2AuthenticationModule, enabling applications to inject security keys via customizeSession(). This works well when key derivation is cheap (static lookups or JWT claim extraction).
For applications with expensive key derivation (e.g., database queries, external API calls), re-deriving keys on every request may be suboptimal. This feature would allow applications to cache/persist the full session state.
Design Decisions
- Location: Separate Maven module
qqq-qbit-session-store - Integration: Explicit config via
QAuthenticationMetaData.withSessionStoreEnabled(true) - Providers: In-Memory, Table-based, and Redis (Strategy Pattern)
Design Pattern: Strategy
┌─────────────────────────────────────────┐
│ QSessionStoreProviderInterface │ ← Strategy Interface
│ (store, load, remove, touch, etc.) │
└─────────────────────────────────────────┘
▲ ▲ ▲
│ │ │
┌─────────┴──┐ ┌──────┴─────┐ ┌───┴────────┐
│ InMemory │ │ TableBased │ │ Redis │ ← Concrete Strategies
│ Provider │ │ Provider │ │ Provider │
└────────────┘ └────────────┘ └────────────┘
▲
│
┌───────┴───────┐
│ Custom impl │ ← User-provided via QCodeReference
└───────────────┘
Proposed Interface
public interface QSessionStoreProviderInterface
{
void store(String sessionUuid, QSession session, Duration ttl);
Optional<QSession> load(String sessionUuid);
void remove(String sessionUuid);
void touch(String sessionUuid); // sliding expiration
void cleanExpired();
String status();
default void configure(QSessionStoreQBitConfig config) {}
}Provider Implementations
- InMemorySessionStoreProvider - ConcurrentHashMap + LRU, for dev/single-server
- TableBasedSessionStoreProvider - QQQ table storage, for persistence
- RedisSessionStoreProvider - Jedis client, for distributed HA
QBitConfig Options
providerType- IN_MEMORY, TABLE_BASED, REDIS, or CUSTOMdefaultTtl- Session expiration (default: 1 hour)enableSlidingExpiration- Reset TTL on accessbackendName- For TABLE_BASED providerredisHost,redisPort,redisPassword,redisKeyPrefix- For REDIScustomProviderCodeReference- For custom implementations
Usage Example
new QSessionStoreQBitProducer()
.withConfig(new QSessionStoreQBitConfig()
.withProviderType(QSessionStoreProviderType.TABLE_BASED)
.withBackendName("primaryBackend")
.withDefaultTtl(Duration.ofHours(8))
.withEnableSlidingExpiration(true))
.produce(qInstance);Implementation TODO
Phase 1: Module Setup
- Create
qqq-qbit-session-storeMaven module - Add to parent pom.xml modules list
Phase 2: Core Interfaces
-
QSessionStoreProviderInterface(Strategy interface) -
QSessionStoreProviderTypeenum -
QSessionStoreProviderFactory -
QSessionStoreQBitConfig
Phase 3: Provider Implementations
-
InMemorySessionStoreProvider+ tests -
TableBasedSessionStoreProvider+StoredSessionentity + tests -
RedisSessionStoreProvider+ tests (Testcontainers)
Phase 4: QBit Producer
-
QSessionStoreQBitProducer -
CleanExpiredSessionsProcess
Phase 5: Auth Module Integration
- Add
sessionStoreEnabledtoQAuthenticationMetaData - Add hooks to
OAuth2AuthenticationModule - Add hooks to
Auth0AuthenticationModule
Phase 6: Testing
- Unit tests for all providers
- Integration tests with auth modules
- Backwards compatibility verification
Related
- Follow-up to Session Security Keys not persisted in OAuth2 flow #334 (Session Security Keys persistence)
- Full design doc:
docs/PLAN-session-store-qbit.md
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request
Type
Projects
Status
Ready