{"id":99108,"date":"2019-10-14T12:47:10","date_gmt":"2019-10-14T09:47:10","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=99108"},"modified":"2019-10-23T12:12:58","modified_gmt":"2019-10-23T09:12:58","slug":"secure-reactive-microservices-with-spring-cloud-gateway","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2019\/10\/secure-reactive-microservices-with-spring-cloud-gateway.html","title":{"rendered":"Secure Reactive Microservices with Spring Cloud Gateway"},"content":{"rendered":"<p><span style=\"font-size: 20px;\"><strong>Friends don\u2019t let friends write user auth. Tired of managing your own users?<\/strong><a href=\"https:\/\/developer.okta.com\/signup\/\/?utm_campaign=text_website_all_multiple_dev_dev_reactive-microservice-spring-cloud_null&amp;utm_source=jcg&amp;utm_medium=cpc\"> Try Okta\u2019s API and Java SDKs today. Authenticate, manage, and secure users in any application within minutes.<\/a><\/span><\/p>\n<p>So you wanna go full reactive, eh? Great! Reactive programming is an increasingly popular way to make your applications more efficient. Instead of making a call to a resource and waiting on a response, reactive applications asynchronously receive a response. This allows them to free up processing power, only perform processing when necessary, and scale more effectively than other systems.<\/p>\n<p>The Java ecosystem has its fair share of reactive frameworks, including Play Framework, Ratpack, Vert.x, and Spring WebFlux. Like Reactive programming, a microservices architecture can help large teams scale quickly and is possible to build using any of the awesome aforementioned frameworks.<\/p>\n<p>Today I\u2019d like to show you how you can build a reactive microservices architecture using Spring Cloud Gateway, Spring Boot, and Spring WebFlux. We\u2019ll leverage Spring Cloud Gateway as API gateways are often important components in a cloud-native microservices architecture, providing the aggregation layer for all your backend microservices.<\/p>\n<p>This tutorial shows you how to build a microservice with a REST API that returns a list of new cars. You\u2019ll use Eureka for service discovery and Spring Cloud Gateway to route requests to the microservice. Then you\u2019ll integrate Spring Security so only authenticated users can access your API gateway and microservice.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/spring-cloud-gateway-oauth2-1024x512.png\" alt=\"\" class=\"wp-image-99109\" width=\"768\" height=\"384\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/spring-cloud-gateway-oauth2-1024x512.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/spring-cloud-gateway-oauth2-300x150.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/spring-cloud-gateway-oauth2-768x384.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/spring-cloud-gateway-oauth2.png 1600w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<p><strong>Prerequisites<\/strong>:&nbsp;<a href=\"https:\/\/httpie.org\/\">HTTPie<\/a>&nbsp;(or cURL),&nbsp;<a href=\"https:\/\/adoptopenjdk.net\/\">Java<\/a>&nbsp;11+, and an internet connection.<\/p>\n<h2 class=\"wp-block-heading\" id=\"spring-cloud-gateway-vs-zuul\">Spring Cloud Gateway vs. Zuul<\/h2>\n<p>Zuul is Netflix\u2019s API gateway. First released in 2013, Zuul was not originally reactive, but Zuul 2 is a ground-up rewrite to make it reactive. Unfortunately, Spring Cloud&nbsp;<a href=\"https:\/\/github.com\/spring-cloud\/spring-cloud-netflix\/issues\/1498\">does not support Zuul 2<\/a>&nbsp;and it likely never will.<\/p>\n<p>Spring Cloud Gateway is now the preferred API gateway implementation from the Spring Cloud Team. It\u2019s built on Spring 5, Reactor, and Spring WebFlux. Not only that, it also includes circuit breaker integration, service discovery with Eureka, and is&nbsp;<strong>much<\/strong>&nbsp;easier to integrate with OAuth 2.0!<\/p>\n<p>Let\u2019s dig in.<\/p>\n<h2 class=\"wp-block-heading\" id=\"create-a-spring-cloud-eureka-server-project\">Create a Spring Cloud Eureka Server Project<\/h2>\n<p>Start by creating a directory to hold all your projects, for example,&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">spring-cloud-gateway<\/code>. Navigate to it in a terminal window and create a&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">discovery-service<\/code>&nbsp;project that includes Spring Cloud Eureka Server as a dependency.<\/p>\n<pre class=\"gutter: false;brush:bash\">http https:\/\/start.spring.io\/starter.zip javaVersion==11 artifactId==discovery-service \\\n  name==eureka-service baseDir==discovery-service \\\n  dependencies==cloud-eureka-server | tar -xzvf -\n<\/pre>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p> The command above uses&nbsp;<a href=\"https:\/\/httpie.org\/\">HTTPie<\/a>. I highly recommend installing it. You can also use&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">curl<\/code>. Run&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">curl <a href=\"https:\/\/start.spring.io\/\">https:\/\/start.spring.io<\/a><\/code>&nbsp;to see the syntax. <\/p>\n<\/blockquote>\n<p>Add&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">@EnableEurekaServer<\/code>&nbsp;on its main class to enable it as a Eureka server.<\/p>\n<pre class=\"gutter: false;brush:java\">import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;\n\n@EnableEurekaServer\n@SpringBootApplication\npublic class EurekaServiceApplication {...}\n<\/pre>\n<p>Add the following properties to the project\u2019s&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">src\/main\/resources\/application.properties<\/code>&nbsp;file to configure its port and turn off Eureka registration.<\/p>\n<pre class=\"gutter: false;brush:bash\">server.port=8761\neureka.client.register-with-eureka=false\n<\/pre>\n<p>To make the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">discovery-service<\/code>&nbsp;run on Java 11+, add a dependency on JAXB.<\/p>\n<pre class=\"gutter: false;brush:xml\">&lt;dependency&gt;\n    &lt;groupId&gt;org.glassfish.jaxb&lt;\/groupId&gt;\n    &lt;artifactId&gt;jaxb-runtime&lt;\/artifactId&gt;\n&lt;\/dependency&gt;\n<\/pre>\n<p>Start the project using&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">.\/mvnw spring-boot:run<\/code>&nbsp;or by running it in your IDE.<\/p>\n<h2 class=\"wp-block-heading\" id=\"create-a-spring-cloud-gateway-project\">Create a Spring Cloud Gateway Project<\/h2>\n<p>Next, create an&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">api-gateway<\/code>&nbsp;project that includes a handful of Spring Cloud dependencies.<\/p>\n<pre class=\"gutter: false;brush:bash\">http https:\/\/start.spring.io\/starter.zip javaVersion==11 artifactId==api-gateway \\\n  name==api-gateway baseDir==api-gateway \\\n  dependencies==actuator,cloud-eureka,cloud-feign,cloud-gateway,cloud-hystrix,webflux,lombok | tar -xzvf -\n<\/pre>\n<p>We\u2019ll come back to configuring this project in a minute.<\/p>\n<h2 class=\"wp-block-heading\" id=\"create-a-reactive-microservice-with-spring-webflux\">Create a Reactive Microservice with Spring WebFlux<\/h2>\n<p>The car microservice will contain a significant portion of this example\u2019s code because it contains a fully-functional REST API that supports CRUD (Create, Read, Update, and Delete).<\/p>\n<p>Create the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">car-service<\/code>&nbsp;project using start.spring.io:<\/p>\n<pre class=\"gutter: false;brush:bash\">http https:\/\/start.spring.io\/starter.zip javaVersion==11 artifactId==car-service \\\n  name==car-service baseDir==car-service \\\n  dependencies==actuator,cloud-eureka,webflux,data-mongodb-reactive,flapdoodle-mongo,lombok | tar -xzvf -\n<\/pre>\n<p>The&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">dependencies<\/code>&nbsp;argument is interesting in this command. You can see that Spring WebFlux is included, as is MongoDB. Spring Data provides reactive drivers for Redis and Cassandra as well.<\/p>\n<p>You may also be interested in&nbsp;<a href=\"https:\/\/r2dbc.io\/\">R2DBC<\/a>&nbsp;(Reactive Relational Database Connectivity) &#8211; an endeavor to bring a reactive programming API to SQL databases. I did not use it in this example because it\u2019s not yet available on start.spring.io.<\/p>\n<h2 class=\"wp-block-heading\" id=\"build-a-rest-api-with-spring-webflux\">Build a REST API with Spring WebFlux<\/h2>\n<p>I\u2019m a big fan of VWs, especially classic ones like the bus and the bug. Did you know that VW has a bunch of electric vehicles coming out in the next few years? I\u2019m really excited by the ID Buzz! It has classic curves and is all-electric. It even has 350+ horsepower!<\/p>\n<p>In case you\u2019re not familiar with the ID Buzz, here\u2019s a photo&nbsp;<a href=\"https:\/\/www.vw.com\/electric-concepts\/section\/id-buzz\/\">from Volkswagen<\/a>.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/id-buzz-1024x512.jpg\" alt=\"\" class=\"wp-image-99111\" width=\"768\" height=\"384\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/id-buzz-1024x512.jpg 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/id-buzz-300x150.jpg 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/id-buzz-768x384.jpg 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/id-buzz.jpg 1280w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<p>Let\u2019s have some fun with this API example and use the electric VWs for our data set. This API will track the various car names and release dates.<\/p>\n<p>Add Eureka registration, sample data initialization, and a reactive REST API to&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">src\/main\/java\/\u2026\u200b\/CarServiceApplication.java<\/code>:<\/p>\n<pre class=\"gutter: false;brush:java\">package com.example.carservice;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.netflix.eureka.EnableEurekaClient;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.mongodb.core.mapping.Document;\nimport org.springframework.data.mongodb.repository.ReactiveMongoRepository;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.*;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport java.time.LocalDate;\nimport java.time.Month;\nimport java.util.Set;\nimport java.util.UUID;\n\n@EnableEurekaClient (1)\n@SpringBootApplication\n@Slf4j (2)\npublic class CarServiceApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(CarServiceApplication.class, args);\n    }\n\n    @Bean (3)\n    ApplicationRunner init(CarRepository repository) {\n        \/\/ Electric VWs from https:\/\/www.vw.com\/electric-concepts\/\n        \/\/ Release dates from https:\/\/www.motor1.com\/features\/346407\/volkswagen-id-price-on-sale\/\n        Car ID = new Car(UUID.randomUUID(), \"ID.\", LocalDate.of(2019, Month.DECEMBER, 1));\n        Car ID_CROZZ = new Car(UUID.randomUUID(), \"ID. CROZZ\", LocalDate.of(2021, Month.MAY, 1));\n        Car ID_VIZZION = new Car(UUID.randomUUID(), \"ID. VIZZION\", LocalDate.of(2021, Month.DECEMBER, 1));\n        Car ID_BUZZ = new Car(UUID.randomUUID(), \"ID. BUZZ\", LocalDate.of(2021, Month.DECEMBER, 1));\n        Set&lt;Car&gt; vwConcepts = Set.of(ID, ID_BUZZ, ID_CROZZ, ID_VIZZION);\n\n        return args -&gt; {\n            repository\n                    .deleteAll() (4)\n                    .thenMany(\n                            Flux\n                                    .just(vwConcepts)\n                                    .flatMap(repository::saveAll)\n                    )\n                    .thenMany(repository.findAll())\n                    .subscribe(car -&gt; log.info(\"saving \" + car.toString())); (5)\n        };\n    }\n}\n\n@Document\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\nclass Car { (6)\n    @Id\n    private UUID id;\n    private String name;\n    private LocalDate releaseDate;\n}\n\ninterface CarRepository extends ReactiveMongoRepository&lt;Car, UUID&gt; { \n} (7)\n\n@RestController\nclass CarController { (8)\n\n    private CarRepository carRepository;\n\n    public CarController(CarRepository carRepository) {\n        this.carRepository = carRepository;\n    }\n\n    @PostMapping(\"\/cars\")\n    @ResponseStatus(HttpStatus.CREATED)\n    public Mono&lt;Car&gt; addCar(@RequestBody Car car) { (9)\n        return carRepository.save(car);\n    }\n\n    @GetMapping(\"\/cars\")\n    public Flux&lt;Car&gt; getCars() { (10)\n        return carRepository.findAll();\n    }\n\n    @DeleteMapping(\"\/cars\/{id}\")\n    public Mono&lt;ResponseEntity&lt;Void&gt;&gt; deleteCar(@PathVariable(\"id\") UUID id) {\n        return carRepository.findById(id)\n                .flatMap(car -&gt; carRepository.delete(car)\n                        .then(Mono.just(new ResponseEntity&lt;Void&gt;(HttpStatus.OK)))\n                )\n                .defaultIfEmpty(new ResponseEntity&lt;&gt;(HttpStatus.NOT_FOUND));\n    }\n}\n<\/pre>\n<ol class=\"wp-block-list\">\n<li> Add the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">@EnableEurekaClient<\/code>&nbsp;annotation for service discovery <\/li>\n<li> <code style=\"font-size:13px\" class=\"highlighter-rouge\">@Slf4j<\/code>&nbsp;is a handy annotation from Lombok to enable logging in a class <\/li>\n<li> <code style=\"font-size:13px\" class=\"highlighter-rouge\">ApplicationRunner<\/code>&nbsp;bean to populate MongoDB with default data <\/li>\n<li> Delete all existing data in MongoDB so new data is not additive <\/li>\n<li> Subscribe to results so both&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">deleteAll()<\/code>&nbsp;and&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">saveAll()<\/code>&nbsp;are invoked <\/li>\n<li><code style=\"font-size:13px\" class=\"highlighter-rouge\">Car<\/code>&nbsp;class with Spring Data NoSQL and Lombok annotations to reduce boilerplate<\/li>\n<li> <code style=\"font-size:13px\" class=\"highlighter-rouge\">CarRepository<\/code>&nbsp;interface that extends&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">ReactiveMongoRepository<\/code>, giving you CRUDability with hardly any code! <\/li>\n<li> <code style=\"font-size:13px\" class=\"highlighter-rouge\">CarController<\/code>&nbsp;class that uses&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">CarRepository<\/code>&nbsp;to perform CRUD actions <\/li>\n<li> Spring WebFlux returns a&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">Mono<\/code>&nbsp;publisher for single objects <\/li>\n<li> Return a&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">Flex<\/code>&nbsp;publisher for multiple objects <\/li>\n<\/ol>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p> If you\u2019re using an IDE to build your projects, you\u2019ll need to&nbsp;<a href=\"https:\/\/www.baeldung.com\/lombok-ide\">setup Lombok for your IDE<\/a>. <\/p>\n<\/blockquote>\n<p>You\u2019ll also need to modify the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">car-service<\/code>&nbsp;project\u2019s&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">application.properties<\/code>&nbsp;to set its name and port.<\/p>\n<pre class=\"gutter: false;brush:bash\">spring.application.name=car-service\nserver.port=8081\n<\/pre>\n<h3 class=\"wp-block-heading\" id=\"run-mongodb\">Run MongoDB<\/h3>\n<p>The easiest way to run MongoDB is to remove the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">test<\/code>&nbsp;scope from the flapdoodle dependency in&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">car-service\/pom.xml<\/code>. This will cause your app to start an embedded MongoDB dependency.<\/p>\n<pre class=\"gutter: false;brush:xml\">&lt;dependency&gt;\n    &lt;groupId&gt;de.flapdoodle.embed&lt;\/groupId&gt;\n    &lt;artifactId&gt;de.flapdoodle.embed.mongo&lt;\/artifactId&gt;\n    &lt;!--&lt;scope&gt;test&lt;\/scope&gt;--&gt;\n&lt;\/dependency&gt;\n<\/pre>\n<p>You can also install and run MongoDB using Homebrew.<\/p>\n<pre class=\"gutter: false;brush:bash\">brew tap mongodb\/brew\nbrew install mongodb-community@4.2\nmongod\n<\/pre>\n<p>Or, use Docker:<\/p>\n<pre class=\"gutter: false;brush:bash\">docker run -d -it -p 27017:27017 mongo\n<\/pre>\n<h3 class=\"wp-block-heading\" id=\"stream-data-with-webflux\">Stream Data with WebFlux<\/h3>\n<p>This completes everything you need to do to build a REST API with Spring WebFlux.<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<p>&#8220;But wait!&#8221; you might say. &#8220;I thought WebFlux was all about streaming data?&#8221;<\/p>\n<p>In this particular example, you can still stream data from the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">\/cars<\/code>&nbsp;endpoint, but not in a browser.<\/p>\n<p>A browser has no way to consume a stream other than using Server-Sent Events or WebSockets. Non-browser clients however can get a JSON stream by sending an&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">Accept<\/code>&nbsp;header with a value of&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">application\/stream+json<\/code>&nbsp;(thanks to&nbsp;<a href=\"https:\/\/www.callicoder.com\/reactive-rest-apis-spring-webflux-reactive-mongo\/\">Rajeev Singh<\/a>&nbsp;for the tip).<\/p>\n<p>You&nbsp;<em>could<\/em>&nbsp;test everything works at this point by firing up your browser and using HTTPie to make requests. However, it\u2019s much better to write automated tests!<\/p>\n<h3 class=\"wp-block-heading\" id=\"test-your-webflux-api-with-webtestclient\">Test Your WebFlux API with WebTestClient<\/h3>\n<p>WebClient ships as part of Spring WebFlux and can be useful for making reactive requests, receiving responses, and populating objects with the payload. A companion class, WebTestClient, can be used to test your WebFlux API. It contains request methods that are similar to WebClient, as well as methods to check the response body, status, and headers.<\/p>\n<p>Modify the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">src\/test\/java\/\u2026\u200b\/CarServiceApplicationTests.java<\/code>&nbsp;class in the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">car-service<\/code>&nbsp;project to contain the code below.<\/p>\n<pre class=\"gutter: false;brush:java\">package com.example.carservice;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport reactor.core.publisher.Mono;\n\nimport java.time.LocalDate;\nimport java.time.Month;\nimport java.util.Collections;\nimport java.util.UUID;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n        properties = {\"spring.cloud.discovery.enabled = false\"})\npublic class CarServiceApplicationTests {\n\n    @Autowired\n    CarRepository carRepository;\n\n    @Autowired\n    WebTestClient webTestClient;\n\n    @Test\n    public void testAddCar() {\n        Car buggy = new Car(UUID.randomUUID(), \"ID. BUGGY\", LocalDate.of(2022, Month.DECEMBER, 1));\n\n        webTestClient.post().uri(\"\/cars\")\n                .contentType(MediaType.APPLICATION_JSON_UTF8)\n                .accept(MediaType.APPLICATION_JSON_UTF8)\n                .body(Mono.just(buggy), Car.class)\n                .exchange()\n                .expectStatus().isCreated()\n                .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)\n                .expectBody()\n                .jsonPath(\"$.id\").isNotEmpty()\n                .jsonPath(\"$.name\").isEqualTo(\"ID. BUGGY\");\n    }\n\n    @Test\n    public void testGetAllCars() {\n        webTestClient.get().uri(\"\/cars\")\n                .accept(MediaType.APPLICATION_JSON_UTF8)\n                .exchange()\n                .expectStatus().isOk()\n                .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)\n                .expectBodyList(Car.class);\n    }\n\n    @Test\n    public void testDeleteCar() {\n        Car buzzCargo = carRepository.save(new Car(UUID.randomUUID(), \"ID. BUZZ CARGO\",\n                LocalDate.of(2022, Month.DECEMBER, 2))).block();\n\n        webTestClient.delete()\n                .uri(\"\/cars\/{id}\", Collections.singletonMap(\"id\", buzzCargo.getId()))\n                .exchange()\n                .expectStatus().isOk();\n    }\n}\n<\/pre>\n<p>To prove it works, run&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">.\/mvnw test<\/code>. Give yourself a pat on the back when your tests pass!<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/test-car-service-1024x553.png\" alt=\"\" class=\"wp-image-99113\" width=\"768\" height=\"415\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/test-car-service-1024x553.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/test-car-service-300x162.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/test-car-service-768x415.png 768w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p> If you\u2019re on Windows, use&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">mvnw test<\/code>. <\/p>\n<\/blockquote>\n<h2 class=\"wp-block-heading\" id=\"use-spring-cloud-gateway-with-reactive-microservices\">Use Spring Cloud Gateway with Reactive Microservices<\/h2>\n<p>To edit all three projects in the same IDE window, I find it useful to create an aggregator&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">pom.xml<\/code>. Create a&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">pom.xml<\/code>&nbsp;file in the parent directory of your projects and copy the XML below into it.<\/p>\n<pre class=\"gutter: false;brush:xml\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n&lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\n    xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\"&gt;\n    &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\n    &lt;groupId&gt;com.okta.developer&lt;\/groupId&gt;\n    &lt;artifactId&gt;reactive-parent&lt;\/artifactId&gt;\n    &lt;version&gt;1.0.0-SNAPSHOT&lt;\/version&gt;\n    &lt;packaging&gt;pom&lt;\/packaging&gt;\n    &lt;name&gt;reactive-parent&lt;\/name&gt;\n    &lt;modules&gt;\n        &lt;module&gt;discovery-service&lt;\/module&gt;\n        &lt;module&gt;car-service&lt;\/module&gt;\n        &lt;module&gt;api-gateway&lt;\/module&gt;\n    &lt;\/modules&gt;\n&lt;\/project&gt;\n<\/pre>\n<p>After creating this file, you should be able to open it in your IDE as a project and navigate between projects easily.<\/p>\n<p>In the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">api-gateway<\/code>&nbsp;project, add&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">@EnableEurekaClient<\/code>&nbsp;to the main class to make it Eureka-aware.<\/p>\n<pre class=\"gutter: false;brush:java\">import org.springframework.cloud.netflix.eureka.EnableEurekaClient;\n\n@EnableEurekaClient\n@SpringBootApplication\npublic class ApiGatewayApplication {...}\n<\/pre>\n<p>Then, modify the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">src\/main\/resources\/application.properties<\/code>&nbsp;file to configure the application name.<\/p>\n<pre class=\"gutter: false;brush:bash\">spring.application.name=gateway\n<\/pre>\n<p>Create a&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">RouteLocator<\/code>&nbsp;bean in&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">ApiGatewayApplication<\/code>&nbsp;to configure routes. You can configure Spring Cloud Gateway with YAML, but I prefer Java.<\/p>\n<pre class=\"gutter: false;brush:java\">package com.example.apigateway;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.gateway.route.RouteLocator;\nimport org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;\nimport org.springframework.cloud.netflix.eureka.EnableEurekaClient;\nimport org.springframework.context.annotation.Bean;\n\n@EnableEurekaClient\n@SpringBootApplication\npublic class ApiGatewayApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(ApiGatewayApplication.class, args);\n    }\n\n    @Bean\n    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {\n        return builder.routes()\n                .route(\"car-service\", r -&gt; r.path(\"\/cars\")\n                        .uri(\"lb:\/\/car-service\"))\n                .build();\n    }\n}\n<\/pre>\n<p>After making these code changes, you should be able to start all three Spring Boot apps and hit&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\"><a href=\"http:\/\/localhost:8080\/cars\">http:\/\/localhost:8080\/cars<\/a><\/code>.<\/p>\n<pre class=\"gutter: false;brush:js\">$ http :8080\/cars\nHTTP\/1.1 200 OK\nContent-Type: application\/json;charset=UTF-8\ntransfer-encoding: chunked\n\n[\n    {\n        \"id\": \"ff48f617-6cba-477c-8e8f-2fc95be96416\",\n        \"name\": \"ID. CROZZ\",\n        \"releaseDate\": \"2021-05-01\"\n    },\n    {\n        \"id\": \"dd6c3c32-724c-4511-a02c-3348b226160a\",\n        \"name\": \"ID. BUZZ\",\n        \"releaseDate\": \"2021-12-01\"\n    },\n    {\n        \"id\": \"97cfc577-d66e-4a3c-bc40-e78c3aab7261\",\n        \"name\": \"ID.\",\n        \"releaseDate\": \"2019-12-01\"\n    },\n    {\n        \"id\": \"477632c8-2206-4f72-b1a8-e982e6128ab4\",\n        \"name\": \"ID. VIZZION\",\n        \"releaseDate\": \"2021-12-01\"\n    }\n]\n<\/pre>\n<h3 class=\"wp-block-heading\" id=\"add-a-rest-api-to-retrieve-your-favorite-cars\">Add a REST API to Retrieve Your Favorite Cars<\/h3>\n<p>Create a&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">\/fave-cars<\/code>&nbsp;endpoint that strips out cars that aren\u2019t your favorite.<\/p>\n<p>First, add a load-balanced&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">WebClient.Builder<\/code>&nbsp;bean.<\/p>\n<pre class=\"gutter: false;brush:java\">@Bean\n@LoadBalanced\npublic WebClient.Builder loadBalancedWebClientBuilder() {\n    return WebClient.builder();\n}\n<\/pre>\n<p>Then add a&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">Car<\/code>&nbsp;POJO and a&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">FaveCarsController<\/code>&nbsp;below the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">ApiGatewayApplication<\/code>&nbsp;class in the same file.<\/p>\n<pre class=\"gutter: false;brush:java\">public class ApiGatewayApplication {...}\nclass Car {...}\nclass FaveCarsController {...}\n<\/pre>\n<p>Use WebClient to retrieve the cars and filter out the ones you don\u2019t love.<\/p>\n<pre class=\"gutter: false;brush:java\">@Data\nclass Car {\n    private String name;\n    private LocalDate releaseDate;\n}\n\n@RestController\nclass FaveCarsController {\n\n    private final WebClient.Builder carClient;\n\n    public FaveCarsController(WebClient.Builder carClient) {\n        this.carClient = carClient;\n    }\n\n    @GetMapping(\"\/fave-cars\")\n    public Flux&lt;Car&gt; faveCars() {\n        return carClient.build().get().uri(\"lb:\/\/car-service\/cars\")\n                .retrieve().bodyToFlux(Car.class)\n                .filter(this::isFavorite);\n    }\n\n    private boolean isFavorite(Car car) {\n        return car.getName().equals(\"ID. BUZZ\");\n    }\n}\n<\/pre>\n<p>If you\u2019re not using an IDE that auto-imports for you, you\u2019ll want to copy\/paste the following into the top of&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">ApiGatewayApplication.java<\/code>:<\/p>\n<pre class=\"gutter: false;brush:java\">import org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.reactive.function.client.WebClient;\nimport reactor.core.publisher.Flux;\n<\/pre>\n<p>Restart your gateway app to see the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\"><a href=\"http:\/\/localhost:8080\/fave-cars\">http:\/\/localhost:8080\/fave-cars<\/a><\/code>&nbsp;endpoint only returns the ID Buzz.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/fave-cars-1024x474.png\" alt=\"\" class=\"wp-image-99114\" width=\"768\" height=\"356\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/fave-cars-1024x474.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/fave-cars-300x139.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/fave-cars-768x356.png 768w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<h3 class=\"wp-block-heading\" id=\"what-about-failover-with-hystrix\">What about Failover with Hystrix?<\/h3>\n<p>Spring Cloud Gateway&nbsp;<a href=\"https:\/\/github.com\/spring-cloud\/spring-cloud-gateway\/issues\/658\">only supports Hystrix<\/a>&nbsp;at the time of this writing. Spring Cloud deprecated direct support for Hystrix in favor of&nbsp;<a href=\"https:\/\/spring.io\/blog\/2019\/04\/16\/introducing-spring-cloud-circuit-breaker\">Spring Cloud Circuit Breaker<\/a>. Unfortunately, this library hasn\u2019t had a GA release yet, so I decided not to use it.<\/p>\n<p>To use Hystrix with Spring Cloud Gateway, you can add a filter to your&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">car-service<\/code>&nbsp;route, like so:<\/p>\n<pre class=\"gutter: false;brush:java\">.route(\"car-service\", r -&gt; r.path(\"\/cars\")\n        .filters(f -&gt; f.hystrix(c -&gt; c.setName(\"carsFallback\")\n                .setFallbackUri(\"forward:\/cars-fallback\")))\n        .uri(\"lb:\/\/car-service\/cars\"))\n.build();\n<\/pre>\n<p>Then create a&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">CarsFallback<\/code>&nbsp;controller to handle the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">\/cars-fallback<\/code>&nbsp;route.<\/p>\n<pre class=\"gutter: false;brush:java\">@RestController\nclass CarsFallback {\n\n    @GetMapping(\"\/cars-fallback\")\n    public Flux&lt;Car&gt; noCars() {\n        return Flux.empty();\n    }\n}\n<\/pre>\n<p>First, restart your gateway and confirm&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\"><a href=\"http:\/\/localhost:8080\/cars\">http:\/\/localhost:8080\/cars<\/a><\/code>&nbsp;works. Then shut down the car service, try again, and you\u2019ll see it now returns an empty array. Restart the car service and you\u2019ll see the list populated again.<\/p>\n<p>You\u2019ve built a resilient and reactive microservices architecture with Spring Cloud Gateway and Spring WebFlux. Now let\u2019s see how to secure it!<\/p>\n<h3 class=\"wp-block-heading\" id=\"what-about-feign-with-spring-cloud-gateway\">What about Feign with Spring Cloud Gateway?<\/h3>\n<p>If you\u2019d like to use Feign in a WebFlux app, see the&nbsp;<a href=\"https:\/\/github.com\/kptfh\/feign-reactive\">feign-reactive<\/a>&nbsp;project. I did not have a need for Feign in this particular example.<\/p>\n<h2 class=\"wp-block-heading\" id=\"secure-spring-cloud-gateway-with-oauth-2-0\">Secure Spring Cloud Gateway with OAuth 2.0<\/h2>\n<p>OAuth 2.0 is an authorization framework for delegated access to APIs. OIDC (or OpenID Connect) is a thin layer on top of OAuth 2.0 that provides authentication. Spring Security has excellent support for both frameworks and so does Okta!<\/p>\n<p>You can use OAuth 2.0 and OIDC without a cloud identity provider by building your own server or by using an open-source implementation. However, wouldn\u2019t you rather just use something that\u2019s&nbsp;<em>always on<\/em>, like Okta?<\/p>\n<p>If you already have an Okta account, see the&nbsp;<strong>Create a Web Application in Okta<\/strong>&nbsp;sidebar below. Otherwise, we created a Maven plugin that configures a free Okta developer account + an OIDC app (in under a minute!).<\/p>\n<p>To use it run:&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">.\/mvnw com.okta:okta-maven-plugin:setup<\/code>&nbsp;to create an account and configure your Spring Boot app to work with Okta.<\/p>\n<p>Create a Web Application in Okta<\/p>\n<p>Log in to your Okta Developer account (or&nbsp;<a href=\"https:\/\/developer.okta.com\/signup\/\">sign up<\/a>&nbsp;if you don\u2019t have an account).<\/p>\n<ol class=\"wp-block-list\">\n<li>From the&nbsp;<strong>Applications<\/strong>&nbsp;page, choose&nbsp;<strong>Add Application<\/strong>.<\/li>\n<li>On the Create New Application page, select&nbsp;<strong>Web<\/strong>.<\/li>\n<li>Give your app a memorable name, add&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\"><a href=\"http:\/\/localhost:8080\/login\/oauth2\/code\/okta\">http:\/\/localhost:8080\/login\/oauth2\/code\/okta<\/a><\/code>&nbsp;as a Login redirect URI, select&nbsp;<strong>Refresh Token<\/strong>&nbsp;(in addition to&nbsp;<strong>Authorization Code<\/strong>), and click&nbsp;<strong>Done<\/strong>.<\/li>\n<\/ol>\n<p>Copy the issuer (found under&nbsp;<strong>API<\/strong>&nbsp;&gt;&nbsp;<strong>Authorization Servers<\/strong>), client ID, and client secret into&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">application.properties<\/code>&nbsp;for both projects.<\/p>\n<pre class=\"gutter: false;brush:bash\">okta.oauth2.issuer=$issuer\nokta.oauth2.client-id=$clientId\nokta.oauth2.client-secret=$clientSecret\n<\/pre>\n<p>Next, add the&nbsp;<a href=\"https:\/\/github.com\/okta\/okta-spring-boot\">Okta Spring Boot starter<\/a>&nbsp;and Spring Cloud Security to your gateway\u2019s&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">pom.xml<\/code>:<\/p>\n<pre class=\"gutter: false;brush:xml\">&lt;dependency&gt;\n    &lt;groupId&gt;com.okta.spring&lt;\/groupId&gt;\n    &lt;artifactId&gt;okta-spring-boot-starter&lt;\/artifactId&gt;\n    &lt;version&gt;1.2.1&lt;\/version&gt;\n&lt;\/dependency&gt;\n&lt;dependency&gt;\n    &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;\n    &lt;artifactId&gt;spring-cloud-security&lt;\/artifactId&gt;\n&lt;\/dependency&gt;\n<\/pre>\n<p>This is all you need to do to add OIDC login with Okta! Restart your Gateway app and navigate to&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\"><a href=\"http:\/\/localhost:8080\/fave-cars\">http:\/\/localhost:8080\/fave-cars<\/a><\/code>&nbsp;in your browser to be redirected to Okta for user authorization.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/okta-sign-in-1024x713.png\" alt=\"\" class=\"wp-image-99115\" width=\"768\" height=\"535\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/okta-sign-in-1024x713.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/okta-sign-in-300x209.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/10\/okta-sign-in-768x535.png 768w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<h3 class=\"wp-block-heading\" id=\"make-your-gateway-an-oauth-2-0-resource-server\">Make Your Gateway an OAuth 2.0 Resource Server<\/h3>\n<p>You likely won\u2019t build the UI for your app on the gateway itself. You\u2019ll probably use a SPA or mobile app instead. To configure your gateway to operate as a resource server (that looks for an&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">Authorization<\/code>&nbsp;header with a bearer token), add a new&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">SecurityConfiguration<\/code>&nbsp;class in the same directory as your main class.<\/p>\n<pre class=\"gutter: false;brush:java\">package com.example.apigateway;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;\nimport org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\n\n@EnableWebFluxSecurity\n@EnableReactiveMethodSecurity\npublic class SecurityConfiguration {\n\n    @Bean\n    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {\n        \/\/ @formatter:off\n        http\n            .authorizeExchange()\n                .anyExchange().authenticated()\n                .and()\n            .oauth2Login()\n                .and()\n            .oauth2ResourceServer()\n                .jwt();\n        return http.build();\n        \/\/ @formatter:on\n    }\n}\n<\/pre>\n<h3 class=\"wp-block-heading\" id=\"cors-with-spring-cloud-gateway\">CORS with Spring Cloud Gateway<\/h3>\n<p>If you\u2019re using a SPA for your UI, you\u2019ll want to configure CORS as well. You can do this by adding a&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">CorsWebFilter<\/code>&nbsp;bean to this class.<\/p>\n<pre class=\"gutter: false;brush:java\">@Bean\nCorsWebFilter corsWebFilter() {\n    CorsConfiguration corsConfig = new CorsConfiguration();\n    corsConfig.setAllowedOrigins(List.of(\"*\"));\n    corsConfig.setMaxAge(3600L);\n    corsConfig.addAllowedMethod(\"*\");\n    corsConfig.addAllowedHeader(\"*\");\n\n    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();\n    source.registerCorsConfiguration(\"\/**\", corsConfig);\n\n    return new CorsWebFilter(source);\n}\n<\/pre>\n<p>Make sure your imports match the ones below.<\/p>\n<pre class=\"gutter: false;brush:java\">import org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.cors.reactive.CorsWebFilter;\nimport org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;\n<\/pre>\n<p>Spring Cloud Gateway\u2019s documentation explains how to configure CORS with&nbsp;<a href=\"https:\/\/cloud.spring.io\/spring-cloud-gateway\/multi\/multi__cors_configuration.html\">YAML<\/a>&nbsp;or with&nbsp;<a href=\"https:\/\/www.baeldung.com\/spring-webflux-cors#global\"><code style=\"font-size:13px\" class=\"highlighter-rouge\">WebFluxConfigurer<\/code><\/a>. Unfortunately, I was unable to get either one to work.<\/p>\n<h2 class=\"wp-block-heading\" id=\"test-your-gateway-with-webtestclient-and-jwt\">Test Your Gateway with WebTestClient and JWT<\/h2>\n<p>If you configured CORS in your gateway, you can test it works with WebTestClient. Replace the code in&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">ApiGatewayApplicationTests<\/code>&nbsp;with the following.<\/p>\n<pre class=\"gutter: false;brush:java\">import java.util.Map;\nimport java.util.function.Consumer;\n\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.when;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n        properties = {\"spring.cloud.discovery.enabled = false\"})\npublic class ApiGatewayApplicationTests {\n\n    @Autowired\n    WebTestClient webTestClient;\n\n    @MockBean (1)\n    ReactiveJwtDecoder jwtDecoder;\n\n    @Test\n    public void testCorsConfiguration() {\n        Jwt jwt = jwt(); (2)\n        when(this.jwtDecoder.decode(anyString())).thenReturn(Mono.just(jwt)); (3)\n        WebTestClient.ResponseSpec response = webTestClient.put().uri(\"\/\")\n                .headers(addJwt(jwt)) (4)\n                .header(\"Origin\", \"http:\/\/example.com\")\n                .exchange();\n\n        response.expectHeader().valueEquals(\"Access-Control-Allow-Origin\", \"*\");\n    }\n\n    private Jwt jwt() {\n        return new Jwt(\"token\", null, null,\n                Map.of(\"alg\", \"none\"), Map.of(\"sub\", \"betsy\"));\n    }\n\n    private Consumer&lt;HttpHeaders&gt; addJwt(Jwt jwt) {\n        return headers -&gt; headers.setBearerAuth(jwt.getTokenValue());\n    }\n}\n<\/pre>\n<ol class=\"wp-block-list\">\n<li> Mock&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">ReactiveJwtDecoder<\/code>&nbsp;so you can set expectations and return mocks when it decodes <\/li>\n<li> Create a new JWT <\/li>\n<li> Return the same JWT when it\u2019s decoded <\/li>\n<li>Add the JWT to the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">Authorization<\/code>&nbsp;header with a&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">Bearer<\/code>&nbsp;prefix<\/li>\n<\/ol>\n<p>I like how&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">WebTestClient<\/code>&nbsp;allows you to set the security headers so easily!<\/p>\n<p>You\u2019ve configured Spring Cloud Gateway to use OIDC login and function as an OAuth 2.0 resource server, but the car service is still available on port&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">8081<\/code>. Let\u2019s fix that so only the gateway can talk to it.<\/p>\n<h2 class=\"wp-block-heading\" id=\"secure-gateway-to-microservice-communication\">Secure Gateway to Microservice Communication<\/h2>\n<p>Add the Okta Spring Boot starter to&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">car-service\/pom.xml<\/code>:<\/p>\n<pre class=\"gutter: false;brush:xml\">&lt;dependency&gt;\n    &lt;groupId&gt;com.okta.spring&lt;\/groupId&gt;\n    &lt;artifactId&gt;okta-spring-boot-starter&lt;\/artifactId&gt;\n    &lt;version&gt;1.2.1&lt;\/version&gt;\n&lt;\/dependency&gt;\n<\/pre>\n<p>Copy the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">okta.*<\/code>&nbsp;properties from the gateway\u2019s&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">application.properties<\/code>&nbsp;to the car service\u2019s. Then create a&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">SecurityConfiguration<\/code>&nbsp;class to make the app an OAuth 2.0 resource server.<\/p>\n<pre class=\"gutter: false;brush:java\">package com.example.carservice;\n\nimport com.okta.spring.boot.oauth.Okta;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;\nimport org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\n\n@EnableWebFluxSecurity\n@EnableReactiveMethodSecurity\npublic class SecurityConfiguration {\n\n    @Bean\n    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {\n        \/\/ @formatter:off\n        http\n            .authorizeExchange()\n                .anyExchange().authenticated()\n                .and()\n            .oauth2ResourceServer()\n                .jwt();\n\n        Okta.configureResourceServer401ResponseBody(http);\n\n        return http.build();\n        \/\/ @formatter:on\n    }\n}\n<\/pre>\n<p>That\u2019s it! Restart your car service application and it\u2019s now protected from anonymous intruders.<\/p>\n<pre class=\"gutter: false;brush:bash\">$ http :8081\/cars\nHTTP\/1.1 401 Unauthorized\nCache-Control: no-cache, no-store, max-age=0, must-revalidate\nContent-Type: text\/plain\n...\n\n401 Unauthorized\n<\/pre>\n<h2 class=\"wp-block-heading\" id=\"test-your-microservice-with-webtestclient-and-jwt\">Test Your Microservice with WebTestClient and JWT<\/h2>\n<p>The tests you added in the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">car-service<\/code>&nbsp;project will no longer work now that you\u2019ve enabled security. Modify the code in&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">CarServiceApplicationTests.java<\/code>&nbsp;to add JWT access tokens to each request.<\/p>\n<pre class=\"gutter: false;brush:java\">package com.example.carservice;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.mock.mockito.MockBean;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.oauth2.jwt.Jwt;\nimport org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport reactor.core.publisher.Mono;\n\nimport java.time.LocalDate;\nimport java.time.Month;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.function.Consumer;\n\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.when;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n        properties = {\"spring.cloud.discovery.enabled = false\"})\npublic class CarServiceApplicationTests {\n\n    @Autowired\n    CarRepository carRepository;\n\n    @Autowired\n    WebTestClient webTestClient;\n\n    @MockBean\n    ReactiveJwtDecoder jwtDecoder;\n\n    @Test\n    public void testAddCar() {\n        Car buggy = new Car(UUID.randomUUID(), \"ID. BUGGY\", LocalDate.of(2022, Month.DECEMBER, 1));\n\n        Jwt jwt = jwt();\n        when(this.jwtDecoder.decode(anyString())).thenReturn(Mono.just(jwt));\n\n        webTestClient.post().uri(\"\/cars\")\n                .contentType(MediaType.APPLICATION_JSON_UTF8)\n                .accept(MediaType.APPLICATION_JSON_UTF8)\n                .headers(addJwt(jwt))\n                .body(Mono.just(buggy), Car.class)\n                .exchange()\n                .expectStatus().isCreated()\n                .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)\n                .expectBody()\n                .jsonPath(\"$.id\").isNotEmpty()\n                .jsonPath(\"$.name\").isEqualTo(\"ID. BUGGY\");\n    }\n\n    @Test\n    public void testGetAllCars() {\n        Jwt jwt = jwt();\n        when(this.jwtDecoder.decode(anyString())).thenReturn(Mono.just(jwt));\n\n        webTestClient.get().uri(\"\/cars\")\n                .accept(MediaType.APPLICATION_JSON_UTF8)\n                .headers(addJwt(jwt))\n                .exchange()\n                .expectStatus().isOk()\n                .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)\n                .expectBodyList(Car.class);\n    }\n\n    @Test\n    public void testDeleteCar() {\n        Car buzzCargo = carRepository.save(new Car(UUID.randomUUID(), \"ID. BUZZ CARGO\",\n                LocalDate.of(2022, Month.DECEMBER, 2))).block();\n\n        Jwt jwt = jwt();\n        when(this.jwtDecoder.decode(anyString())).thenReturn(Mono.just(jwt));\n\n        webTestClient.delete()\n                .uri(\"\/cars\/{id}\", Map.of(\"id\", buzzCargo.getId()))\n                .headers(addJwt(jwt))\n                .exchange()\n                .expectStatus().isOk();\n    }\n\n    private Jwt jwt() {\n        return new Jwt(\"token\", null, null,\n                Map.of(\"alg\", \"none\"), Map.of(\"sub\", \"dave\"));\n    }\n\n    private Consumer&lt;HttpHeaders&gt; addJwt(Jwt jwt) {\n        return headers -&gt; headers.setBearerAuth(jwt.getTokenValue());\n    }\n}\n<\/pre>\n<p>Run the test again and everything should pass!<\/p>\n<h2 class=\"wp-block-heading\" id=\"mock-jwt-support-in-spring-security-5-2\">Mock JWT Support in Spring Security 5.2<\/h2>\n<p>Kudos to&nbsp;<a href=\"https:\/\/spring.io\/team\/jzheaux\">Josh Cummings<\/a>&nbsp;for his help with JWTs and WebTestClient. Josh gave me a preview of the mock JWT support coming in Spring Security 5.2.<\/p>\n<pre class=\"gutter: false;brush:java\">this.webTestClient.mutateWith(jwt()).post(...)\n<\/pre>\n<p>Josh also provided an&nbsp;<a href=\"https:\/\/github.com\/spring-projects\/spring-security\/blob\/master\/samples\/boot\/oauth2resourceserver-webflux\/src\/test\/java\/sample\/OAuth2ResourceServerControllerTests.java\">example test showing how to mock a JWT\u2019s subject, scope, and claims<\/a>. This code is based on new functionality in Spring Security 5.2.0.M3.<\/p>\n<p>The future is bright for OAuth 2.0 and JWT support in Spring Security land! \ud83d\ude0e<\/p>\n<h2 class=\"wp-block-heading\" id=\"relay-the-access-token-gateway-to-microservice\">Relay the Access Token: Gateway to Microservice<\/h2>\n<p>You only need to make one small change for your gateway to talk to this protected service. It\u2019s incredibly easy and I \u2764\ufe0f it!<\/p>\n<p>In&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">ApiGatewayApplication.java<\/code>, add a filter that applies the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">TokenRelayGatewayFilterFactory<\/code>&nbsp;from Spring Cloud Security.<\/p>\n<pre class=\"gutter: false;brush:java\">import org.springframework.cloud.security.oauth2.gateway.TokenRelayGatewayFilterFactory;\n\n@Bean\npublic RouteLocator customRouteLocator(RouteLocatorBuilder builder,\n                                       TokenRelayGatewayFilterFactory filterFactory) {\n    return builder.routes()\n            .route(\"car-service\", r -&gt; r.path(\"\/cars\")\n                    .filters(f -&gt; f.filter(filterFactory.apply()))\n                    .uri(\"lb:\/\/car-service\/cars\"))\n            .build();\n}\n<\/pre>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p> This relay factory does not&nbsp;<a href=\"https:\/\/github.com\/spring-cloud\/spring-cloud-security\/issues\/175\">automatically refresh access tokens<\/a>&nbsp;(yet). <\/p>\n<\/blockquote>\n<p>Restart your API gateway and you should be able to view&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\"><a href=\"http:\/\/localhost:8080\/cars\">http:\/\/localhost:8080\/cars<\/a><\/code>&nbsp;and have everything work as expected.<\/p>\n<p>Pretty sweet, don\u2019t you think?!<\/p>\n<h2 class=\"wp-block-heading\" id=\"learn-more-about-spring-cloud-gateway-and-reactive-microservices-with-spring\">Learn More about Spring Cloud Gateway and Reactive Microservices with Spring<\/h2>\n<p>I\u2019ve barely scratched the surface of what Spring Cloud Gateway is capable of. If you\u2019re building reactive microservices, I\u2019d suggest you take a look at it.<\/p>\n<p>See the&nbsp;<a href=\"https:\/\/spring.io\/projects\/spring-cloud-gateway\">Spring Cloud Gateway<\/a>&nbsp;project page for more information, including documentation. I also found these tutorials useful:<\/p>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/spring.io\/blog\/2019\/06\/18\/getting-started-with-spring-cloud-gateway\">Getting Started with Spring Cloud Gateway<\/a>&nbsp;&#8211; June 18, 2019<\/li>\n<li><a href=\"https:\/\/www.devglan.com\/spring-cloud\/spring-cloud-gateway\">Spring Cloud Gateway Tutorial<\/a>&nbsp;&#8211; May 30, 2019<\/li>\n<\/ul>\n<p>You can find the source code for this example at&nbsp;<a href=\"https:\/\/github.com\/oktadeveloper\/java-microservices-examples\">@oktadeveloper\/java-microservices-examples<\/a>, in the&nbsp;<code style=\"font-size:13px\" class=\"highlighter-rouge\">spring-cloud-gateway<\/code>&nbsp;directory.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ngit clone https:\/\/github.com\/oktadeveloper\/java-microservices-examples.git\ncd java-microservices-examples\/spring-cloud-gateway\n<\/pre>\n<\/div>\n<p>To learn more about microservices and reactive programming with Java and Spring, check out these posts.<\/p>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2019\/05\/22\/java-microservices-spring-boot-spring-cloud\/?utm_campaign=text_website_all_multiple_dev_dev_reactive-microservice-spring-cloud_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Java Microservices with Spring Boot and Spring Cloud<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2019\/05\/23\/java-microservices-spring-cloud-config\/?utm_campaign=text_website_all_multiple_dev_dev_reactive-microservice-spring-cloud_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Java Microservices with Spring Cloud Config and JHipster<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2019\/08\/09\/jib-docker-spring-boot\/?utm_campaign=text_website_all_multiple_dev_dev_reactive-microservice-spring-cloud_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Get Jibby With Java, Docker, and Spring Boot<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2019\/02\/28\/spring-microservices-docker\/?utm_campaign=text_website_all_multiple_dev_dev_reactive-microservice-spring-cloud_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Build Spring Microservices and Dockerize Them for Production<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2018\/09\/24\/reactive-apis-with-spring-webflux\/?utm_campaign=text_website_all_multiple_dev_dev_reactive-microservice-spring-cloud_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Build Reactive APIs with Spring WebFlux<\/a><\/li>\n<\/ul>\n<p>If you liked this tutorial, follow&nbsp;<a href=\"https:\/\/twitter.com\/oktadev\">@oktadev<\/a>&nbsp;on Twitter. We also publish screencasts to&nbsp;<a href=\"https:\/\/youtube.com\/c\/oktadev\">our YouTube channel<\/a>&nbsp;on a regular basis.<\/p>\n<p><a href=\"https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway\/?utm_campaign=text_website_all_multiple_dev_dev_reactive-microservice-spring-cloud_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Secure Reactive Microservices with Spring Cloud Gateway<\/a>&nbsp;was originally published on the Okta Developer Blog on August 28, 2019.<\/p>\n<p><span style=\"font-size: 20px;\"><strong>Friends don\u2019t let friends write user auth. Tired of managing your own users?<\/strong><a href=\"https:\/\/developer.okta.com\/signup\/?utm_campaign=text_website_all_multiple_dev_dev_spring-preauthorize_null&amp;utm_source=jcg&amp;utm_medium=cpc\"> Try Okta\u2019s API and Java SDKs today. Authenticate, manage, and secure users in any application within minutes.<\/a><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Friends don\u2019t let friends write user auth. Tired of managing your own users? Try Okta\u2019s API and Java SDKs today. Authenticate, manage, and secure users in any application within minutes. So you wanna go full reactive, eh? Great! Reactive programming is an increasingly popular way to make your applications more efficient. Instead of making a &hellip;<\/p>\n","protected":false},"author":13127,"featured_media":240,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[30,992],"class_list":["post-99108","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-spring","tag-spring-cloud"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Secure Reactive Microservices with Spring Cloud Gateway - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"Interested to learn about Spring Cloud Gateway? Check our article explaining how to Secure Reactive Microservices with Spring Cloud Gateway\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Secure Reactive Microservices with Spring Cloud Gateway - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"Interested to learn about Spring Cloud Gateway? Check our article explaining how to Secure Reactive Microservices with Spring Cloud Gateway\" \/>\n<meta property=\"og:url\" content=\"https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2019-10-14T09:47:10+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-10-23T09:12:58+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Matt Raible\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@mraible\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Matt Raible\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"23 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/08\\\/28\\\/reactive-microservices-spring-cloud-gateway#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/10\\\/secure-reactive-microservices-with-spring-cloud-gateway.html\"},\"author\":{\"name\":\"Matt Raible\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/54edd49deb980d7706e2af51514c3f7f\"},\"headline\":\"Secure Reactive Microservices with Spring Cloud Gateway\",\"datePublished\":\"2019-10-14T09:47:10+00:00\",\"dateModified\":\"2019-10-23T09:12:58+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/10\\\/secure-reactive-microservices-with-spring-cloud-gateway.html\"},\"wordCount\":2614,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/08\\\/28\\\/reactive-microservices-spring-cloud-gateway#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"keywords\":[\"Spring\",\"Spring Cloud\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/08\\\/28\\\/reactive-microservices-spring-cloud-gateway#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/10\\\/secure-reactive-microservices-with-spring-cloud-gateway.html\",\"url\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/08\\\/28\\\/reactive-microservices-spring-cloud-gateway\",\"name\":\"Secure Reactive Microservices with Spring Cloud Gateway - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/08\\\/28\\\/reactive-microservices-spring-cloud-gateway#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/08\\\/28\\\/reactive-microservices-spring-cloud-gateway#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"datePublished\":\"2019-10-14T09:47:10+00:00\",\"dateModified\":\"2019-10-23T09:12:58+00:00\",\"description\":\"Interested to learn about Spring Cloud Gateway? Check our article explaining how to Secure Reactive Microservices with Spring Cloud Gateway\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/08\\\/28\\\/reactive-microservices-spring-cloud-gateway#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/08\\\/28\\\/reactive-microservices-spring-cloud-gateway\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/08\\\/28\\\/reactive-microservices-spring-cloud-gateway#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"width\":150,\"height\":150,\"caption\":\"spring-interview-questions-answers\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/08\\\/28\\\/reactive-microservices-spring-cloud-gateway#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Secure Reactive Microservices with Spring Cloud Gateway\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/54edd49deb980d7706e2af51514c3f7f\",\"name\":\"Matt Raible\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g\",\"caption\":\"Matt Raible\"},\"description\":\"Java Champion and Developer Advocate @okta with a passion for skiing, mtn biking, VWs, &amp; good beer.\",\"sameAs\":[\"https:\\\/\\\/developer.okta.com\",\"https:\\\/\\\/x.com\\\/mraible\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/matt-raible\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Secure Reactive Microservices with Spring Cloud Gateway - Java Code Geeks","description":"Interested to learn about Spring Cloud Gateway? Check our article explaining how to Secure Reactive Microservices with Spring Cloud Gateway","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway","og_locale":"en_US","og_type":"article","og_title":"Secure Reactive Microservices with Spring Cloud Gateway - Java Code Geeks","og_description":"Interested to learn about Spring Cloud Gateway? Check our article explaining how to Secure Reactive Microservices with Spring Cloud Gateway","og_url":"https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2019-10-14T09:47:10+00:00","article_modified_time":"2019-10-23T09:12:58+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","type":"image\/jpeg"}],"author":"Matt Raible","twitter_card":"summary_large_image","twitter_creator":"@mraible","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Matt Raible","Est. reading time":"23 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2019\/10\/secure-reactive-microservices-with-spring-cloud-gateway.html"},"author":{"name":"Matt Raible","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/54edd49deb980d7706e2af51514c3f7f"},"headline":"Secure Reactive Microservices with Spring Cloud Gateway","datePublished":"2019-10-14T09:47:10+00:00","dateModified":"2019-10-23T09:12:58+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2019\/10\/secure-reactive-microservices-with-spring-cloud-gateway.html"},"wordCount":2614,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","keywords":["Spring","Spring Cloud"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2019\/10\/secure-reactive-microservices-with-spring-cloud-gateway.html","url":"https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway","name":"Secure Reactive Microservices with Spring Cloud Gateway - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway#primaryimage"},"image":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","datePublished":"2019-10-14T09:47:10+00:00","dateModified":"2019-10-23T09:12:58+00:00","description":"Interested to learn about Spring Cloud Gateway? Check our article explaining how to Secure Reactive Microservices with Spring Cloud Gateway","breadcrumb":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","width":150,"height":150,"caption":"spring-interview-questions-answers"},{"@type":"BreadcrumbList","@id":"https:\/\/developer.okta.com\/blog\/2019\/08\/28\/reactive-microservices-spring-cloud-gateway#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Secure Reactive Microservices with Spring Cloud Gateway"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/54edd49deb980d7706e2af51514c3f7f","name":"Matt Raible","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g","caption":"Matt Raible"},"description":"Java Champion and Developer Advocate @okta with a passion for skiing, mtn biking, VWs, &amp; good beer.","sameAs":["https:\/\/developer.okta.com","https:\/\/x.com\/mraible"],"url":"https:\/\/www.javacodegeeks.com\/author\/matt-raible"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/99108","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/13127"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=99108"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/99108\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/240"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=99108"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=99108"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=99108"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}