State Management
Post-authentication state management strategy. Choose between Session (server memory/Redis) or OAuth2 (JWT Stateless). Each authentication method can be independently configured with a different state.
Overview
Configure state by calling .session() or .oauth2() after an authentication method in the DSL. The AbstractFlowRegistrar.StateSetter applies the state to the most recently added flow.
registry
.form(f -> f.loginPage("/login"))
.session(Customizer.withDefaults()) // form -> Session
.rest(r -> r.loginProcessingUrl("/api/auth"))
.oauth2(Customizer.withDefaults()) // rest -> OAuth2
.mfa(m -> m.primaryAuthentication(...).passkey(...))
.session(Customizer.withDefaults()) // mfa -> Session
.build();
Session vs OAuth2 Comparison
| Category | Session | OAuth2 |
|---|---|---|
| State Storage | Server memory by default, with optional shared Redis-backed storage in distributed deployments | JWT token (Stateless) |
| Suitable For | Traditional web apps, SSR | SPA, API, Microservices |
| Scalability | Works with in-memory session state by default; Redis-backed sharing is optional for multi-instance deployments | Stateless (easy horizontal scaling) |
| Built-in Security | Session fixation protection (sessionFixation().changeSessionId()) | JWT + OIDC + Zero Trust Filter |
| CSRF | Required (cookie-based) | Not required (token-based) |
| Logout | Session invalidation + cookie deletion | Authorization invalidation via CompositeLogoutHandler and DeviceAwareOAuth2AuthorizationService |
Session-Based
Configured via .session(Customizer.withDefaults()). Suitable for traditional web applications and server-side rendering.
Auto-Applied
sessionFixation().changeSessionId()— Session fixation attack protection- Session invalidation + cookie deletion on logout
CompositeLogoutHandlerintegration (Strategy pattern)
Additional Configuration via rawHttp
.form(f -> f
.rawHttp(http -> http.sessionManagement(s -> s
.maximumSessions(1)
.maxSessionsPreventsLogin(true)))
)
.session(Customizer.withDefaults())
OAuth2-Based
Configured via .oauth2(Customizer.withDefaults()). Suitable for SPA, microservices, and API servers.
Auto-Applied
- Resource Server: JWT authentication converter, authentication failure/access denied handlers,
SessionCreationPolicy.STATELESS - Authorization Server:
AuthorizationService,ClientRepository, token endpoint,authenticated_usergrant type, OIDC support - OAuth2 CSRF: Controlled by the
spring.auth.oauth2-csrfconfiguration
authenticated_user Grant Type
A custom grant type that issues OAuth2 tokens to users who have completed Identity authentication (Form, REST, MFA). It bridges traditional authentication with OAuth2 token issuance.
authenticated_user Grant Flow
===============================
[Form/REST/MFA Authentication Complete]
|
v
[AuthenticatedUserGrantAuthenticationProvider]
|
+-- Client Verification
+-- User Lookup (UserRepository)
+-- Scope Resolution
+-- Access Token Generation (JWT)
+-- Refresh Token Generation (optional)
+-- Authorization Persistence (transactional)
|
v
[JWT Token Issuance Complete]
Configuration Properties
Core settings from AuthContextProperties (spring.auth.*).
Core Settings (spring.auth.*)
| Property | Type | Default | Description |
|---|---|---|---|
state-type | enum | OAUTH2 | Authentication state type (OAUTH2, SESSION) |
token-transport-type | enum | HEADER | Token transport method (HEADER, COOKIE, HEADER_COOKIE) |
token-issuer | enum | INTERNAL | Token issuer (INTERNAL, AUTHORIZATION_SERVER) |
factor-selection-type | enum | SELECT | MFA factor selection strategy |
access-token-validity | long (ms) | 3600000 (1h) | Access token validity period |
refresh-token-validity | long (ms) | 604800000 (7d) | Refresh token validity period |
refresh-rotate-threshold | long (ms) | 43200000 (12h) | Refresh-token rotation threshold |
enable-refresh-token | boolean | true | Enable refresh token |
allow-multiple-logins | boolean | false | Allow concurrent multiple logins |
max-concurrent-logins | int | 3 | Maximum concurrent login count |
cookie-secure | boolean | true | Cookie Secure flag |
token-persistence | String | "memory" | Preferred token persistence mode exposed to generated login and MFA pages / SDK |
token-prefix | String | "Bearer " | Token prefix |
roles-claim | String | "roles" | JWT roles claim |
scopes-claim | String | "scopes" | JWT scopes claim |
oauth2-csrf | boolean | false | OAuth2 CSRF protection |
TokenTransportType Details
| Value | accessToken | refreshToken |
|---|---|---|
HEADER | HTTP Header | HTTP Header |
COOKIE | Cookie | Cookie |
HEADER_COOKIE (recommended) | HTTP Header | Cookie |
OAuth2 Settings (spring.auth.oauth2.*)
| Property | Default | Description |
|---|---|---|
client-id | default-client | OAuth2 client ID |
client-secret | 173f8245-5f7d-4623-a612-aa0c68f6da4a | Client secret |
issuer-uri | http://localhost:9000 | Token issuer URI |
token-endpoint | /oauth2/token | Authorization Server token endpoint |
scope | read | Default requested scope |
redirect-uri | http://localhost:8080 | Client redirect URI |
authorized-uri | Unset | Optional pre-authorized redirect URI |
jwk-key-store-path | Unset | JWK keystore path |
jwk-key-store-password | Unset | Keystore password |
jwk-key-alias | Unset | Key alias |
jwk-key-password | Unset | Key password |
MFA Settings (spring.auth.mfa.*)
| Property | Default | Description |
|---|---|---|
session-timeout-ms | 600000 (10min) | MFA session timeout |
challenge-timeout-ms | 300000 (5min) | Challenge timeout |
inactivity-timeout | 900000 (15min) | Inactive MFA session timeout |
cache-ttl | 300000 (5min) | Cached MFA state TTL |
session-refresh-interval-ms | 30000 (30s) | Interval for refreshing active MFA session state |
state-machine-timeout-ms | 10000 (10s) | State machine execution timeout |
max-retry-attempts | 5 | Maximum retry attempts |
account-lockout-duration-ms | 900000 (15min) | Account lockout duration |
minimum-delay-ms | 500 | Minimum delay between sensitive MFA operations |
otp-token-validity-seconds | 300 | OTP validity period (seconds) |
otp-token-length | 6 | OTP code length |
sms-resend-interval-seconds | 60 | Minimum interval between SMS resends |
email-resend-interval-seconds | 120 | Minimum interval between email resends |
device-remember-duration-ms | 2592000000 (30d) | Device trust retention period |
state-machine-pool-size | 100 | State machine worker pool size |
state-machine-cache-ttl-ms | 300000 (5min) | Cached state machine state TTL |
circuit-breaker-failure-threshold | 5 | Circuit breaker failure threshold |
circuit-breaker-timeout-seconds | 30 | Circuit breaker timeout |
detailed-logging-enabled | false | Enable verbose MFA debug logging |
metrics-enabled | true | Enable MFA metrics |
audit-logging-enabled | true | Enable MFA audit logging |
session-storage-type | http-session | Preferred MFA session storage type |
auto-select-repository | false | Automatically choose the session repository |
repository-priority | redis,memory,http-session | Repository selection priority order |
fallback-repository-type | http-session | Fallback repository type |
MFA Nested Settings
| Prefix | Description | Representative Defaults |
|---|---|---|
spring.auth.mfa.http-session.* | HTTP-session-backed MFA storage options | enabled=true, session-attribute-name=MFA_SESSION_ID |
spring.auth.mfa.redis.* | Redis-backed MFA storage options for distributed deployments | key-prefix=mfa:session:, cookie-name=MFA_SID, same-site=Strict |
spring.auth.mfa.memory.* | In-memory MFA storage tuning | cleanup-interval-minutes=5, max-sessions=10000 |
spring.auth.mfa.sms-factor.* | SMS factor delivery settings | provider=default, template-id=mfa_sms_template, enabled=true |
spring.auth.mfa.email-factor.* | Email factor delivery settings | from-address=noreply@company.com, template-id=mfa_email_template, enabled=true |
application.yml Example
spring:
auth:
state-type: OAUTH2
token-transport-type: header_cookie
access-token-validity: 3600000
enable-refresh-token: true
oauth2:
client-id: my-client
issuer-uri: https://auth.example.com
jwk-key-store-path: classpath:keystore.jks
mfa:
session-timeout-ms: 600000
otp-token-validity-seconds: 300
session-storage-type: redis
redis:
key-prefix: mfa:session:
cookie-name: MFA_SID