React调用Keycloak获取AccessToken时的CORS跨域问题求助
Let me break down the issues here and walk you through the fixes, since I’ve dealt with this exact scenario a few times:
First, the Obvious Mismatch in Your Code
Looking at your React code, you’re using client_id: 'admin-cli', but you mentioned you configured the demo client’s Web Origins. That’s a critical mistake! Keycloak applies CORS rules per client, so if you’re using admin-cli in your request, you need to set up Web Origins for the admin-cli client, not the demo one.
Why Password Grant Type Is a Bad Fit for React
The password grant type you’re using is designed for server-side applications, not frontend SPAs (like React). Exposing usernames and passwords directly in your frontend code is a huge security risk, and Keycloak’s default settings often restrict this grant type for public/frontend clients, which can contribute to CORS issues.
Fixes If You Insist on Using Password Grant (Not Recommended)
If you have to stick with this approach for now, here’s what you need to adjust:
Fix the Client Configuration
- Go to your Keycloak admin console, find the
admin-cliclient (or switch your code to use thedemoclient instead) - Set its Access Type to
public(since frontend apps can’t keep client secrets safe) - Update the Web Origins to
http://localhost:3000(or+to allow all origins matching your valid redirect URIs) - Make sure Direct Access Grants Enabled is turned on for the client (this is required for password grant)
- Go to your Keycloak admin console, find the
Fix Your Axios Request Format
Your request setsContent-Type: application/x-www-form-urlencoded, but you’re passing a JSON object. Keycloak expects form-encoded data here, so you need to wrap your data inURLSearchParams:useEffect(() => { const fetchKeycloakUser = async () => { setIsKeycloakUserError(false) try { const URL = 'http://localhost:8080/auth/realms/demo/protocol/openid-connect/token' // Wrap data in URLSearchParams for form-encoded format const data = new URLSearchParams(); data.append('username', 'admin'); data.append('password', 'admin'); data.append('client_id', 'demo'); // Use your actual demo client here data.append('grant_type', 'password'); const result = await axios({ method: 'POST', url: URL, data: data, headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, withCredentials: false, }) console.log(result) } catch (error) { console.log(error) setIsKeycloakUserError(true) } } fetchKeycloakUser() }, [])
The Secure, Recommended Approach: Authorization Code Flow with PKCE
For frontend SPAs, the Authorization Code Flow with PKCE is the industry standard—it’s secure, avoids exposing credentials, and plays nicely with Keycloak’s CORS rules. Here’s how to implement it without the official Keycloak adapter:
Configure Your Demo Client
- Set Access Type to
public - Add
http://localhost:3000/*to Valid Redirect URIs - Set Web Origins to
http://localhost:3000or+ - Ensure Authorization Code Flow Enabled is checked
- Set Access Type to
Implement PKCE in React
You’ll need to:- Generate a
code_verifierandcode_challenge(cryptographically random strings) - Redirect the user to Keycloak’s authorization endpoint with the
code_challenge - After the user logs in, Keycloak will redirect back to your React app with an authorization code
- Exchange that code (along with the
code_verifier) for an access token via a POST request to the token endpoint
- Generate a
This flow avoids CORS issues because the initial authentication is a browser redirect, not an AJAX request. The token exchange request will work because Keycloak recognizes the origin from your client’s Web Origins configuration.
内容的提问来源于stack exchange,提问作者nimsrules

