What does @EnableRSocketSecurity do, and how do you turn on security for an RSocket server in Spring?
answer
- @EnableRSocketSecurity -> RSocketSecurity builder
- build() -> PayloadSocketAcceptorInterceptor bean
- authorizePayload + simpleAuthentication/jwt
- reactive only, not the HTTP filter chain
- forget it = wide-open RSocket
basics
~10 s@EnableRSocketSecurity turns on Spring Security for RSocket and gives you an RSocketSecurity builder. You use it to create a PayloadSocketAcceptorInterceptor bean that defines who can connect and which routes require authentication.
solid answer
~30 sRSocket is a binary, bidirectional messaging protocol; Spring Security secures it separately from HTTP. You add @EnableRSocketSecurity to a @Configuration class (requires the spring-security-messaging/rsocket dependency and a reactive stack). This exposes an RSocketSecurity builder that you inject to build a PayloadSocketAcceptorInterceptor bean. On that builder you call authorizePayload(...) to declare authorization rules — for example .setup().authenticated() for the connection handshake and .route("secure.*").authenticated() for message routes — and enable an authentication method like simpleAuthentication() or jwt(). Spring wires the interceptor into the RSocket acceptor so every SETUP and REQUEST payload passes through the security rules. Without @EnableRSocketSecurity, RSocket endpoints are wide open.
code
java · 22 lines@Configuration
@EnableRSocketSecurity
public class RSocketSecurityConfig {
@Bean
PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity security) {
security.authorizePayload(authorize -> authorize
.setup().authenticated()
.route("secure.*").authenticated()
.anyRequest().authenticated()
.anyExchange().permitAll())
.simpleAuthentication(Customizer.withDefaults());
return security.build();
}
@Bean
MapReactiveUserDetailsService users() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user").password("pass").roles("USER").build();
return new MapReactiveUserDetailsService(user);
}
}go deeper
Know that @EnableRSocketSecurity exists, needs a PayloadSocketAcceptorInterceptor bean, and that RSocket is secured separately from HTTP.
Explain the RSocketSecurity DSL (authorizePayload, setup vs route vs anyRequest) and wiring the interceptor bean.
Discuss reactive-only nature, security context propagation via Reactor context, and pairing with an AuthenticationManager/UserDetailsService.
Reason about securing RSocket as a first-class channel across a system, threat model of an open acceptor, and consistency with HTTP auth.
**RSocket** is an application-level, binary messaging protocol built on Reactive Streams. It supports four interaction models (request-response, fire-and-forget, request-stream, request-channel), runs over TCP or WebSocket, and is fully asynchronous and bidirectional. Because it is not HTTP, the normal Spring Security web filter chain does not apply — RSocket needs its own security integration. **@EnableRSocketSecurity** is the annotation that activates that integration. You place it on a `@Configuration` class. It requires: (1) the reactive Spring stack, and (2) `spring-boot-starter-rsocket` plus Spring Security's RSocket support (`spring-security-messaging` / `spring-security-rsocket`, pulled in transitively by the security starter). It works with the reactive `RSocketSecurity` DSL — RSocket security in Spring is reactive-only. Activating the annotation publishes an **`RSocketSecurity`** bean — a builder object. You inject it into a `@Bean` method and use it to construct a **`PayloadSocketAcceptorInterceptor`**. This interceptor is what Spring plugs into the RSocket `SocketAcceptor` so that security runs on incoming payloads. Typical minimal config: ```java @Bean PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity security) { security.authorizePayload(authorize -> authorize .anyRequest().authenticated() .anyExchange().permitAll()) .simpleAuthentication(Customizer.withDefaults()); return security.build(); } ``` Key pieces of the DSL: - **`authorizePayload(...)`** — declares authorization rules. Inside it you match on `.setup()` (the connection handshake), `.route("pattern")` (a specific `@MessageMapping` route, using Ant-style/`PathPattern` matching), `.anyRequest()` (any request payload), and `.anyExchange()` (any payload including setup and metadata pushes). - **`simpleAuthentication()` / `jwt()` / `basicAuthentication()`** — declares which authentication method to accept from metadata. **Gotchas:** - If you forget `@EnableRSocketSecurity` (or forget to return the interceptor bean), the RSocket server is unauthenticated — anyone who can open a connection can invoke any route. - RSocket security is **reactive**; there is no servlet/imperative variant. `SecurityContext` is propagated via the Reactor context, so `@MessageMapping` handlers read the principal with `ReactiveSecurityContextHolder` or an `@AuthenticationPrincipal`/`Mono<Principal>` parameter. - You also need an `AuthenticationManager` (e.g. a `MapReactiveUserDetailsService` or a JWT decoder) for the chosen authentication method to validate credentials. **When to use:** any time you expose RSocket endpoints (`@MessageMapping`) that should not be public.
- Why can't the normal HTTP SecurityFilterChain secure RSocket endpoints?RSocket is a separate binary protocol over TCP/WebSocket, not HTTP request/response, so the servlet/WebFlux web filter chain never sees RSocket frames. Security is applied via a PayloadSocketAcceptorInterceptor instead.
- How does an @MessageMapping handler read the authenticated user?Via the reactive security context — accept a Mono<Principal>/@AuthenticationPrincipal parameter or call ReactiveSecurityContextHolder.getContext(). The principal is propagated through the Reactor context, not a ThreadLocal.
saying these in an interview costs you the question
- Thinking the HTTP SecurityFilterChain secures RSocket automatically
- Believing RSocket security has an imperative (non-reactive) variant
- Not returning the PayloadSocketAcceptorInterceptor bean, leaving endpoints open