2

I'm trying CORS with Spring security. So here is my WebSecurityConfigurerAdapter :


@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors()
                .and()
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .oauth2Login();
    }
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(List.of("*"));
        configuration.setAllowedMethods(List.of("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

And here is my WebMvcCofigurer :

@EnableWebSecurity
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer
{
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry
                .addMapping("/**")
                .allowedOrigins("http://localhost:3000")
                .allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
    }
}

But it gives me from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Current code : SecurityConfig.java

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        securedEnabled = true,
        jsr250Enabled = true,
        prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors()
                .disable()//some stackoverflow solution(not accepted) said so
                .csrf()
                .disable()
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .oauth2Login();
    }
}

WebConfig.java:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@EnableWebSecurity
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://localhost:3000")
                .allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH")
                .allowedHeaders("*")
                .allowCredentials(true);
    }

}

I tried even a filter(As it crashes when starting, so I removed it) MyCorsFilter.java

@Configuration
public class MyCorsFilter {
    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://localhost:3000");
        config.addAllowedHeader("*");//tried list and all other collection stuff
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0);//tried with negative value
        return bean;
    }
}

Also tried

http
.headers()
.addHeaderWriter(
      new StaticHeadersWriter(
            "Access-Control-Allow-Origin",
            "http://localhost:3000"))

And here is the OAuth2 configuration :

@Configuration
public class OAuth2Config {
    @Bean
    @RequestScope
    public GoogleOAuth2 google(OAuth2AuthorizedClientService clientService) {
        Authentication authentication =
                SecurityContextHolder.getContext().getAuthentication();
        String accessToken = null;
        if (authentication.getClass()
                .isAssignableFrom(OAuth2AuthenticationToken.class)) {
            OAuth2AuthenticationToken oauthToken =
                    (OAuth2AuthenticationToken) authentication;
            String clientRegistrationId =
                    oauthToken.getAuthorizedClientRegistrationId();
            if (clientRegistrationId.equals("google")) {
                OAuth2AuthorizedClient client = clientService.loadAuthorizedClient(
                        clientRegistrationId, oauthToken.getName());
                accessToken = client.getAccessToken().getTokenValue();
            }
        }
        return new GoogleOAuth2(accessToken);
    }

}
Maifee Ul Asad
  • 3,992
  • 6
  • 38
  • 86

2 Answers2

6

Recently I faced the exact same error as I was trying to integrate my angular application to enable authentication for JWT based authentication using spring security.

I see what you are missing in your security configuration. Maybe that is the problem.

First of all, if you configure everything related to CORS in your security configuration then you don't need to create filter or extend WebMvcConfigurer.

Below is what you are missing in your security config.

http.csrf().disable().cors().configurationSource(corsConfigurationSource())

Here is complete code I copied and pasted it from my working code which I fixed yesterday.

@Override
protected void configure(HttpSecurity http) throws Exception {

    http  
            .cors()
            .configurationSource(corsConfigurationSource())
            .and()
            .csrf()
            .disable()
            .authorizeRequests()
            .anyRequest()
            .authenticated()
            .and()
            .oauth2Login();

}

And then cors config code is which is almost same as yours.

@Bean
CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList("*"));
    configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH"));
    configuration.setAllowCredentials(true);
    //the below three lines will add the relevant CORS response headers
    configuration.addAllowedOrigin("*");
    configuration.addAllowedHeader("*");
    configuration.addAllowedMethod("*");
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}

Remove your MyCorsFilter and WebConfig class. Both are not needed.

Rajeev
  • 1,730
  • 3
  • 20
  • 33
  • can you clear `jwtAuthEntityPoint` and `jwtFilter` ?? – Maifee Ul Asad Jun 01 '20 at 19:37
  • Simplified as you requested. – Rajeev Jun 01 '20 at 19:56
  • **`Access to XMLHttpRequest at 'https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=693417856482-slejtj57gb2nrcehe82ih45o2vdhkj5t.apps.googleusercontent.com&scope=openid%20profile%20email&state=g9XON-I0coOhmke3n4wBAmMdhFQs1YgCq8ytPWWBVrU%3D&redirect_uri=http://localhost:8080/login/oauth2/code/google&nonce=iDxik20BDhEDZ7xaNccu9pLZgAtsjYvZH2zGZ77UVQ0' (redirected from 'http://localhost:8080/token') from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.`** – Maifee Ul Asad Jun 01 '20 at 20:34
  • Okay, I think I know where you are facing an issue now. Google is blocking you to access this request from your localhost:3000. This URL should be open in a separate window. Otherwise, it won't work. It is better when you click on "Login with Google" button and you open separate child window and call http://localhost:8080/oauth2/authorize/google and let everythign happen in that child window. – Rajeev Jun 01 '20 at 20:57
  • It is not your app who is blocking this. It is Google, since when you request this URL from your domain localhost:3000. So during the request to google Origin was present. I hope this clarifies your concerns now. – Rajeev Jun 01 '20 at 21:02
  • Like I said when user clicks on 'Login with Google' button you need to open a separate child window and the URL of that child window should be http://localhost:8080/oauth2/authorize/google. Try this. – Rajeev Jun 01 '20 at 21:06
  • sorry to say, but that didn't worked.. again that [error](https://i.stack.imgur.com/RvN8O.png) even inside popup window – Maifee Ul Asad Jun 02 '20 at 08:30
  • 1
    Okay. Will try to replicate this at my local If I can. Meanwhile see if this helps you in any way. Complete code is there on github. https://medium.com/@mail2rajeevshukla/spring-security-5-3-oauth2-integration-with-facebook-along-with-form-based-login-767e10b02dbc – Rajeev Jun 02 '20 at 13:43
  • After adding this configuration.addAllowedHeader("*"); it works for me. My requirement is i need to allow specific urls and in my case its two this accepts only one string parameter. How do i acheive this? – Shaik Mujahid Ali Sep 03 '20 at 08:15
4

UPDATE:

CORS issue with Google Oauth2 for server side webapps

CORS issue while making an Ajax request for oauth2 access token

When you use the Authorization code grant (OAuth2 for backend apps - &response_type=code), you must redirect the browser to the /auth endpoint - you cannot use XHR for that. The user will be redirected back after authentication.

After redirecting to the /auth endpoint, user needs to see in an address bar that the page is from Google (trusted source) and Google may need to do some more redirects in order to authenticate the user and present the consent page. So using XHR is not possible.


You may use UrlBasedCorsConfigurationSource with CorsFilter as used below. Please comment or remove the other CORS configurations and try with it.

package com.learning.jhipster.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.util.Arrays;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
    securedEnabled = true,
    jsr250Enabled = true,
    prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final CorsFilter corsFilter;

    public SecurityConfig(@Lazy CorsFilter corsFilter) {
        this.corsFilter = corsFilter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .cors()
            .disable()//some stackoverflow solution(not accepted) said so
            .csrf()
            .disable()
            .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
            .authorizeRequests()
            .anyRequest()
            .authenticated()
            .and()
            .oauth2Login();
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(Arrays.asList("*"));
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("DELETE");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}
Romil Patel
  • 12,879
  • 7
  • 47
  • 76