title: JWT Authorization failed with Angular 7 + Spring Boot + h2 database
body: <p>This is the <strong>error</strong> I am getting in <strong>intelliJ</strong> when I call the Angular code from the frontend:</p>
  
  <pre><code>io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
  at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:354) ~[jjwt-0.9.1.jar:0.9.1]
  at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:481) ~[jjwt-0.9.1.jar:0.9.1]
  at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:541) ~[jjwt-0.9.1.jar:0.9.1]
  at com.sda.VictorLiviu.ecommerce.security.JWTAuthorizationFilter.getAuthentication(JWTAuthorizationFilter.java:42) ~[classes/:na]
  at com.sda.VictorLiviu.ecommerce.security.JWTAuthorizationFilter.doFilterInternal(JWTAuthorizationFilter.java:32) ~[classes/:na]
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
  at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
  at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
  at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
  at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
  at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
  at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
  at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
  at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
  at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:836) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1747) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
  at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.19.jar:9.0.19]
  at java.base/java.lang.Thread.run(Thread.java:835) ~[na:na]
  </code></pre>
  
  <p>This is the <strong>chrome console</strong> when I click login:</p>
  
  <pre><code>    POST http://localhost:8080/authenticate 403
  login.component.ts:32 HttpErrorResponse {headers: HttpHeaders, status: 403, statusText: "OK", url: "http://localhost:8080/authenticate", ok: false, …}
  </code></pre>
  
  <p>This is the <strong>Angular code</strong> that is getting called when I click login:</p>
  
  <pre><code>export const TOKEN = 'token'
  export const AUTHENTICATED_USER = 'authenticaterUser'
  
  executeJWTAuthenticationService(username, password) {
      return this.http.post&lt;any&gt;(
        `${API_URL}/authenticate`, {
          username,
          password
        }).pipe(
          map(
            data =&gt; {
              sessionStorage.setItem(AUTHENTICATED_USER, username);
              sessionStorage.setItem(TOKEN, `Bearer ${data.token}`);
              return data;
            }
          )
        );
    }
  </code></pre>
  
  <p><strong>JWTAuthorizationFilter</strong> class:</p>
  
  <pre><code>    public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
      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(SECRET)
                      .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>JWTAuthenticationFilter</strong> class:</p>
  
  <pre><code>public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
  private AuthenticationManager authenticationManager;
  
  JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
      this.authenticationManager = authenticationManager;
  }
  
  @Override
  public Authentication attemptAuthentication(HttpServletRequest req,
                                              HttpServletResponse res) throws AuthenticationException {
      try {
          User creds = new ObjectMapper()
                  .readValue(req.getInputStream(), User.class);
          return authenticationManager.authenticate(
                  new UsernamePasswordAuthenticationToken(
                          creds.getUsername(),
                          creds.getPassword(),
                          new ArrayList&lt;&gt;())
          );
      } catch (IOException e) {
          throw new RuntimeException(e);
      }
  }
  
  @Override
  protected void successfulAuthentication(HttpServletRequest req,
                                          HttpServletResponse res,
                                          FilterChain chain,
                                          Authentication auth) {
      String token = Jwts.builder()
              .setSubject(((User) auth.getPrincipal()).getUsername())
              .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
              .signWith(SignatureAlgorithm.HS512, SECRET)
              .compact();
      res.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
  }
  </code></pre>
  
  <p>}</p>
  
  <p><strong>User entity</strong>:</p>
  
  <pre><code>    @Entity
  public class User {
  
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      @Column(name = "user_id")
      private Long id;
  
      @Column(name = "username")
      private String username;
  
      @Column(name = "password")
      private String password;
  
      @OneToOne(cascade = CascadeType.ALL)
      @JoinColumn(name = "order_id", referencedColumnName = "id")
      private Orders order;
  
      //getters and setters
  </code></pre>
  
  <p><strong>User Controller</strong>:</p>
  
  <pre><code>    @CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
  @RestController
  @RequestMapping("/users")
  public class UserController {
  
      private UserService service;
      private BCryptPasswordEncoder bCryptPasswordEncoder;
  
      public UserController(UserService service, BCryptPasswordEncoder bCryptPasswordEncoder) {
          this.service = service;
          this.bCryptPasswordEncoder = bCryptPasswordEncoder;
      }
  
      @GetMapping
      public ResponseEntity&lt;List&lt;User&gt;&gt; getAll() {
          List&lt;User&gt; users = service.getUsers();
  
          if (users.isEmpty()) {
              return new ResponseEntity&lt;&gt;(HttpStatus.NO_CONTENT);
          }
  
          return new ResponseEntity&lt;&gt;(users, HttpStatus.OK);
      }
  
      @DeleteMapping("/delete/{id}")
      public void deleteUser(@PathVariable Long id) {
          service.delete(id);
      }
  
      @PostMapping(
              value = "register",
              consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
      public ResponseEntity&lt;HttpStatus&gt; registerUser(@RequestBody UserDetailsModel userDetails) {
          userDetails.setPassword(bCryptPasswordEncoder.encode(userDetails.getPassword()));
          service.createUser(userDetails);
  
          return new ResponseEntity&lt;&gt;(HttpStatus.OK);
      }
  }
  </code></pre>
  
  <p><strong>end of code</strong>:
     My main concerns is that the code is working but I am calling the wrong URL. I am currently calling localhost:8080/authenticate and sending the username and password. 
     I can successfully add a user to the database using the register button(checked it in h2 console), but I cannot log in that user.</p>
  
  <p>I am pretty new to JWT, although I have read a lot about it online.</p>
  
  <p>Please hint me to what to do since the code is from an online tutorial and I don't really understand much of it. I just need to make the login to work in order to finish my project. </p>
  
  <p>Also a link to a good online tutorial about implementing JWT authentication would be much appreciated.</p>