From spring
Replace container-local sessions with Spring Session across Spring Security, WebFlux, and WebSocket endpoints using a chosen backing store and customized cookies or headers. Use this skill when replacing container-local sessions with Spring Session, choosing a backing session store, customizing session cookies or headers, and integrating shared sessions with Spring Security, WebFlux, or WebSocket endpoints.
npx claudepluginhub ririnto/sinon --plugin springThis skill uses the workspace's default tool permissions.
Use this skill when replacing container-local sessions with Spring-managed shared sessions, choosing a backing store, customizing session id transport, or wiring shared sessions into Spring Security and related web behavior.
Mandates invoking relevant skills via tools before any response in coding sessions. Covers access, priorities, and adaptations for Claude Code, Copilot CLI, Gemini CLI.
Share bugs, ideas, or general feedback.
Use this skill when replacing container-local sessions with Spring-managed shared sessions, choosing a backing store, customizing session id transport, or wiring shared sessions into Spring Security and related web behavior.
Use spring-session for session persistence, clustered session sharing, cookie or header-based session id transport, repository choice, principal-indexed session lookup, and framework integration around HttpSession or WebSession.
spring-session focused on where session state lives and how it is resolved.RedisTemplate usage outside this skill's scope when the task is not primarily about session storage.The ordinary Spring Session job is:
HttpSession or reactive WebSession.SKILL.md for the ordinary servlet path: Redis-backed servlet sessions, explicit timeout and namespace, cookie or header transport choice, indexed-versus-default Redis repository choice, cookie customization, JSON serializer awareness, principal lookup, and store-backed tests.WebSession instead of servlet HttpSession.Prefer the Spring Session module that matches the store, plus the matching data-access starter or driver support. Start with Redis for the common clustered browser-session path unless the deployment already standardizes on a different store.
<dependencies>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
findByPrincipalName(...) or session lifecycle events.spring:
session:
store-type: redis
timeout: 30m
redis:
namespace: app:session
repository-type: indexed
flush-mode: on-save
save-mode: on-set-attribute
data:
redis:
host: localhost
port: 6379
server:
servlet:
session:
cookie:
name: SESSION
http-only: true
secure: true
Use the indexed Redis variant when principal lookup is part of the job.
@Configuration
@EnableRedisIndexedHttpSession
class SessionConfig {
@Bean
CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("SESSION");
serializer.setUseHttpOnlyCookie(true);
serializer.setUseSecureCookie(true);
serializer.setSameSite("Lax");
serializer.setCookiePath("/");
return serializer;
}
}
Use this only when a non-browser client contract requires header transport.
@Bean
HttpSessionIdResolver httpSessionIdResolver() {
return HeaderHttpSessionIdResolver.xAuthToken();
}
The default Redis serializer is acceptable for one application controlling both reads and writes. Switch to JSON serialization when multiple applications, rolling upgrades, or payload inspection requirements make default serialization too brittle.
HttpSession) or reactive (WebSession). Do not mix the two models in examples or configuration.spring.session.timeout and the session namespace or table name explicitly so runtime behavior is obvious in operations.SameSite, JSON payload compatibility, or rolling upgrades matter.HttpSessionListener bridging are additive features, not the ordinary path.WebSession semantics replace servlet HttpSession semantics.@Service
class SessionAdministrationService {
private final FindByIndexNameSessionRepository<? extends Session> sessionRepository;
SessionAdministrationService(FindByIndexNameSessionRepository<? extends Session> sessionRepository) {
this.sessionRepository = sessionRepository;
}
void expireAllSessionsFor(String username) {
Map<String, ? extends Session> sessions =
sessionRepository.findByPrincipalName(username);
for (String sessionId : sessions.keySet()) {
sessionRepository.deleteById(sessionId);
}
}
}
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
class SessionFlowTest {
@Autowired
MockMvc mockMvc;
@Test
void sessionStateIsReusedAcrossRequests() throws Exception {
MvcResult first = mockMvc.perform(post("/cart/items")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"sku\":\"SKU-1\"}"))
.andExpect(status().isOk())
.andReturn();
Cookie sessionCookie = first.getResponse().getCookie("SESSION");
ResultActions secondRequest = mockMvc.perform(post("/cart/items")
.cookie(sessionCookie)
.contentType(MediaType.APPLICATION_JSON)
.content("{\"sku\":\"SKU-2\"}"));
assertAll(
() -> secondRequest.andExpect(status().isOk()),
() -> secondRequest.andExpect(jsonPath("$.itemCount").value(2))
);
}
}
Return:
SameSite, and secure flags with the actual deployment topology before release.