Spring Security JWT user becoming null

1 day ago 3
ARTICLE AD BOX

I'm implementing authentication using Spring Security with JWT.

My login and register endpoints were working correctly before adding JWT. However, after implementing JWT and adding the security filter, I started getting the following error when trying to log in:

java.lang.NullPointerException: Cannot invoke "org.springframework.security.core.userdetails.UserDetails.getAuthorities()" because "user" is null at br.com.gustavo.numa.infra.security.SecurityFilter.doFilterInternal(SecurityFilter.java:33) ~[classes/:na]

My question

Why is user becoming null after validating the JWT token?

Code

Below is my implementation:

SecurityConfiguration

@Configuration @EnableWebSecurity public class SecurityConfiguration { @Autowired SecurityFilter securityFilter; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception{ return httpSecurity .csrf(csrf -> csrf.disable()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(authorize -> authorize .requestMatchers(HttpMethod.POST, "/auth/login").permitAll() .requestMatchers(HttpMethod.POST, "/auth/register").permitAll() .requestMatchers(HttpMethod.GET, "/test").hasRole("USER") .anyRequest().authenticated() ) .addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class) .build(); } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception{ return authenticationConfiguration.getAuthenticationManager(); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }

SecurityFilter

@Component public class SecurityFilter extends OncePerRequestFilter { @Autowired TokenService tokenService; @Autowired UserRepository userRepository; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { var token = this.recoverToken(request); if (token != null) { var login = tokenService.validateToken(token); UserDetails user = userRepository.findByEmail(login); var authentication = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authentication); } filterChain.doFilter(request, response); } private String recoverToken(HttpServletRequest request) { var authHeader = request.getHeader("Authorization"); if (authHeader == null) return null; return authHeader.replace("Bearer ", ""); } }

TokenService

@Component public class TokenService { @Value("${api.security.token.secret}") private String secret; public String generateToken(User user) { try { Algorithm algorithm = Algorithm.HMAC256(secret); return JWT.create() .withIssuer("auth-api") .withSubject(user.getEmail()) .withExpiresAt(genExpirationDate()) .sign(algorithm); } catch (JWTCreationException exception) { throw new RuntimeException("Error while generating token"); } } public String validateToken(String token) { try { Algorithm algorithm = Algorithm.HMAC256(secret); return JWT.require(algorithm) .withIssuer("auth-api") .build() .verify(token) .getSubject(); } catch (JWTVerificationException exception) { return ""; } } private Instant genExpirationDate() { return LocalDateTime.now().plusHours(2).toInstant(ZoneOffset.of("-03:00")); } }
Read Entire Article