Implementing CORS in Spring Boot with Spring Security
Last Updated :
16 Jul, 2024
CORS issue is one of the common issues being faced in web development. We are here going to configure CORS in our backend application built using Spring Boot and Spring security, being used for security purpose.
Before going to fix the issue, lets understand what CORS is and how it works and why browsers show error while sending CORS request.
What is CORS?
Cross-Origin Resource Sharing (CORS) is a type of additional security layer that you can consider which is implemented by most of the browsers. It is the specification provided by W3C, which all browsers implement by default. This CORS issue arises when you make request to server from different origin. The difference can be between port numbers or domain or the protocols (http/https).
Actions performed by browsers while making a CORS request
- Browsers will first make a preflight request to the server checking for the requested domain is allowed to access the resource or not. Preflight request is made by browsers automatically in case of CORS request before original request is sent to server.
- After making pre-flight request and getting response from the server, it will decide whether to make the request to the server or not. And if not, it will throw a CORS error otherwise it will make the actual request.
- Browsers will not make the pre-flight request each time to the server, it caches the response of first pre-flight response and will use the same response.
- The cache cleans up according to what maxAge you have specified in the CORS configs in server side. After that tenure, if any further request is requested to make, then it will make the pre-flight call again and this process will continue.
Configuring CORS in Spring Boot application with the help of Spring Security
We are going to create our spring application and will configure according to our needs. We will be having two applications; one will be named as server and other as client both running on different ports.
We will see how CORS configuration makes the communication possible between these two applications running on different ports or different origins.
Prerequisites:
- JDK 17 or above
- IntelliJ Idea or your other favourite IDE
Now, we will create one server application and one client application.
Server Application
Step 1: Creating Server application
Create a spring boot application from Spring Initializer with these set of configurations provided below.
Add two dependencies by clicking on add dependencies button:
- Spring Web
- Spring Security
Server applicationNote: Here, we are going to use the latest spring security version 6.X, just mentioning that spring security 5 or below were earlier involving WebSecurityConfigurerAdapter class, where we used to provide the spring security related configs. But in spring security 6, those things have been deprecated and removed by introducing SecurityFilterChain in latest version, where you have to provide the configurations related to spring security.
pom.xml file:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo</groupId>
<artifactId>Server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Server</name>
<description>Server</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Step 2: Create Controller
We will have a GET API exposed in this controller with endpoint as "/hello". It will return a string message "Hello World" in response.
HelloController.java:
Java
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public ResponseEntity<String> hello() {
return ResponseEntity.ok("Hello World");
}
}
Step 3: Setting Server property in application.properties file
spring.application.name=Server
server.port=5050
We will run our server on port 5050.
Step 4: Create Configuration Class
Create a SecurityConfiguration class and add the following code. This file will have the configurations related to CORS.
In this file, we have configured the bean of SecurityFilterChain. This bean is responsible for all the spring security related configurations. In this bean only, we are providing configs related to CORS in cors() method of HttpSecurity.
SecurityConfiguration.java:
Java
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration
public class SecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors(corsCustomizer->corsCustomizer.configurationSource(new CorsConfigurationSource() {
@Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration corsConfiguration=new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);// allows taking authentication with credentials
corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:7070"));
// providing the allowed origin details, can provide multiple origins here, 7070 is the port number of client application here
corsConfiguration.setAllowedMethods(Collections.singletonList("*"));// allowing all HTTP methods GET,POST,PUT etc, can configure on your need
corsConfiguration.setAllowedHeaders(Collections.singletonList("*"));// allowing all the request headers, can configure according to your need, which headers to allow
corsConfiguration.setMaxAge(Duration.ofMinutes(5L)); // setting the max time till which the allowed origin will not make a pre-flight request again to check if the CORS is allowed on not
return corsConfiguration;
}
}))
.authorizeHttpRequests(auth->auth.requestMatchers("/hello").permitAll()//this autorizeHttpRequests method is related to configuring your API security based on roles, this is not realted to CORS
.anyRequest() .authenticated())
.formLogin(withDefaults());
return httpSecurity.build();
}
}
Note: This was just the configuration related to CORS, you can modify as per your need.
Output:
Client Application
Similar to server app, we will create another spring boot application which is named as "Client". It will run on different port and will make call to "/hello" endpoint of server application.
Step 1: Create Client Application
Select the configurations in spring initializer for client application.
Add two dependencies by clicking on add dependencies button:
- Spring Web
- Spring Reactive Web
Here, we are using spring reactive web to use WebClient to make REST API call to server application.
Client Application
pom.xml file:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo</groupId>
<artifactId>Client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Client</name>
<description>Client</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Step 2: WebClient Bean Configuration in ClientApplication.java
Java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.reactive.function.client.WebClient;
import java.beans.BeanProperty;
@SpringBootApplication
public class ClientApplication {
@Bean
public WebClient webClient(){
return WebClient.builder().baseUrl("http://localhost:5050").build();
}
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
Step 3: Creating HelloController.java in Client application
This controller will have an endpoint "/hello" and when we make a call to "/hello" endpoint of client application, then it will internally make a call to "/hello" endpoint of server application.
Java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
@RestController
public class HelloController {
@Autowired
private WebClient webClient;
@GetMapping("/hello")
public ResponseEntity<String> hello(){
return webClient.get().uri("/hello").retrieve()
.toEntity(String.class).block();
}
}
Step 4: Adding properties in application.properties file
spring.application.name=Client
server.port=7070
Client application will run on 7070 port number.
Output:
We will now start application and hit the "/hello" endpoint of the application.
Hitting endpoint "/hello" of server:
Now we will try to make request to "/hello" endpoint of client application which will internally make call to server application to its "/hello" endpoint. We are configured the CORS properly in server side so will get proper response in client application.
Output after proper CORS configuration:
We have seen how to configure CORS in our application and tested the output through client application by making a CORS request. You can control the settings of CORS as per your requirements.
Similar Reads
How to Integrate Keycloak with Spring Boot and Spring Security?
Keycloak is Open Source Identity and Access Management (IAM) solution developed by Red Hat. By using this you can add authentication to applications and secure services with minimum effort. No need to deal with storing users or authenticating users. Keycloak provides user federation, strong authenti
2 min read
Implementing OAuth2 with Spring Security: A Step-by-Step Guide
OAuth is an authorization framework that creates a permissions policy and enables applications to have limited access to user accounts on HTTP services such as Facebook, GitHub, and Google. It works by allowing the users to authorize third-party applications to access their data without sharing thei
8 min read
How to Implement One to Many Mapping in Spring Boot?
Spring Boot is built on the top of the spring and contains all the features of spring. Spring also provides JPA and hibernate to increase the data manipulation efficiency between the spring application and the database. In very simple terms we can say JPA (Java persistence API) is like an interface
3 min read
Properties with Spring and Spring Boot
Java-based applications using the Spring framework and its evolution into the Spring Boot and the properties play a crucial role in configuring the various aspects of the application. Properties can allow the developers to externalize the configuration settings from the code. Understanding how to wo
4 min read
Security with Spring Security and Spring Webflux
Spring WebFlux is a part of the Spring Framework that supports reactive programming, enabling non-blocking asynchronous request handling. When developing web applications with Spring WebFlux, securing the application is a crucial aspect to ensure unauthorized access is prevented. This article provid
3 min read
Testing Spring Security Auth with JUnit
Here we are going to learn how to use InMemoryDaoImpl to verify Spring security authentication using a JUnit test case and how to programmatically create a fully complete authentication object and then utilize it in an application. SecurityContextHolder: Spring security is built on the concept of a
4 min read
Spring Security - Custom Form Login with Example
Spring Security is a framework that allows a programmer to use JEE components to set security limitations on Spring-framework-based Web applications. In a nutshell, itâs a library that can be utilized and customized to suit the demands of the programmer. Because it is a part of the same Spring famil
8 min read
Returning Errors Using ProblemDetail in Spring Boot
In a Spring Boot application, error handling is an important aspect of providing a robust and user-friendly API. Traditionally, Spring Boot has provided various methods like @ExceptionHandler, ResponseEntityExceptionHandler, and @ControllerAdvice for handling exceptions. With Spring Framework 6 and
7 min read
Spring Security - Securing Endpoints Using antMatchers()
antMatchers() is used to configure the URL paths which either can be permitted or denied to the user's http request, according to the role or the authorization of that particular user. The authorizeHttpRequests().antMatchers() are used to apply authorization to one or more paths you specify in antMa
8 min read
Extra Login Fields with Spring Security
In many applications, the default login mechanism of the Spring Security which usually requires just the username and password sometimes it may not be sufficient. An application might need the additional information for the authentication such as the users role, department or the security question.
10 min read