Categories: Spring Boot

Fix CORS issues between Spring Boot and Angular on localhost

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:

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

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@Profile("development")
public class DevCorsConfiguration implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(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 allowedOriginsallowedMethods, 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:

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.

Be aware, that not all requests trigger a CORS preflight. You can read about it in the Simple requests chapter in the MDN web docs.

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):

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

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@Profile("development")
public class DevCorsConfiguration implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(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

little_pinecone

View Comments

  • Hello, I have done the same thing but it doesn't work for me ! It event hided my RestController and its methods (even with Swagger I'm not able to do Rest calls)

    • I had also Problems with CORS here, this helped me:

      Add "OPTIONS" to the allowed methods and ".exposedHeaders("Authorization")". Little-Pinecone did that, but you can only see it in her github project.

      Hope this helps you!

      Btw: great work little_pinecone with the angular/spring boot project, your tutorials helped me very much! :)

  • Thank you so much for the feedback :)
    You are right, I used different configuration in the project scrum_ally, after I had introduced the JWT standard for authentication and authorisation. You can find the new configuration in the project repository.

  • Hi little_pinecone,

    thx for all your hints.

    But with all your recommendations in place I still face the error "Access to XMLHttpRequest at 'https://xyz.mydomain.de/api/authenticate' from origin 'http://localhost' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status."

    That's what I've done so far:

    added the http.cors() in the WebSecurityConfigurerAdapter
    addCorsMappings with /api/**, all my possible origins, allowedMethods("GET", "POST", "PUT", "PATCH", "OPTIONS", "DELETE"), exposedHeaders("Authorization") and allowCredentials(true)
    added a corsConfigurationSource to my WebSecurityConfigurerAdapter (with same properties as in addCorsMappings)

    BTW: I use angular, ionic, capacitor and there is a reverse proxy between front-end and spring boot backend.

    Every idea is welcome.

    Cheers
    Frank

  • I had CORS issue with springBoot back end  and Angular front end application. My Issue got resolved by declaring  my rest controller with all api code methods annotated with  @CrossOrigin("http://localhost:4200") annotation. I was working on local laptop environment and argument to @CrossOrigin will need host and port your front end web app will be running  and communicating with your backend api code for  data display.Though production code should be restrictive on CORSAngular 13 and SpringBoot 2.5

  • @CrossOrigin annotation is not required on all api  methods  if you have defined more than one methods in single  rest controller.Decalre it at class level along with annotation of @RestController 

Recent Posts

Simplify the management of user roles in Spring Boot

Spring Security allows us to use role-based control to restrict access to API resources. However,…

3 years ago

Create a custom annotation to configure Spring Boot tests

A custom annotation in Spring Boot tests is an easy and flexible way to provide…

3 years ago

Keycloak with Spring Boot #4 – Simple guide for roles and authorities

Delegating user management to Keycloak allows us to better focus on meeting the business needs…

3 years ago

Keycloak with Spring Boot #3 – How to authorize requests in Swagger UI

Swagger offers various methods to authorize requests to our Keycloak secured API. I'll show you…

3 years ago

Keycloak with Spring Boot #2 – Spring Security instead of Keycloak in tests

Configuring our Spring Boot API to use Keycloak as an authentication and authorization server can…

3 years ago

Keycloak with Spring Boot #1 – Configure Spring Security with Keycloak

Keycloak provides simple integration with Spring applications. As a result, we can easily configure our…

3 years ago