Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot get cookies in Java Spring Boot / Angular application

I am working on a Angular11 frontend app coupled with a Java Spring boot backend.

Context

I am trying to create an authentication with cookies with JWT. To do so I am inspired by

  • JWT refresh token flow
  • Access token and Refresh token best practices ? How to implement Access & Refresh Tokens

My endpoint /authenticate returns a jwt access token and set a jwt refresh token in the cookies (httpOnly).
My endpoint /refreshtoken gets the refresh token from the cookies and validates it before generating a new jwt access token and a new jwt refresh token.
Here is the code of my AuthenticationController

    @RestController
    @AllArgsConstructor
    @CrossOrigin(origins = "http://localhost:4200", allowCredentials = "true")
    public class AuthenticationController {
        
            private final AuthenticationManager authenticationManager;
            private final JwtTokenUtil jwtTokenUtil;
            private final UserDetailsServiceImpl userDetailsService;
            private final static String REFRESH_TOKEN_COOKIE = "resfreshtoken";
        
            @PostMapping(value = "/authenticate")
            public ResponseEntity<JwtAuthenticationResponse> createAuthenticationToken(@RequestBody JwtAuthenticationRequest authenticationRequest, HttpServletResponse response) throws Exception {
                try {
                    this.authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword()));
                }
                catch (DisabledException e) {
                    throw new Exception("USER_DISABLED", e);
                }
                catch (BadCredentialsException e) {
                    throw new Exception("INVALID_CREDENTIALS", e);
                }
                final UserDetails userDetails = this.userDetailsService.loadUserByUsername(authenticationRequest.getUsername());
                final String token = this.jwtTokenUtil.generateToken(userDetails.getUsername());
                final String refreshToken = this.jwtTokenUtil.generateRefreshToken(new HashMap<>(), userDetails.getUsername());
        
                Cookie cookie = new Cookie(REFRESH_TOKEN_COOKIE, refreshToken);
                cookie.setHttpOnly(true);
                // cookie.setDomain("localhost");
                // cookie.setPath("/");
                response.addCookie(cookie);
        
                return ResponseEntity.ok(new JwtAuthenticationResponse(token));
            }
        
            @GetMapping(value = "/refreshtoken")
            public ResponseEntity<?> refreshToken(@CookieValue(value = REFRESH_TOKEN_COOKIE, required = false) String refreshToken, HttpServletRequest request, HttpServletResponse response) {
                Cookie[] cookies = request.getCookies(); // ALWAYS returns null
                log.debug("refreshToken {}", refreshToken); // ALWAYS null
                try {
                    Claims claims = this.jwtTokenUtil.getAllClaimsFromToken(refreshToken);
                    final String username = claims.get("sub").toString();
                    final String newAccessToken = this.jwtTokenUtil.generateToken(username);
                    final String newRefreshToken = this.jwtTokenUtil.generateRefreshToken(claims, username);
                    CookieUtil.writeCookie(response, REFRESH_TOKEN_COOKIE, newRefreshToken);
        
                    return ResponseEntity.ok(new JwtAuthenticationResponse(newAccessToken));
                }
                catch (SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException ex) {
                    throw new BadCredentialsException("INVALID_CREDENTIALS", ex);
                }
                catch (ExpiredJwtException e) {
                    // user should re-login
                }
    
                  return new ResponseEntity<>("Something went wrong", HttpStatus.BAD_REQUEST);
                }
        }

On Angular frontend, here are the options I add to my /refreshtoken Http request (withCredentials=true)

refreshToken(): Observable<AuthenticationResponse> {
        return this.http.get<AuthenticationResponse>(this.apiUrl + 'refreshtoken', { withCredentials: true }).pipe(
            tap(response => LocalStorageUtils.save(LocalStorageKey.JWT_ACCESS_TOKEN_KEY, response.jwtAccessToken))
        );
    }

My issue

If I try to reach my endpoint /authenticate then /refreshtoken from postman, everything works well and I can see the cookie
If I call /authenticate from my frontend, I can see the cookie in the response with the header SET-COOKIE (and in the cookies tab) enter image description here But then if I call /refreshtoken from my frontend, I cannot get the cookies with request.getCookies() nor @CookieValue() on the backend, it always returns null !
It seems like the cookie is well received on the frontend but not set anywere (I cannot see it in application tab -> cookies on Chrome).
Therefore it is not sent with the /refreshtoken request

If anyone can help or has an idea about what is going wrong, I would be grateful ! I can provide more details about my code if it is needed.

like image 908
TCH Avatar asked Oct 22 '25 13:10

TCH


1 Answers

You need to add withCredentials: true to your httpOptions and pass it with HttpClient every request. You can also configure it globally with HttpClient and Interceptors.

like image 146
Keshavram Kuduwa Avatar answered Oct 25 '25 07:10

Keshavram Kuduwa



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!