title: Spring Boot OAuth 2 Resource Server not accepting public key for JWT verification
body: <p>I'm using Spring Boot 2.1.5 and creating two separate modules for Authorization Server and Resource Server. I recently shifted to use JWT instead of normal access tokens using the examples shown <a href="https://www.baeldung.com/spring-security-oauth-jwt" rel="nofollow noreferrer">here</a> and <a href="http://stytex.de/blog/2016/02/01/spring-cloud-security-with-oauth2/" rel="nofollow noreferrer">here</a>.</p>
  
  <p>Now the error which got me here is this</p>
  
  <pre><code>Caused by: java.lang.IllegalStateException: For MAC signing you do not need to specify the verifier key separately, and if you do it must match the signing key
  </code></pre>
  
  <p>I had a look at <a href="https://stackoverflow.com/a/48213780/3733631">this answer</a> but that's not the case with me. I have generated proper files using keytool and saved them to my resources folder.</p>
  
  <ol>
  <li>JKS file in the resources folder of Authorization Server module</li>
  <li>public_key.txt in the resources folder of Resource Server module</li>
  </ol>
  
  <p>Here is my Authorization Server Configuration File</p>
  
  <pre class="lang-java prettyprint-override"><code>@Configuration
  @EnableAuthorizationServer
  public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
      private static final Logger logger = LoggerFactory.getLogger(AuthorizationServerConfiguration.class);
  
      @Autowired
      private AuthenticationManager authenticationManager;
  
      @Autowired
      private UserDetailsService userDetailsService;
  
      @Autowired
      private DataSource dataSource;
  
      @Autowired
      private PasswordEncoder passwordEncoder;
  
      @Override
      public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
          clients.jdbc(this.dataSource);
      }
  
      @Override
      public void configure(final AuthorizationServerEndpointsConfigurer endpoints) {
          TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
          tokenEnhancerChain.setTokenEnhancers(
                  Arrays.asList(tokenEnhancer(), jwtAccessTokenConverter()));
  
          endpoints.authenticationManager(authenticationManager)
                  .userDetailsService(userDetailsService)
                  .tokenEnhancer(tokenEnhancerChain)
                  .accessTokenConverter(jwtAccessTokenConverter())
                  .tokenStore(tokenStore());
      }
  
      @Override
      public void configure(final AuthorizationServerSecurityConfigurer oauthServer) {
          oauthServer.passwordEncoder(passwordEncoder).tokenKeyAccess("permitAll()")
                  .checkTokenAccess("isAuthenticated()");
      }
  
      @Bean
      public TokenStore tokenStore() {
          return new JwtTokenStore(jwtAccessTokenConverter());
      }
  
      @Bean
      public JwtAccessTokenConverter jwtAccessTokenConverter() {
          JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
  
          KeyStoreKeyFactory keyStoreKeyFactory =
                  new KeyStoreKeyFactory(new ClassPathResource("accesstoken_keystore.jks"), "my-keystore-password".toCharArray());
          jwtAccessTokenConverter.setKeyPair(keyStoreKeyFactory.getKeyPair("my-alias"));
          return jwtAccessTokenConverter;
      }
  
      @Bean
      public TokenEnhancer tokenEnhancer() {
          return new CustomTokenEnhancer();
      }
  
      @Bean
      public DefaultTokenServices tokenServices(final TokenStore tokenStore,
                                                final ClientDetailsService clientDetailsService) {
          DefaultTokenServices tokenServices = new DefaultTokenServices();
          tokenServices.setSupportRefreshToken(true);
          tokenServices.setTokenStore(tokenStore);
          tokenServices.setClientDetailsService(clientDetailsService);
          tokenServices.setAuthenticationManager(authenticationManager);
          return tokenServices;
      }
  }
  
  </code></pre>
  
  <p>And Here is my Resource Server Configuration class</p>
  
  <pre class="lang-java prettyprint-override"><code>@Configuration
  @EnableResourceServer
  @EnableGlobalMethodSecurity(prePostEnabled = true)
  public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
      private static final Logger logger = LoggerFactory.getLogger(ResourceServerConfig.class);
  
      @Autowired
      private Environment env;
  
      @Autowired
      private CustomAccessTokenConverter accessTokenConverter;
  
      @Override
      public void configure(HttpSecurity http) throws Exception {
          http
                  .authorizeRequests()
                  .antMatchers("/**").access("#oauth2.hasScope('read')")
                  .anyRequest().authenticated()
                  .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
      }
  
      @Override
      public void configure(ResourceServerSecurityConfigurer config) {
          config.tokenServices(tokenServices());
      }
  
      @Bean
      public TokenStore tokenStore() {
          return new JwtTokenStore(accessTokenConverter());
      }
  
      @Bean
      public JwtAccessTokenConverter accessTokenConverter() {
          JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  
          Resource publicKeyResource = new ClassPathResource("public_key.txt");
          String publicKey = null;
          try {
              publicKey = new String(FileCopyUtils.copyToByteArray(publicKeyResource.getInputStream()));
          } catch (final IOException e) {
              throw new RuntimeException(e);
          }
  
          converter.setVerifierKey(publicKey);  //this is where I'm getting the error
  
          return converter;
      }
  
      @Bean
      @Primary
      public DefaultTokenServices tokenServices() {
          DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
          defaultTokenServices.setTokenStore(tokenStore());
          return defaultTokenServices;
      }
  </code></pre>
  
  <p>And here is the content of public_key.txt file as it is</p>
  
  <pre><code>-----BEGIN PUBLIC KEY-----
  blah blah blah
  blah blah blah
  -----END PUBLIC KEY-----
  </code></pre>
  
  <p>I'm expecting that the Authorization Server will sign the JWT using the Private Key extracted from the KeyStore file and Resource Server will just verify it.</p>
  
  <p>Not sure what's wrong. Everything was working fine before I decided to use a RSA key asymmetric pair.</p>