Skip to main content

Command Palette

Search for a command to run...

Authenticating WebSocket Connections with JWT in Spring Boot

In modern web applications, WebSocket provides a seamless, bidirectional communication channel that enhances user experiences, especially for real-time applications. But with this power comes responsibility: ensuring secure communication is param...

Published
4 min read
Authenticating WebSocket Connections with JWT in Spring Boot
T

I am Tuanh.net. As of 2024, I have accumulated 8 years of experience in backend programming. I am delighted to connect and share my knowledge with everyone.

1. Understanding the Basics of WebSocket Authentication

1.1 What is WebSocket?

WebSocket is a communication protocol that provides full-duplex communication over a single TCP connection. Unlike HTTP, which is stateless, WebSocket keeps connections open, enabling real-time data exchange.

1.2 Why Use JWT for WebSocket Authentication?

JWT offers a compact, self-contained way to securely transmit information between parties. It is widely used for authenticating HTTP requests and is equally applicable to WebSocket connections.

  • Compact: JWT tokens are small and easy to transmit.
  • Secure: Supports claims that are cryptographically signed.
  • Stateless: No need to store session data on the server.

1.3 Challenges in WebSocket Authentication

Unlike HTTP requests, WebSocket connections don’t include headers like Authorization in the same straightforward manner. Authentication must be handled at the handshake phase, making integration with JWT slightly more complex.

2. Configuring WebSocket Authentication with JWT in Spring Boot

2.1 Setting Up the WebSocket Endpoint

Spring Boot provides built-in support for WebSocket using @EnableWebSocket and @EnableWebSocketMessageBroker. Begin by configuring your WebSocket endpoint.

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOrigins("*")
.withSockJS();
}
}

This configuration defines a WebSocket endpoint /ws and sets up a message broker for communication.

2.2 Adding JWT Authentication During the WebSocket Handshake

To authenticate WebSocket connections, intercept the handshake request and validate the JWT. This involves creating a custom HandshakeInterceptor.

Example: Implementing a HandshakeInterceptor

@Component
public class JwtHandshakeInterceptor implements HandshakeInterceptor {

private final JwtTokenProvider jwtTokenProvider;

public JwtHandshakeInterceptor(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}

@Override
public boolean beforeHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {

if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
String token = servletRequest.getServletRequest().getParameter("token");

if (token != null && jwtTokenProvider.validateToken(token)) {
// Add user details to attributes for later use
attributes.put("user", jwtTokenProvider.getUserFromToken(token));
return true;
}
}
return false; // Reject the handshake if token is invalid
}

@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {
// No-op
}
}

In this code:

  • The beforeHandshake method extracts the JWT token from the request.
  • The token is validated using a JwtTokenProvider.
  • If valid, user details are added to the attributes map.

2.3 Creating the JWT Token Provider

The JwtTokenProvider encapsulates logic for generating and validating JWT tokens.

@Component
public class JwtTokenProvider {

private final String secretKey = "your-secret-key";

public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1 hour validity
.signWith(SignatureAlgorithm.HS512, secretKey)
.compact();
}

public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
return true;
} catch (JwtException | IllegalArgumentException e) {
return false;
}
}

public String getUserFromToken(String token) {
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
}

2.4 Integrating the Interceptor with WebSocket Configuration

Finally, integrate the custom JwtHandshakeInterceptor into the WebSocket configuration.

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.addInterceptors(new JwtHandshakeInterceptor(jwtTokenProvider))
.setAllowedOrigins("*")
.withSockJS();
}

3. Enhancing Security and Troubleshooting

3.1 Handling Expired Tokens

Expired JWT tokens are a common issue. Ensure clients can refresh tokens using a dedicated HTTP endpoint.

@PostMapping("/auth/refresh")
public ResponseEntity<String> refreshToken(@RequestParam String token) {
if (jwtTokenProvider.validateToken(token)) {
String username = jwtTokenProvider.getUserFromToken(token);
String newToken = jwtTokenProvider.generateToken(username);
return ResponseEntity.ok(newToken);
}
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}

3.2 Logging and Error Handling

Add robust logging to capture invalid handshake attempts. Consider returning specific error codes to clients for better debugging.

4. Conclusion

Securing WebSocket connections with JWT in Spring Boot ensures robust, stateless authentication for real-time applications. By leveraging a handshake interceptor and a well-structured JwtTokenProvider, you can enforce secure access while maintaining the performance and scalability of your application.

If you have questions or need further clarification, feel free to comment below!

Read more at : Authenticating WebSocket Connections with JWT in Spring Boot

More from this blog

T

tuanh.net

540 posts

Are you ready to elevate your Java, OOP, Spring, and DevOps skills? Look no further!