How to send a HTTP Cookie using the Set-Cookie header over a HTTP connection?

39 Views Asked by At

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.

1

There are 1 best solutions below

1
showprojects On

Couple things:

  1. Check CORS Configuration: Cross-Origin Resource Sharing (CORS) could be prevent the client form accepting cookies from your server. Ensure that your CORS configuration allows credentials (cookies) to be sent with requests. You can do this by configuring CORS in your Spring Security configuration:
@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurer() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowCredentials(true) // Allow cookies
                .maxAge(3600);
        }
    };
}
  1. Check your Cookie domain The domain specified for the cookie might not be valid> Instead of using request.getRemoteAddr(), you could explicitly set the domain to your application domain or localhost for testing
ResponseCookie cookieAccessToken = ResponseCookie.from("accessToken", responseDTO.getAccessToken())
    .maxAge(Duration.ofMinutes(5))
    .domain("yourdomain.com") // Set your domain here
    .path("/") // Set the path if necessary
    .sameSite("Lax")
    .secure(false)
    .httpOnly(true)
    .build();