title: Integrate spring cloud gateway with oauth2
body: <p>I am trying to implement a gateway for my dataservices. All my dataservices are protected with JWT authentacitation (i.e every request must have 'Authorization' header otherwise dataservices respond with 'Unauthorized'). I would like my gateway to also validate all the request for the authorization header. How do I achieve this? As spring cloud gateway is based on reactive model, I am not able to use same configuration. Below are configuration for other data services:</p>
  
  <p>application.properties</p>
  
  <pre><code>security.jwt.signing-key=secret-key
  security.resource.id=abc.dataService.com
  </code></pre>
  
  <p>securityConfig.java</p>
  
  <pre><code>import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.beans.factory.annotation.Value;
  import org.springframework.context.annotation.Bean;
  import org.springframework.context.annotation.Configuration;
  import org.springframework.security.authentication.AuthenticationManager;
  import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
  import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
  import org.springframework.security.oauth2.provider.token.TokenStore;
  import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
  import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
  import org.springframework.web.cors.CorsConfiguration;
  import org.springframework.web.cors.CorsConfigurationSource;
  import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
  
  import java.util.Arrays;
  import java.util.concurrent.TimeUnit;
  
  /**
   * Defines beans that protect resources using OAuth2 and JWT tokens
   */
  @Configuration
  @EnableWebSecurity
  @EnableGlobalMethodSecurity(prePostEnabled = true)
  public class SecurityConfig extends WebSecurityConfigurerAdapter {
      @Autowired
      private AllClaimsMappingAccessTokenConverter customAccessTokenConverter;
  
      @Value("${security.jwt.signing-key}")
      private String signingKey;
  
      @Value("${security.cors.allowedOrigins}")
      private String allowedOrigins;
  
      @Bean
      @Override
      protected AuthenticationManager authenticationManager() throws Exception {
          return super.authenticationManager();
      }
  
      @Bean
      public JwtAccessTokenConverter accessTokenConverter() {
          JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
          converter.setSigningKey(signingKey);
          converter.setAccessTokenConverter(customAccessTokenConverter);
          return converter;
      }
  
      @Bean
      public TokenStore tokenStore() {
          return new JwtTokenStore(accessTokenConverter());
      }
  
      @Bean
      public DefaultTokenServices tokenServices() {
          DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
          defaultTokenServices.setTokenStore(tokenStore());
          defaultTokenServices.setSupportRefreshToken(true);
          return defaultTokenServices;
      }
  
      @Bean
      CorsConfigurationSource corsConfigurationSource() {
          CorsConfiguration configuration = new CorsConfiguration();
          configuration.setAllowedOrigins(Arrays.asList(allowedOrigins.split(",")));
          configuration.setAllowedMethods(Arrays.asList("GET", "POST", "DELETE", "PUT", "PATCH"));
          configuration.setAllowedHeaders(Arrays.asList("X-Requested-With", "Origin", "Content-Type", "Accept", "Authorization", "X-Auth-Token"));
          configuration.setMaxAge(TimeUnit.DAYS.toSeconds(2));
          UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
          source.registerCorsConfiguration("/**", configuration);
          return source;
      }
  }
  </code></pre>
  
  <p>resourceServerConfig.java</p>
  
  <pre><code>import java.io.IOException;
  import java.time.Instant;
  
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.beans.factory.annotation.Value;
  import org.springframework.context.annotation.Configuration;
  import org.springframework.http.HttpStatus;
  import org.springframework.http.MediaType;
  import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  import org.springframework.security.core.AuthenticationException;
  import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
  import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
  import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
  import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
  import org.springframework.security.web.AuthenticationEntryPoint;
  import org.springframework.stereotype.Component;
  
  @Configuration
  @EnableResourceServer
  public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
      private static final Logger LOGGER = LoggerFactory.getLogger(ResourceServerConfig.class);
  
      @Value("${security.resource.id}")
      private String resourceId;
  
      @Autowired
      private ResourceServerTokenServices tokenServices;
  
      @Autowired
      private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
  
      @Override
      public void configure(ResourceServerSecurityConfigurer resources)
              throws Exception {
          resources.resourceId(resourceId).tokenServices(tokenServices);
          resources.authenticationEntryPoint(restAuthenticationEntryPoint);
      }
  
      @Override
      public void configure(HttpSecurity http) throws Exception {
          http
                  .cors().and()
                  .requestMatchers()
                  .and()
                  .authorizeRequests()
                  .antMatchers("/**").authenticated();
      }
  
      @Component("restAuthenticationEntryPoint")
      public static class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
  
          private static final String ERROR_JSON_TEMPLATE = "{ \"errors\": [ { \"id\": %d, \"status\": 401, \"title\": \"Not Authorized\", \"detail\": \"%s\" } ], \"meta\": {} }";
  
          @Override
          public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex)
                  throws IOException, ServletException {
              long instant = Instant.now().toEpochMilli();
              LOGGER.error("Auth exception at {}", instant, ex);
  
              response.getWriter()
                      .println(String.format(ERROR_JSON_TEMPLATE, instant, ex.getMessage()));
              response.setStatus(HttpStatus.UNAUTHORIZED.value());
              response.setContentType(MediaType.APPLICATION_JSON_VALUE);
              response.flushBuffer();
          }
      }
  }
  </code></pre>
  
  <p>TokenConverter</p>
  
  <pre><code>import java.util.Map;
  
  import org.springframework.security.oauth2.provider.OAuth2Authentication;
  import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
  import org.springframework.stereotype.Component;
  
  @Component
  public class AllClaimsMappingAccessTokenConverter extends DefaultAccessTokenConverter {
  
      @Override
      public OAuth2Authentication extractAuthentication(Map&lt;String, ?&gt; claims) {
          OAuth2Authentication authentication = super.extractAuthentication(claims);
          authentication.setDetails(claims);
          return authentication;
      }
  }
  </code></pre>