title: How can I handle InvalidSignatureException while validating JWT in Spring Boot?
body: <p>I am developing my own Spring Boot authentication server and resource server, and they work normally.
  The authentication server provides RS256 JWS token and the resource server is able to verify the token.</p>
  
  <p>I was so happy and I would like to know what would happen if I use a different RSA key pair to verify the JWS token. It came out:</p>
  
  <pre><code>org.springframework.security.jwt.crypto.sign.InvalidSignatureException: RSA Signature did not match content
      at org.springframework.security.jwt.crypto.sign.RsaVerifier.verify(RsaVerifier.java:55)
      at org.springframework.security.jwt.JwtImpl.verifySignature(JwtHelper.java:287)
      at org.springframework.security.oauth2.provider.token.store.jwk.JwkVerifyingJwtAccessTokenConverter.decode(JwkVerifyingJwtAccessTokenConverter.java:122)
      at org.springframework.security.oauth2.provider.token.store.JwtTokenStore.convertAccessToken(JwtTokenStore.java:88)
      at org.springframework.security.oauth2.provider.token.store.JwtTokenStore.readAccessToken(JwtTokenStore.java:80)
      at org.springframework.security.oauth2.provider.token.store.jwk.JwkTokenStore.readAccessToken(JwkTokenStore.java:212)
      at org.springframework.security.oauth2.provider.token.DefaultTokenServices.loadAuthentication(DefaultTokenServices.java:229)
      at org.springframework.security.oauth2.provider.token.DefaultTokenServices$$FastClassBySpringCGLIB$$5a1f25c.invoke(&lt;generated&gt;)
      at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
      at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684)
      at org.springframework.security.oauth2.provider.token.DefaultTokenServices$$EnhancerBySpringCGLIB$$14463cf2.loadAuthentication(&lt;generated&gt;)
      at org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager.authenticate(OAuth2AuthenticationManager.java:83)
      at org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter.doFilter(OAuth2AuthenticationProcessingFilter.java:150)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
  ...
  </code></pre>
  
  <p>and the response is &lt;500 Internal Server Error> with body:</p>
  
  <pre><code>&lt;!doctype html&gt;
  &lt;html lang="en"&gt;
  
  &lt;head&gt;
      &lt;title&gt;HTTP Status 500 – Internal Server Error&lt;/title&gt;
      &lt;style type="text/css"&gt;
          h1 {
              font-family: Tahoma, Arial, sans-serif;
              color: white;
              background-color: #525D76;
              font-size: 22px;
          }
  
          h2 {
              font-family: Tahoma, Arial, sans-serif;
              color: white;
              background-color: #525D76;
              font-size: 16px;
          }
  
          h3 {
              font-family: Tahoma, Arial, sans-serif;
              color: white;
              background-color: #525D76;
              font-size: 14px;
          }
  
          body {
              font-family: Tahoma, Arial, sans-serif;
              color: black;
              background-color: white;
          }
  
          b {
              font-family: Tahoma, Arial, sans-serif;
              color: white;
              background-color: #525D76;
          }
  
          p {
              font-family: Tahoma, Arial, sans-serif;
              background: white;
              color: black;
              font-size: 12px;
          }
  
          a {
              color: black;
          }
  
          a.name {
              color: black;
          }
  
          .line {
              height: 1px;
              background-color: #525D76;
              border: none;
          }
      &lt;/style&gt;
  &lt;/head&gt;
  
  &lt;body&gt;
      &lt;h1&gt;HTTP Status 500 – Internal Server Error&lt;/h1&gt;
  &lt;/body&gt;
  
  &lt;/html&gt;
  </code></pre>
  
  <p><strong>I would like to handle this error into custom JSON error body, or at least look like the same as the normal AuthenticationException</strong></p>
  
  <p>e.g. &lt;401 Unauthorized></p>
  
  <pre><code>{
      "error": "invalid_token",
      "error_description": "Invalid JWT/JWS: RSA Signature did not match content"
  }
  </code></pre>
  
  <p>My Spring / Boot dependencies:</p>
  
  <pre><code>plugins {
      id 'org.springframework.boot' version '2.2.4.RELEASE'
      ...
  }
  
  dependencies {
      implementation 'org.springframework.boot:spring-boot-starter'
      testImplementation('org.springframework.boot:spring-boot-starter-test') {
          exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
      }
      compile("org.springframework.boot:spring-boot-starter-security")
      compile("org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.1.0.RELEASE")
      compile('org.springframework.boot:spring-boot-starter-web')
      testCompile('org.springframework.boot:spring-boot-starter-web')
      compile("org.springframework.cloud:spring-cloud-starter-sleuth")
      compile("org.springframework.security:spring-security-jwt")
      ...
  }
  </code></pre>
  
  <p>What I have tried:</p>
  
  <ul>
  <li>Handle in <code>@ControllerAdvice</code> (From other answers in Stackoverflow, should be the request still haven't passed into MVC, so useless)</li>
  <li>Register custom <code>AuthenticationEntryPoint</code> through <code>ResourceServerConfigurerAdapter.configure(HttpSecurity)</code> (Don't know why it can't help, but tried)</li>
  <li><strong>Edit</strong><br>
  Tried the suggestion from @Jazzepi, Implementing <code>HandlerExceptionResolver</code> or extending <code>AbstractHandlerExceptionResolver</code> with method:</li>
  </ul>
  
  <pre><code>@Override
      public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
          if (ex instanceof InvalidSignatureException) {
              ModelAndView mav = new ModelAndView(new MappingJackson2JsonView());
              mav.addObject("key", "value");
              return mav;
          }
          return null;
      }
  </code></pre>
  
  <p>And then tried to register through <code>WebMvcConfigurator.extendHandlerExceptionResolvers(List&lt;HandleExceptionResolvers&gt;)</code> (It can't help, still output the same response as above)</p>
  
  <hr>
  
  <p><strong>Edit:</strong></p>
  
  <p><strong>How I build and decode the token?</strong><br>
  Follows exactly this tutorial: <a href="https://www.baeldung.com/spring-security-oauth2-jws-jwk" rel="nofollow noreferrer">https://www.baeldung.com/spring-security-oauth2-jws-jwk</a></p>
  
  <p><strong>How to re-play this situation?</strong>  </p>
  
  <ol>
  <li>Start both auth and resource server.</li>
  <li>Get a token from auth server and use the token in the resource server once to make the resource server cache the public key in local</li>
  <li>Change the keystore file in the auth server and restart</li>
  <li>Get a new token from the restarted auth server</li>
  <li>Use the new token in the resource server</li>
  </ol>