Files
Flash5/flash-extensions/flash-ext-auth-core/docs/sessions.md
T
Zakaria El Orche 829b9bf348 feat(ext-mcp): let applications put middleware on the MCP route, and document the auth split
McpExtension built its middleware chain entirely internally, so a consumer had no
way to add rate limiting, audit logging or tracing to /mcp — routine on every other
Flash route. McpConfig.middleware(...) appends to the chain after the transport
guards and after whatever McpSecurity resolved to, so it composes with OAuth2
protection instead of replacing it, and never satisfies REQUIRED.

Docs: flash-ext-auth-core and flash-ext-auth-oidc both get a docs/ directory —
oidc had none at all, and its module README documented types that no longer exist.
Includes a migration table from flash-ext-oidc.
2026-09-10 19:12:44 +00:00

1.8 KiB

Sessions

A Session is what a credential source keeps server-side between requests, looked up by a cookie. Core owns the container; what goes in it is the source's business.

public final class Session {
    String              id();
    Map<String, Object> claims();
    Instant             expiresAt();
    Map<String, Object> attributes();
    boolean             isExpired();
    Object              attribute(String key);
    String              attributeAsString(String key);
}

Why it expires early

isExpired() returns true 30 seconds before expiresAt. Without that window a session can pass the check at the top of a request and be dead by the time the handler uses it — a class of failure that reproduces once a day and never in a test. Renewal is therefore always slightly premature, on purpose.

Attributes

attributes() is opaque to this module. flash-ext-auth-oidc keeps its access, id and refresh tokens there under its own keys, which is what lets renewal stay entirely inside that extension while the session itself carries no OAuth2 vocabulary.

Store what your source needs to renew or revoke, and nothing a handler should be reading — handlers read claims().

The store

public interface SessionStore {
    void save(Session session);
    Optional<Session> find(String sessionId);
    void delete(String sessionId);
}

InMemorySessionStore is the default: a ConcurrentHashMap, fine for a single instance, and it loses every session on restart. Supply your own for Redis or JDBC when sessions have to survive a deploy or be shared across nodes.

Sessions are immutable. Renewing one builds a new instance with the same id() and saves it over the old — there is no mutate-in-place path, so a store can cache or serialise freely.