I'm currently looking at implementing an API Gateway using Spring Cloud Gateway. There will be some React clients to the APIs and also some devices. The devices will be granted access using OAuth device_code grant. The API gateway will pass JWT to back end resource API servers, which will validate the request. I have followed the following example which seems to get me part of the way there.
https://spring.io/blog/2019/08/16/securing-services-with-spring-cloud-gateway I've also been able to swap out the IdP in that example for WSO2.
I obtained a bearer token from the IdP using curl in order to test using an opaque token.
curl -u OzVconnyapPW2yWzxrSebCKmY9Qa:5cBcZmnnaW5gGOW3qt9sumw4Ubka -k -d "grant_type=password&username=admin&password=admin" -H "Content-Type:application/x-www-form-urlencoded" https://localhost:9443/oauth2/token
which returned me an access token.
curl -k http://springboot.example.com:8080/ -H "Authorization: Bearer 123b546d-f35b-38b8-a2c8-4e0d4487329d"
But this tries to redirect me to login.
How can I get Spring Cloud API Gateway to process requests where an Authorization: Bearer xxxx header has been added?
Am I using the correct 'opaque token' (i.e. is an Authorization token the correct way to do this)?
Can the oauth2 client be bypassed if an Authorization header is set and could a resource server be triggered instead?
This diagram represents my current thinking, which could be wrong (please say if so!)

API Gateway app:
package com.scg.gateway;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.cloud.security.oauth2.gateway.TokenRelayGatewayFilterFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
@SpringBootApplication
public class GatewayApplication {
@Autowired
private TokenRelayGatewayFilterFactory filterFactory;
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("resource", r -> r.path("/resource")
.filters(f -> f.filters(filterFactory.apply())
.removeRequestHeader("Cookie")) // Prevents cookie being sent downstream
.uri("http://springboot.example.com:9000")) // Taking advantage of docker naming
.build();
}
@GetMapping("/")
public String index(Model model,
@RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient,
@AuthenticationPrincipal OAuth2User oauth2User) {
model.addAttribute("userName", oauth2User.getName());
model.addAttribute("clientName", authorizedClient.getClientRegistration().getClientName());
model.addAttribute("userAttributes", oauth2User.getAttributes());
return "index";
}
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
API Gateway Yaml
server:
port: 8080
logging:
level:
root: INFO
org.springframework.web: INFO
org.springframework.web.HttpLogging: DEBUG
org.springframework.security: DEBUG
org.springframework.security.oauth2: DEBUG
org.springframework.cloud.gateway: DEBUG
spring:
autoconfigure:
# TODO: remove when fixed https://github.com/spring-projects/spring-security/issues/6314
exclude: org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration
thymeleaf:
cache: false
security:
oauth2:
client:
registration:
gateway:
provider: wso2
client-id: OzVconnyapPW2yWzxrSebCKmY9Qa
client-secret: 5cBcZmnnaW5gGOW3qt9sumw4Ubka
authorization-grant-type: authorization_code
redirect-uri-template: "{baseUrl}/login/oauth2/code/wso2"
scope: openid,profile,email,resource.read
provider:
wso2:
authorization-uri: http://idp.example.com:9763/oauth2/authorize
token-uri: http://idp.example.com:9763/oauth2/token
user-info-uri: http://idp.example.com:9763/oauth2/userinfo
user-name-attribute: sub
jwk-set-uri: http://idp.example.com:9763/oauth2/jwks