title: Null @AuthenticationPrincipal user
body: <p>I want to Secure REST server with JWTs. For this purpose I use <a href="https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/" rel="nofollow noreferrer">this tutorial</a>. All fine, except one thing - I want to get authorized user in the private controllers, when the user already logged in, but getUserInfo method receives user equal to null.</p>
  
  <p>This is private controller, AccountController:</p>
  
  <pre><code>@RestController
  @RequestMapping("/private")
  public class AccountController {
  
      @GetMapping("/getUserInfo")
      public @ResponseBody
      String getUserInfo(@AuthenticationPrincipal final UserDetails user) {// user == null
          return user.getUsername();
      }
  }
  </code></pre>
  
  <p>WebSecurity:</p>
  
  <pre><code>@EnableWebSecurity
  public class WebSecurity extends WebSecurityConfigurerAdapter {
      private AccountDetailsServiceImpl accountDetailsService;
      private BCryptPasswordEncoder bCryptPasswordEncoder;
  
      public WebSecurity(AccountDetailsServiceImpl accountDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
          this.accountDetailsService = accountDetailsService;
          this.bCryptPasswordEncoder = bCryptPasswordEncoder;
      }
  
  
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http.cors().and().csrf().disable().authorizeRequests()
                  .antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
                  .anyRequest().authenticated()
                  .and()
                  .addFilter(new JWTAuthenticationFilter(authenticationManager()))
                  .addFilter(new JWTAuthorizationFilter(authenticationManager()))
                  // this disables session creation on Spring Security
                  .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
      }
  
      @Override
      public void configure(AuthenticationManagerBuilder auth) throws Exception {
          auth.userDetailsService(accountDetailsService).passwordEncoder(bCryptPasswordEncoder);
      }
  
      @Bean
      CorsConfigurationSource corsConfigurationSource() {
          final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
          source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
          return source;
      }
  }
  </code></pre>
  
  <p>AccountDetailsServiceImpl:</p>
  
  <pre><code>@Service
  public class AccountDetailsServiceImpl implements UserDetailsService {
      private AccountRepository applicationUserRepository;
  
      public AccountDetailsServiceImpl(AccountRepository applicationUserRepository) {
          this.applicationUserRepository = applicationUserRepository;
      }
  
      @Override
      public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
          Optional&lt;Account&gt; applicationUser = applicationUserRepository.findByUsername(username);
          if (applicationUser == null) {
              throw new UsernameNotFoundException(username);
          }
          User user = new User(applicationUser.get().getUsername(), applicationUser.get().getPassword(), emptyList());
          return user;
      }
  }
  </code></pre>
  
  <p>Account:</p>
  
  <pre><code>@Entity(name = "Account")
  @Table(name = "account")
  public class Account implements UserDetails {
  
      @Id
      @GeneratedValue(strategy=GenerationType.IDENTITY)
      private Long id;
  
      private String username;
  
      private String password;
  
  
      private Account() { }
  
      public Account(final String username, final String password) {
          this.username = username;
          this.password = password;
      }
  
  
      @Override
      public Collection&lt;GrantedAuthority&gt; getAuthorities() {
          return new ArrayList&lt;&gt;();
      }
  
      @JsonIgnore
      @Override
      public boolean isAccountNonExpired() {
          return true;
      }
  
      @JsonIgnore
      @Override
      public boolean isAccountNonLocked() {
          return true;
      }
  
      @JsonIgnore
      @Override
      public boolean isCredentialsNonExpired() {
          return true;
      }
  
      @Override
      public boolean isEnabled() {
          return true;
      }
  
      public Long getId() {
          return id;
      }
  
      @Override
      public String getUsername() {
          return username;
      }
  
      @Override
      public String getPassword() {
          return password;
      }
  
      public void setPassword(String password) {
          this.password = password;
      }
  }
  </code></pre>
  
  <p>So what is the problem and how can I obtain authorized user using <code>AuthenticationPrincipal</code>?</p>
  
  <p><strong>UPD:</strong></p>
  
  <p>I tried to use </p>
  
  <pre><code>String getUserInfo(@AuthenticationPrincipal final Object user)
  </code></pre>
  
  <p>in my <code>AccountController</code>(I changed type of <code>user</code> to <code>Object</code>) and got <strong>not null object</strong>. After that I tried to obtain the true object type using <code>user.getClass()</code> and got <code>String</code>. Next I tried to change type of the parameter <code>user</code> to <code>String</code> in the <code>getUserInfo</code> signature and got <code>String</code> with the username of the user. So, I can get user info, but with the unsuitable type. I also tried to use <code>Account</code> type but also got <code>null</code>. </p>
  
  <p>So, now the main question how can I get <code>user</code> with <code>Account</code> type using <code>@AuthenticationPrincipal</code>?</p>
  
  <p><strong>UPD2:</strong></p>
  
  <p>Now I also realized that <code>getUserInfo</code> gets <code>UsernamePasswordAuthenticationToken</code> object, so I think I need to change my <code>JWTAuthorizationFilter</code>, but how exactly if <code>SecurityContextHolder.getContext().setAuthentication()</code> needs instance of <code>UsernamePasswordAuthenticationToken</code>?</p>
  
  <p><strong>UPD3:</strong></p>
  
  <p>JWTAuthorizationFilter:</p>
  
  <pre><code>public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
  
      public JWTAuthorizationFilter(AuthenticationManager authManager) {
          super(authManager);
      }
  
      @Override
      protected void doFilterInternal(HttpServletRequest req,
                                      HttpServletResponse res,
                                      FilterChain chain) throws IOException, ServletException {
          String header = req.getHeader(HEADER_STRING);
  
          if (header == null || !header.startsWith(TOKEN_PREFIX)) {
              chain.doFilter(req, res);
              return;
          }
  
          UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
  
          SecurityContextHolder.getContext().setAuthentication(authentication);
          chain.doFilter(req, res);
      }
  
      private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
          String token = request.getHeader(HEADER_STRING);
          if (token != null) {
              // parse the token.
  
              String user = Jwts.parser().setSigningKey(KEY).parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody().getSubject();
  
  
              if (user != null) {
                  return new UsernamePasswordAuthenticationToken(user, null, new ArrayList&lt;&gt;());
              }
              return null;
          }
          return null;
      }
  }
  </code></pre>
  
  <p><strong>UPD4:</strong></p>
  
  <p>JWTAuthenticationFilter.doFilterInternal():</p>
  
  <pre><code>@Override
  protected void doFilterInternal(HttpServletRequest req,
                                  HttpServletResponse res,
                                  FilterChain chain) throws IOException, ServletException {
      String header = req.getHeader(HEADER_STRING);
  
      if (header == null || !header.startsWith(TOKEN_PREFIX)) {
          chain.doFilter(req, res);
          return;
      }
  
      UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
      authentication.setDetails(authenticationDetailsSource.buildDetails(req));
  
      Authentication authResult = getAuthenticationManager().authenticate(authentication); //BadCredentialsException: Bad credentials
  
      SecurityContextHolder.getContext().setAuthentication(authResult);
  
      chain.doFilter(req, res);
  }
  </code></pre>
  
  <p>Updated version of this method throws <code>BadCredentialsException: Bad credentials</code></p>