No Access-Control-Allow-Origin header is present on the requested resource angular Spring boot

During the development of your application it is a good practice to work with 2 separate server. A server for your backend and a server for your frontend.
Your JavaScript frontend will communicate with your backend to collect information using REST services.

At this moment you will incur in a problem : for security reasons browsers don’t allow that a page answering from the domainA load resources from a domainB.

No Access-Control-Allow-Origin header is present on the requested resource angular Spring boot

How CORS works

You can read the detailed explanation of the CORS mechanism here: Mozilla

To summarize, the browser for security reasons must enforce the Same-Origin-Policy. By default, it won't allow your website: http://mywebsite.com to access resources of a different website if not explicitly allowed.

To define if the origin is the same the browser use the scheme, host and port of the server e.g.: http://mydomain.com has a different host of : http://api.mydomain.com for this reason the requests will be blocked.

When you try to access a different domain, the browser send a pre-flight request with OPTIONS to get information from the target server. If the target server responds with Access-Control-Allow-Origin: http://mydomain.com in the headers, your browser will send requests to it.

How to allow CORS requests

Angular

In our Angular request, if we don't use the HttpClient that comes with the framework, we have to add the header
X-Requested-With. This header enables a webpage to update just partially.

this.headers = new Headers({ 'Content-Type': 'application/json' }) this.headers.append('Accept', 'application/json, text/csv'); this.headers.append('X-Requested-With', 'XMLHttpRequest');

The same solution works for React and Vue.js projects.

Spring Boot

Building a Spring application with a web client when you deploy the application on 2 different servers or ports you could get this error when you try a REST call:

Access to XMLHttpRequest at '[url]' from origin '[url]' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

By default, for security reasons, the application server doesn't allow that clients running in other machines / on other ports use your service without authorization.

For an intranet / secured network application you can simply allow all the request to be executed

With @CrossOrigin annotation

import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; @RestController @CrossOrigin("*") public class FoodController {

The * accepts requests from every origin, for production environments you have to fine tune this parameter.

To see in the detail the feature:

@CorsOrigin source code

CorsConfiguration source code

Without annotations

You have to update the ALLOWED_ORIGINS constant with the URL of the frontend server sending the requests to the backend server. 

@Configuration public class CorsConfig { private static final String[] ALLOWED_ORIGINS = {"https://localhost:3000", "https://localhost:8080"}; @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/*").allowedOrigins(ALLOWED_ORIGINS); } }; } }

Java EE

Filter

The filter solution can be used in Servlet compatible Servers.

@Order(Ordered.HIGHEST_PRECEDENCE) class CorsFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Allow-Headers", "Authorization,Content-Type, x-requested-with"); response.setHeader("Access-Control-Max-Age", "3600"); if (((HttpServletRequest)req).getMethod().equals("OPTIONS")) { response.setStatus(HttpServletResponse.SC_OK); } else { chain.doFilter(req, res); } } public void init(FilterConfig filterConfig) {} public void destroy() {} }

An Angular app is served by a different host than a Spring Boot API, so reaching for data via REST API will result in the following error:
"Failed to load http://localhost:8080/api: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access."

Read this post to learn how to configure Cross-origin resource sharing (CORS) to enable the cross-domain communication on a development environment.

For security reasons, browsers don’t allow calls to resources residing outside the current origin. To specify what kind of cross-domain requests are authorised in our app, we are going to configure CORS globally.

Allow Angular to consume data fetched by Spring Boot

In this example we are working on a project that is built with Maven into a single application with frontend powered by Angular and backend run with Spring Boot. Therefore, we require CORS only on the development environment, to enable working on an Angular app without the need of rebuilding the whole project.

You can find the spring-boot-angular-scaffolding project repository on GitHub.

Add the DevCorsConfiguration class to your config directory:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

// spring-boot-angular-scaffolding/backend/src/main/java/in/keepgrowing/springbootangularscaffolding/config/DevCorsConfiguration.java

packagein.keepgrowing.springbootangularscaffolding.config;

import org.springframework.context.annotation.Configuration;

importorg.springframework.context.annotation.Profile;

import org.springframework.web.servlet.config.annotation.CorsRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration

@Profile("development")

publicclassDevCorsConfiguration implementsWebMvcConfigurer{

    @Override

    publicvoidaddCorsMappings(CorsRegistry registry){

        registry.addMapping("/api/**").allowedMethods("GET", "POST","PUT","PATCH","DELETE","OPTIONS");

    }

}

This configuration enables CORS requests from any origin to the api/ endpoint in the application. You can narrow the access by using the allowedOrigins, allowedMethods, allowedHeaders, exposedHeaders, maxAge or allowCredentials methods – check out the examples in this spring.io blog post.

Declare the active profile of your application

Spring provides a way to configure an application accordingly to various environments – it picks up the application configuration based on the active profile.

Our DevCorsConfiguration class uses @Profile annotation to load its configuration only on a development environment. We will specify the active profile in the application.properties file:

# application.properties

spring.profiles.active=development

The work done in this post is contained in the commit 405a4aa5bae96105af5581551c1e6341c3b7acbf.

Run the backend and frontend modules separately, then open your browser on http://localhost:4200/ , you should see this Angular start screen, without any errors in the console:

No Access-Control-Allow-Origin header is present on the requested resource angular Spring boot

Troubleshooting

Thanks to the Stormbreaker’s comment I realised I should edit the post to add the following.

You didn’t specify OPTIONS in the allowed methods list

To obtain the communication options available for the target resource, a preflight request with the OPTIONS  method is sent. You can read about the details in the Preflighted requests in CORS and Functional overview chapters in the MDN web docs about CORS. Make sure that the  OPTIONS  method is allowed:

// spring-boot-angular-scaffolding/backend/src/main/java/in/keepgrowing/springbootangularscaffolding/config/DevCorsConfiguration.java

.allowedMethods("GET","POST","PUT","PATCH","DELETE", "OPTIONS");

I missed that in the original version of my project, you can find the update in the 817bbe2acea969b1f686f2d721490d75ffef1631 commit.

You want to authorise users

When your project uses authentication and authorisation mechanisms, like Json Web Token standard, you should configure it to process authorisation header. Add "Authorisation"  to the exposedHeaders()  method like in the example below (line 17):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

// scrum_ally/backend/src/main/java/in/keepgrowing/springbootangularscaffolding/config/DevCorsConfiguration.java

packagein.keepgrowing.scrumally.config;

import org.springframework.context.annotation.Configuration;

importorg.springframework.context.annotation.Profile;

import org.springframework.web.servlet.config.annotation.CorsRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration

@Profile("development")

publicclassDevCorsConfiguration implementsWebMvcConfigurer{

    @Override

    publicvoidaddCorsMappings(CorsRegistry registry){

        registry.addMapping("/api/**")

                .allowedMethods("GET","POST","PUT","PATCH","DELETE","OPTIONS")

                .exposedHeaders("Authorization");

    }

}

I was able to solve this problem thanks to this response from StackOverflow. You can find this code in my scrum_ally repository.

Photo by Daria Shevtsova on StockSnap