reactjsspringcookieshttp-headerssetcookie

Spring -> React : cannot set-cookie in any ways


I know I know, there are THOUSANDS of forums and questions where people get to make it work, and I've followed ALL of their suggestions, but I still cannot make it right and I'm literally wasting days on this, hopefully someone will help me out.

So, I have a controller in Spring, annotated :

@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")

From this controller, I'm returning the header for the set-cookie:

return ResponseEntity.ok()
                .header(HttpHeaders.SET_COOKIE, my_cookie)
                ...

my_cookie is made this way:

ResponseCookie.from("cookie_name", value)
                .path("/")
                .httpOnly(true)
                .secure(false)
                .domain("localhost")
                .build()
                .toString();

Before you say anything, yes I've tried ALL of possible combinations that I've found on the internet:

secure false|true --> which as I understand true is only for https, so should be false for localhost tests

domain --> I've tried with localhost, localhost.org, localhost.test, my.localhost.org, no domain at all...

samesite --> either strict|none|lax , I've tried all of them in all combinations with other flags.

Spring is on port 8080.

Then, in react, on port 3000, I'm calling for authentication:

async function login(email, password) {
    await fetch("http://localhost:8080/auth/login", {
      method: "POST",
      body: JSON.stringify({
        email: email,
        password: password,
      }),
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
      },
    })
      .then((response) => {
        return response.json();
      })
      .then((json) => {
        if (json.error) {
          const error = json.error;
          setShowError(true);
          setError(errorMap.get(error));
          return;
        }
        const token = json.payload.token;
        const refreshToken = json.payload.refreshToken;
        const name = json.payload.name;
        setCookie("token", token);
        setCookie("refreshToken", refreshToken);
        setCookie("name", name);
      })
      .catch(() => {
        setShowError(true);
        setError("Error from server");
      });
  }

So, the 3 cookies get set, as I do it from react. But the set-cookie from spring does NOT get set on the Application --> localhost:3000 cookies. I instead get the cookie on postman. I know it's browser related, but I just want to point out that I correctly get the cookie set on postman.

Looking at the console in browser, the Set-Cookie header is there, and there is also the tab "Cookies" inside the request panel. It just gets no set on the browser's cookie side.

Moreover, when I call subsequent requests, I can't see the 3 cookies in requests. As I understand, cookies should be always included in requests towards BE, the browser does that automatically, right?

There seems to be wee details I'm missing, I know. I've tried those domains with .test, .org,... because I've read of the docs about Set-Cookie header in response and read about the double dots/3 dots etc... so I've tried them too.

Please help me out of this, It's been days trying different combinations. I also tried with Firefox, same results.


Solution

  • Solved it finally !!! Actually there were 2 mistakes: first one, I was missing credentials: "include" in react when calling for auth/login. Second mistake, I was setting the cookie with name "__Secure-", which is not preferrable for the browser. So I just took "__" out.

    Settings that work that I'm using now:

    ResponseCookie.from("Secure-name", cookieValue)
                    .path("/")
                    .httpOnly(true)
                    .secure(false)
                    .domain("localhost")
                    .build()
                    .toString();
    

    localhost:3000 react

    localhost:8080 spring

    @CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true")
    

    on Auth controller.

    Moreover, all cookies are now sent correctly on subsequent requests.