How to Use Spring Cloud Gateway With OAuth 2.0 Patterns
The reactive AI Gateway of the Spring Ecosystem—built on Spring Boot, WebFluz, and Project—is Spring Cloud Gateway. Spring Cloud Gateway’s job is to factor and route requests to services, as well as provide alternative concerns, like security, monitoring, and resilience. While Reactive models gain popularity, the microservices you use will most likely be a combination of Spring MVC blocking applications and Spring WebFlux non-blocking applications.
This article will show you how to use Spring Cloud Gateway for routing as well as traditional Servlet API microservices. You will also learn the necessary configurations for OpenID Configuration Authentication, Token Relay, and Client Credentials Grant, all of which are common OAuth2 patterns that use Okta as an authorization server.
Prerequisites:
Java 11+
cURL
Table of Contents
- Pattern 1: OpenID Connect Authentication
- Create a Eureka Discovery Service
- Create a Spring Cloud Gateway Application
- Pattern 2: Token Relay to Service
- Create a REST API Service
- Route the REST API Through Spring Cloud Gateway
- Pattern 3: Service-to-Service Client Credentials Grant
- Create a Microervice
- Secure the Micro Service using OAuth 2.0 Scopes
- Update the REST API to Call the Micro Service
- Putting it All Together
- Learn More About Building Secure Applications
Pattern 1: OpenID Connect Authentication
OpenID Connect defines a mechanism for end-user authentication based on the OAuth2 authorization code flow. In this pattern, the Authorization Server returns an Authorization Code to the application, which can then exchange it for an ID Token and an Access Token directly. The Authorization Server authenticates the application with a ClientId and ClientSecret before the exchange happens. As you can see in the diagram below, OpenID and OAuth2 patterns make extensive use of HTTP redirections, some of which have been omitted for clarity.
For testing this OAuth2 pattern, create the API Gateway with service discovery. First, create a base folder for all the projects:
xxxxxxxxxx
mkdir oauth2-patterns
cd oauth2-patterns
Create a Eureka Discovery Service
With Spring Initializr, create an Eureka server:
xxxxxxxxxx
curl https://start.spring.io/starter.zip -d dependencies=cloud-eureka-server \
-d groupId=com.okta.developer \
-d artifactId=discovery-service \
-d name="Eureka Service" \
-d description="Discovery service" \
-d packageName=com.okta.developer.discovery \
-d javaVersion=11 \
-o eureka.zip
Unzip the file:
xxxxxxxxxx
unzip eureka.zip -d eureka
cd eureka
As described in Spring Cloud Netflix documentation, the JAXB modules, which the Eureka server depends upon, were removed in JDK 11. If you are running Eureka server with JDK 11, edit the pom.xml
and add the following dependency:
xxxxxxxxxx
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
Edit EurekaServiceApplication
to add @EnableEurekaServer
annotation:
xxxxxxxxxx
package com.okta.developer.discovery;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
public class EurekaServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServiceApplication.class, args);
}
}
Rename src/main/resources/application.properties
to application.yml
and add the following content:
xxxxxxxxxx
server
port8761
eureka
instance
hostname localhost
client
registerWithEurekafalse
fetchRegistryfalse
serviceUrl
defaultZone http //$ eureka.instance.hostname $ server.port /eureka/
Start the service:
xxxxxxxxxx
./mvnw spring-boot:run
Go to http://localhost:8761
and you should see the Eureka home.
Create a Spring Cloud Gateway Application
Now let’s create an API Gateway with Spring Cloud Gateway, using Spring Initializr again.
xxxxxxxxxx
curl https://start.spring.io/starter.zip \
-d dependencies=cloud-eureka,cloud-gateway,webflux,okta,cloud-security,thymeleaf \
-d groupId=com.okta.developer \
-d artifactId=api-gateway \
-d name="Spring Cloud Gateway Application" \
-d description="Demo project of a Spring Cloud Gateway application and OAuth flows" \
-d packageName=com.okta.developer.gateway \
-d javaVersion=11 \
-o api-gateway.zip
Unzip the project:
xxxxxxxxxx
unzip api-gateway.zip -d api-gateway
cd api-gateway
Edit SpringCloudGatewayApplication
to add @EnableEurekaClient
annotation.
xxxxxxxxxx
package com.okta.developer.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
public class SpringCloudGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudGatewayApplication.class, args);
}
}
Add a package controller
and the controller class src/main/java/com/okta/developer/gateway/controller/GreetingController.java
. The controller will allow us to test the login without having configured any routes yet.
xxxxxxxxxx
package com.okta.developer.gateway.controller;
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.oidc.user.OidcUser;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
public class GreetingController {
"/greeting") (
public String greeting( OidcUser oidcUser, Model model,
"okta") OAuth2AuthorizedClient client) { (
model.addAttribute("username", oidcUser.getEmail());
model.addAttribute("idToken", oidcUser.getIdToken());
model.addAttribute("accessToken", client.getAccessToken());
return "greeting";
}
}
Add a greeting template src/main/resources/templates/greeting.html
: