callicoder / spring-boot-react-oauth2-social-login-demo

Spring Boot React OAuth2 Social Login with Google, Facebook, and Github
1.44k stars 702 forks source link

Setting Cookie instead of JWT Token #57

Closed serkanz closed 2 years ago

serkanz commented 2 years ago

Hi,

After a successful Oauth2 authorization, I want to issue a cookie to secure access to my controllers. In order to do this, I added the lines below determineTargetUrl on OAuth2AuthenticationSuccessHandler. This sets a cookie containing JWT token created by TokenProvider.

CookieUtils.addCookie(response, appProperties.getAuth().getAuthenticationCookieName(), token, (int) appProperties.getAuth().getTokenExpirationMsec());

And then I created a CookieAuthenticationFilter similar to TokenAuthenticationFilter which checks the cookie set by OAuth2AuthenticationSuccessHandler.

public class CookieAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private AppProperties appProperties;

    @Autowired
    private TokenProvider tokenProvider;

    @Autowired
    private CustomUserDetailsService customUserDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            Optional<String> jwt = CookieUtils.getCookie(request, appProperties.getAuth().getAuthenticationCookieName()).map(Cookie::getValue);

            if (StringUtils.hasText(String.valueOf(jwt)) && tokenProvider.validateToken(String.valueOf(jwt))) {
                Long userId = tokenProvider.getUserIdFromToken(String.valueOf(jwt));

                UserDetails userDetails = customUserDetailsService.loadUserById(userId);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                SecurityContextHolder.getContext().setAuthentication(authentication);
            }

        } catch (Exception ex) {
            logger.error("Could not set user authentication in security context", ex);
        }

        filterChain.doFilter(request, response);
    }
}

and on SecurityConfig I replaced tokenAuthenticationFilter bean to cookieAuthenticationFilter

http.addFilterBefore(cookieAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

When I run the project, Oauth2 authentication is made successfully and cookie is set. However when I request a secured controller method, CookieAuthenticationFilter.doFilterInternal is not hit and request directly goes to RestAuthenticationEntryPoint.commence and exception is thrown with message Full authentication is required to access this resource .

Do I have to change any more configuration to change authentication to cookie from Bearer (JWT)?

serkanz commented 2 years ago

The problem was a result of a missing exception without catch. The sample and the code works as expected.