Search code examples
angularspring-bootspring-securitycorsokta

Okta blocks call from angular front end at localhost:4200 to spring boot backend at localhost:8080


When Okta is used to secure API access, cross domain call from angular app at localhost:4200 to spring boot app at localhost:8080 will be blocked even with @CrossOrigin("*") placed on controller.

Below is the error in developer console:

Access to XMLHttpRequest at http://localhost:8080/api/messages from origin 'http://localhost:4200' 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.

Here is the code of the angular app which makes a GET request to backend with an access token in headers.

getMessages(): Observable<Message[]>{
      const apiUrl = 'http://localhost:8080/api/messages';
      const accessToken = this.oktaAuth.getAccessToken();
      const headers = new HttpHeaders({'Authorization': 'Bearer ' + accessToken, 'Access-Control-Allow-Origin': 'http://localhost:4200'});
      return this.http.get<Message[]>(apiUrl, {headers: headers});
  } 

Both front end and backend are integrated with Okta authentication.

If spring boot Okta starter dependency is removed from POM, cross domain call can be made with @CrossOrigin("") placed at the controller. But if spring boot Okta starter is included in POM, @CrossOrigin("") will not work. Looks like OKta is responding to the preflight request from browser.

Tried to enable CORS by following https://developer.okta.com/docs/guides/enable-cors/main/ and have http://localhost:4200 listed in Trusted Origins ( type CORS ). But this does not work. Okta said Trusted Origins config does not work for OAuth2. This seems to be a common scenario. But I could not find a working solution on Internet. Anyone has a solution for this? Thanks

Tried to enable CORS by following https://developer.okta.com/docs/guides/enable-cors/main/


Solution

  • In my experience, @CrossOrigin stops working when you integrate it with Spring Security. Adding a filter works much better. Can you try registering a CORS filter and see if that works?

    @Bean
    public FilterRegistrationBean simpleCorsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.setAllowedOrigins(Collections.singletonList("http://localhost:4200"));
        config.setAllowedMethods(Collections.singletonList("*"));
        config.setAllowedHeaders(Collections.singletonList("*"));
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean<>(new CorsFilter(source));
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return bean;
    }