You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security OAuth2 JWT及基础认证CORS配置问题求助

CORS + Spring Security Troubleshooting & Solutions

Hey there, I’ve battled through similar CORS and Spring Security headaches with OAuth2 and basic auth in the past, so let’s break down what’s going wrong and how to fix each case, plus cover common root causes and more secure auth options.

Case 1: Spring Boot 1.5.9 + OAuth2 + JWT (OPTIONS /oauth/token returns 401)

The key issue here is that the /oauth/token endpoint is managed by the AuthorizationServer, not the ResourceServer. Your existing CorsConfigurationSource bean is likely only applied to the ResourceServer or WebSecurity filter chain, which doesn’t cover OAuth2-specific endpoints.

Fix Steps:

  1. Add CORS config directly to the AuthorizationServer
    Override the configure(AuthorizationServerSecurityConfigurer security) method in your AuthorizationServerConfig to attach a CORS filter to the token endpoint:
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        // Allow unauthenticated OPTIONS requests to /oauth/token
        security.tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()")
                .allowFormAuthenticationForClients()
                // Attach CORS filter to the token endpoint
                .addTokenEndpointAuthenticationFilter(new CorsFilter(corsConfigurationSource()));
    }
    
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(Arrays.asList("http://your-react-app-url")); // Replace with your frontend URL
        config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        config.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type"));
        config.setAllowCredentials(true); // Critical for sending cookies/tokens with credentials
    
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/oauth/token", config);
        // Register for other OAuth endpoints if needed (e.g., /oauth/authorize)
        return source;
    }
    
  2. Keep ResourceServer CORS setup
    Don’t forget to maintain your ResourceServerConfig CORS configuration for API endpoints, so other protected resources work correctly with cross-origin requests.
  3. Enforce filter order
    In Spring Boot 1.5.x, ensure the CorsFilter runs before Spring Security filters by setting its order explicitly:
    @Bean
    public FilterRegistrationBean corsFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(new CorsFilter(corsConfigurationSource()));
        registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return registrationBean;
    }
    

Case 2: Spring Boot 2.0.0 M7 + Spring Security 5 Basic Auth (Redirect to login after successful auth)

This happens because Spring Security’s default behavior for unauthenticated/expired sessions is to redirect to the login page—but your React app expects a JSON response, not a redirect. The OPTIONS request works because you probably allowed it, but the core issue is handling auth failures properly for API clients.

Fix Steps:

  1. Disable redirects and return JSON responses
    Update your SecurityConfig to override exception handlers and auth success/failure handlers to return JSON instead of redirects:
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                // Handle login success with JSON
                .successHandler((request, response, authentication) -> {
                    response.setContentType("application/json");
                    response.getWriter().write("{\"status\": \"success\", \"message\": \"Authenticated\"}");
                })
                // Handle login failure with JSON
                .failureHandler((request, response, exception) -> {
                    response.setContentType("application/json");
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    response.getWriter().write("{\"status\": \"error\", \"message\": \"" + exception.getMessage() + "\"}");
                })
                .and()
                .logout()
                // Handle logout success with JSON
                .logoutSuccessHandler((request, response, authentication) -> {
                    response.setContentType("application/json");
                    response.getWriter().write("{\"status\": \"success\", \"message\": \"Logged out\"}");
                })
                .and()
                .exceptionHandling()
                // Return 401 JSON instead of redirecting to login
                .authenticationEntryPoint((request, response, authException) -> {
                    response.setContentType("application/json");
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    response.getWriter().write("{\"status\": \"error\", \"message\": \"Unauthorized\"}");
                });
    }
    
  2. Enable credentials in CORS
    Ensure your CORS configuration allows credentials (allowCredentials(true)), and your React app sends requests with withCredentials: true (critical for session-based auth across domains).

Common Root Causes for Both Cases

Both issues boil down to misalignment between Spring Security’s filter chain and CORS/API-specific requirements:

  • Filter Priority: CORS filters need to run before Spring Security filters to handle OPTIONS requests before they get blocked by auth checks.
  • Endpoint-Specific Configuration: Special endpoints (like /oauth/token or auth endpoints) aren’t covered by generic CORS/security rules—you need to explicitly configure them.
  • Default Behavior Misalignment: Spring Security’s default redirect behavior is built for server-rendered apps, not SPAs that expect JSON responses.

More Secure Authentication Options for SPAs

For React and other single-page apps, these are the most secure approaches:

  1. OAuth2 Authorization Code Flow with PKCE: The industry standard for SPAs. It eliminates the need to store a client secret (impossible in browser-based apps) and uses PKCE to prevent authorization code interception.
  2. JWT + Refresh Token: If you prefer a custom solution, use short-lived JWT access tokens paired with long-lived refresh tokens. Store refresh tokens in HttpOnly, Secure cookies to prevent XSS attacks, and use strong signing algorithms like RS256 for JWTs.
  3. OpenID Connect: Build on OAuth2 to add identity management features (like user profile retrieval). Spring Security has excellent support for integrating with OIDC providers (e.g., Auth0, Okta, or your own Spring Authorization Server).

Avoid using basic auth or session-based auth directly in SPAs—they’re more vulnerable to CSRF and XSS attacks if not configured carefully.

内容的提问来源于stack exchange,提问作者patjd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:52:15