0

I'm storing my authentication token on an http-only cookie. When an user logs-in, an http cookie carrying the token will be set. Here's the code to process the login:

@PostMapping("/processlogin")
@ResponseBody
public ResponseEntity<String> processLogin(
    @RequestBody SigninDataDto signinDataDto,
    HttpServletResponse response
) {
    if(signinDataDto.getUserName()!=null && signinDataDto.getPassword()!=null) {
        String userName = signinDataDto.getUserName();
        String password = Common.sha256Hash(signinDataDto.getPassword());
        boolean rememberMe = signinDataDto.isRememberMe();
        UserDetails customUserDetails = new UserService(userRepository).loadUserByUsername(userName);
        if(password.equals(customUserDetails.getPassword())) {
            //Authenticate by cookie
            Cookie jwtCookie = new Cookie(Constants.JWT_NAME, jwtService.generateToken((CustomUserDetails) customUserDetails));
            if(rememberMe) {
                jwtCookie.setMaxAge(7*24*60*60);
            }
            jwtCookie.setPath("/");
            jwtCookie.setHttpOnly(true);
            response.addCookie(jwtCookie);
            return ResponseEntity.ok("success");
        }
    }
    log.error("Login failed!");
    return ResponseEntity.badRequest().body("failed");
}

Then i made a filter to authenticate each request by getting the token cookie and verify it. Here's the filter code:

package com.springdemo.library.security;

import com.springdemo.library.services.JwtService;
import com.springdemo.library.services.UserService;
import com.springdemo.library.utils.Common;
import com.springdemo.library.utils.Constants;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private JwtService jwtService;
    @Autowired
    private UserService customUserDetailsService;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            String jwt = getJwt(request);

            if (StringUtils.hasText(jwt) && jwtService.validateToken(jwt)) {
                String userName = jwtService.getUserNameFromJWT(jwt);
                UserDetails userDetails = customUserDetailsService.loadUserByUsername(userName);
                if(userDetails != null) {
                    UsernamePasswordAuthenticationToken
                            authentication = new UsernamePasswordAuthenticationToken(userDetails, null,
                            userDetails.getAuthorities());
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                    SecurityContextHolder.getContext().setAuthentication(authentication);
                } else {
                    response.sendRedirect("/login");
                }
            }
        } catch (Exception ex) {
            log.error("failed on set user authentication", ex);
        }

        filterChain.doFilter(request, response);
    }

    private String getJwt(HttpServletRequest request) {
        Cookie cookie = Common.getCookie(request, Constants.JWT_NAME);
        if(cookie!=null) {
            String token = cookie.getValue();
            if(StringUtils.hasText(token)) {
                return token;
            }
        }
        return null;
    }
}

Security config:

@Bean
protected SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http.csrf(AbstractHttpConfigurer::disable)
            .authorizeRequests(authorizeRequests ->
                    authorizeRequests
                            .requestMatchers("/login", "/processlogin").permitAll()
                            .anyRequest().authenticated()
            );
    http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    return http.build();
}

It works fine if in the filter I don't check isHttpOnly for the jwt cookie, but if I do, the browser denies access to /Library/home. Please can anyone explain why can't the filter verify isHttpOnly for the jwt cookie, eventhough I set the cookie as HttpOnly? And any way to check if a cookie is HttpOnly in Java/Spring Boot?

Here's the JavaScript code that I used to login

$('document').ready(function () {
    $('#id-form-login').on('submit', function (e) {
        e.preventDefault();
        $.ajax({
            url: '/Library/processlogin',
            method: 'POST',
            contentType: 'application/json',
            data: JSON.stringify({
                userName: $("#login-username").val(),
                password: $("#login-password").val(),
                rememberMe: $("#rememberme").prop("checked")
            }),
            success: function () {
                window.location.replace("/Library/home");
            },
            error: function (jqXHR, textStatus, errorThrown) {
                console.warn('Error:', textStatus, errorThrown);
            }
        });
    });
});

Appreciate anyone who helps

3
  • Can you please explain what you actually mean by, "It works fine if in the filter I don't check isHttpOnly for the jwt cookie" - what "check" are you referring to here? Commented May 28, 2024 at 9:58
  • I mean i want to check if the cookie is httponly, if it's not, the request is denied. Commented May 28, 2024 at 10:05
  • You can not "check" that for a cookie that you receive from the client. All you get is the name=value pair, all other "options" used when the cookie was set, will not get send back to the server. Commented May 28, 2024 at 10:08

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.