I'm developing the backend for a web application using the Java Spring Framework and Spring Security. I'm trying to create a login system using JWT, by sending the JWT access token from the server to the client as cookies using the Set-Cookie header.
When I'm testing on localhost with Postman, I seem to have no problems. However, when trying to send the cookies to a client on another pc, the Set-Cookie header seems to get refused by the client.
This is the logic for receiving a login request from the client, and returning a JWT access token if the login is valid :
@PostMapping("/login")
public ResponseEntity<?> authenticate(HttpServletRequest request, HttpServletResponse response, @RequestBody AuthRequestDTO requestDTO){
// Verify the client's login (username and password)
AuthDTO responseDTO = authService.authenticate(requestDTO);
// Set JWT access token if the client's login details are valid
ResponseCookie cookieAccessToken = ResponseCookie.from("accessToken", responseDTO.getAccessToken())
.maxAge(Duration.ofMinutes(5))
.domain(request.getRemoteAddr())
.sameSite("Lax")
.secure(false)
.httpOnly(true)
.build();
// Add access token as "Set-Cookie" key-value in HTTP response header.
response.addHeader(HttpHeaders.SET_COOKIE, cookieAccessToken.toString());
log.info("Access Token Cookie : " + cookieAccessToken.toString());
return ResponseEntity.ok().body(null);
}
I feel that the main point is regarding the ResponseCookie methods. I've tried changing up many of the method options but to no avail. If anyone has worked with sending cookies over a HTTP connection (not HTTPS - due to the code being in early development), I would appreciate help on this matter.
For reference, this is my Spring Security config settings (AUTH_WHITELIST allows access to the login API without needing an access token, and jwtAuthenticationFilter is a spring bean component of my custom implementation of JWT) :
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
http.csrf((csrf) -> csrf.disable())
.headers((header)->header.frameOptions((fo)->fo.sameOrigin()))
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(AUTH_WHITELIST).permitAll()
.requestMatchers("/api/admin").hasAnyRole(ADMIN_MAIN.name(), ADMIN_SUB.name())
.requestMatchers("/api/file").hasAnyRole(ADMIN_MAIN.name(), ADMIN_SUB.name())
.requestMatchers("/**").hasAnyRole(ADMIN_MAIN.name(), ADMIN_SUB.name(), USER_ENTERPRISE.name(), USER_INDIVIDUAL.name(), VISITOR.name())
.anyRequest().authenticated());
http.sessionManagement((sessionManagement) -> sessionManagement
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
http.logout((logout) -> logout.logoutUrl("/api/auth/logout").addLogoutHandler(logoutHandler)
.logoutSuccessHandler((request, response, authentication) -> SecurityContextHolder.clearContext()));
return http.build();
}
I've tried accessing the login API from several clients. I tried accessing the login API on Google Chrome, Mozilla Firefox, and Postman from another pc (i.e. different IP address from the server).
EDIT : I do have CORS configured in a separate file.
@Override
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE");
}
EDIT 2 : I've also tried explicitly setting the IP of the client pc as the domain. For some baffling reason that didn't seem to work either.
Couple things:
request.getRemoteAddr(), you could explicitly set the domain to your application domain orlocalhostfor testing