Configuring CORS with Your Keycloak OIDC Client
Last updated: March 2026
Browser-based applications that authenticate with Keycloak must make cross-origin HTTP requests. Your JavaScript SPA runs on https://myapp.com, but Keycloak lives at https://auth.example.com. Without proper CORS configuration, the browser blocks every token request, userinfo call, and logout redirect before your users ever see a login screen.
CORS (Cross-Origin Resource Sharing) is the browser mechanism that controls which origins can make requests to a different domain. Keycloak has built-in CORS support, but it only works when you configure it correctly in the client settings. Misconfigured CORS is one of the most common issues developers encounter when integrating Keycloak with frontend applications.
This guide covers how Keycloak handles CORS, how to configure it properly, how to diagnose and fix common errors, and what security practices to follow in production.
Why CORS Matters for Keycloak
When a browser-based application authenticates with Keycloak using OpenID Connect, several cross-origin requests happen behind the scenes:
- Token exchange: After the authorization code redirect, your app sends a POST request to Keycloak’s token endpoint to exchange the code for tokens.
- Token refresh: When the access token expires, your app sends a refresh request to the token endpoint.
- UserInfo calls: Your app may call the
/userinfoendpoint to fetch profile data. - Logout: End-session requests hit Keycloak’s logout endpoint.
- JWKS retrieval: Token validation libraries fetch Keycloak’s public keys from the
/certsendpoint.
Every one of these requests crosses an origin boundary. If Keycloak does not include the correct Access-Control-Allow-Origin header in its responses, the browser rejects them. Your application gets opaque network errors, and your users cannot log in.
This is not a bug. It is the browser enforcing the same-origin policy. The fix is telling Keycloak which origins are allowed to make these requests.
How Keycloak Handles CORS
Keycloak manages CORS at the client level through a setting called Web Origins. Each OIDC client in Keycloak has a Web Origins field that defines which origins are permitted to make cross-origin requests to Keycloak endpoints on behalf of that client.
When Keycloak receives a cross-origin request, it checks the Origin header against the Web Origins configured for the client associated with the request. If the origin matches, Keycloak includes the appropriate CORS headers in the response:
Access-Control-Allow-Origin: https://myapp.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
If the origin does not match any entry in Web Origins, Keycloak omits these headers and the browser blocks the response.
The key point: CORS configuration in Keycloak is per-client, not global. Each client that serves browser-based applications needs its own Web Origins configured.
Configuring Web Origins in the Keycloak Admin Console
To configure Web Origins for an OIDC client:
- Open the Keycloak Admin Console and navigate to your realm.
- Go to Clients and select the client you want to configure.
- Scroll down to the Web Origins field in the client settings.
Option 1: Exact Origins (Recommended)
Specify the exact origins that your application runs on:
https://myapp.com
https://staging.myapp.com
Each entry is a full origin (scheme + host + port). Do not include paths, trailing slashes, or wildcards within the origin. These are correct:
https://myapp.com
http://localhost:3000
https://app.example.com:8443
These are incorrect:
https://myapp.com/ # trailing slash
https://myapp.com/app # includes path
https://*.myapp.com # subdomain wildcard (not supported in Web Origins)
Option 2: The + Shortcut
Keycloak supports a special + value in Web Origins that automatically derives allowed origins from the client’s Valid Redirect URIs. If your redirect URIs are:
https://myapp.com/*
https://staging.myapp.com/*
Then setting Web Origins to + is equivalent to adding:
https://myapp.com
https://staging.myapp.com
This is convenient because it keeps your CORS configuration in sync with your redirect URIs. When you add a new redirect URI, the corresponding origin is automatically allowed.
For most setups, + is the best choice. It reduces duplication and avoids the common mistake of updating redirect URIs but forgetting to update Web Origins.
Option 3: Wildcard * (Development Only)
Setting Web Origins to * allows any origin to make cross-origin requests to Keycloak for this client.
*
This is acceptable for local development and testing. It is not acceptable for production. A wildcard origin means any website on the internet can make authenticated requests to your Keycloak instance on behalf of this client. This opens the door to token theft via cross-site request attacks.
Common CORS Errors and Fixes
Error: “Access-Control-Allow-Origin” Header Missing
What you see in the browser console:
Access to XMLHttpRequest at 'https://auth.example.com/realms/myrealm/protocol/openid-connect/token'
from origin 'https://myapp.com' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Cause: The origin https://myapp.com is not listed in the client’s Web Origins setting.
Fix:
- Open the Keycloak Admin Console.
- Navigate to the client.
- Add
https://myapp.comto Web Origins, or set Web Origins to+if the origin is already covered by your redirect URIs. - Save the client.
No restart is required. Keycloak picks up the change immediately.
Error: Preflight Request Fails
What you see:
Access to XMLHttpRequest at 'https://auth.example.com/...' from origin 'https://myapp.com'
has been blocked by CORS policy: Response to preflight request doesn't pass access control check.
Cause: The browser sends an OPTIONS preflight request before the actual request. This happens when the request includes custom headers (like Authorization) or uses methods other than GET/POST with simple content types.
Possible fixes:
- Verify Web Origins are configured correctly (same as above).
- Check if a reverse proxy or API gateway in front of Keycloak is stripping or overriding CORS headers. If you run Keycloak behind Nginx, Apache, or a cloud load balancer, make sure the proxy is not adding its own CORS headers that conflict with Keycloak’s.
- If using a reverse proxy, ensure it passes
OPTIONSrequests through to Keycloak rather than returning its own response.
A common proxy misconfiguration:
# WRONG: This conflicts with Keycloak's CORS headers
location /auth/ {
add_header Access-Control-Allow-Origin *;
proxy_pass http://keycloak:8080/;
}
# CORRECT: Let Keycloak handle CORS headers
location /auth/ {
proxy_pass http://keycloak:8080/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Error: Token Endpoint Returns CORS Error After Successful Login
What you see: The browser redirects to Keycloak, the user logs in successfully, and the browser redirects back to your app with an authorization code. But the token exchange POST request fails with a CORS error.
Cause: This is almost always a Web Origins misconfiguration. The authorization redirect works because it is a full-page navigation (not subject to CORS), but the token exchange is an XHR/fetch request from your app’s origin.
Fix: Confirm that the origin of your application (not the redirect URI, but the origin) is in Web Origins. If your redirect URI is https://myapp.com/callback, the Web Origin must be https://myapp.com.
Error: CORS Works in Development but Fails in Production
Cause: Your local development origin (e.g., http://localhost:3000) is in Web Origins, but the production origin (e.g., https://myapp.com) is not.
Fix: Add all environment-specific origins to Web Origins, or use the + shortcut and ensure all environment redirect URIs are in the Valid Redirect URIs field.
CORS with Different Client Types
Public Clients (SPAs)
Single-page applications are the primary use case for CORS configuration in Keycloak. Public clients use the authorization code flow with PKCE, and they make cross-origin requests directly from the browser.
For public clients:
- Client authentication: Off
- Valid Redirect URIs: Your app URLs (e.g.,
https://myapp.com/*) - Web Origins:
+or explicit origins
If you are building a JavaScript or React application, the keycloak-js adapter handles the OIDC flow for you. But the adapter cannot bypass CORS restrictions. Web Origins must still be configured on the Keycloak side.
For a deeper look at how the PKCE flow works with browser-based clients, see the Skycloak documentation.
Confidential Clients (Backend Services)
Server-side applications (Node.js backends, Java services, etc.) do not need CORS configuration in Keycloak. These applications make server-to-server HTTP requests that are not subject to browser CORS policies.
For confidential clients:
- Client authentication: On
- Web Origins: Leave empty (or remove all entries)
If your architecture has a frontend SPA and a backend API, only the frontend client needs Web Origins configured. The backend client communicates with Keycloak server-to-server without CORS constraints.
Hybrid Architectures
Some architectures use a Backend-for-Frontend (BFF) pattern where the browser talks to your backend, and your backend talks to Keycloak. In this case, CORS is between your frontend and your backend, not between your frontend and Keycloak. Keycloak Web Origins are not relevant here; configure CORS on your backend server instead.
Testing CORS Configuration
Using Browser DevTools
The fastest way to test CORS is to open your application in the browser and watch the Network tab in DevTools.
- Open DevTools (F12 or Cmd+Option+I).
- Go to the Network tab.
- Trigger a login flow in your application.
- Look for requests to your Keycloak domain.
- Click on the token endpoint request and check the response headers.
You should see:
Access-Control-Allow-Origin: https://myapp.com
Access-Control-Allow-Credentials: true
If these headers are missing, your Web Origins are not configured correctly.
Using curl to Test Preflight
You can simulate a CORS preflight request with curl:
curl -v -X OPTIONS
-H "Origin: https://myapp.com"
-H "Access-Control-Request-Method: POST"
-H "Access-Control-Request-Headers: Content-Type"
"https://auth.example.com/realms/myrealm/protocol/openid-connect/token"
A successful response includes:
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: https://myapp.com
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Methods: POST, OPTIONS
< Access-Control-Allow-Headers: Authorization, Content-Type
If the response is missing these headers, the origin is not in the client’s Web Origins.
You can also test with an origin that should be rejected:
curl -v -X OPTIONS
-H "Origin: https://evil-site.com"
-H "Access-Control-Request-Method: POST"
"https://auth.example.com/realms/myrealm/protocol/openid-connect/token"
The response should not include Access-Control-Allow-Origin: https://evil-site.com.
Verifying Tokens
After confirming CORS is working and your application can obtain tokens, use the JWT Token Analyzer to inspect the access token and verify it contains the expected claims, audience, and scopes.
Security Best Practices
Never Use * in Production
The wildcard * allows any origin to make cross-origin requests. In a production environment, this means a malicious website could potentially interact with your Keycloak endpoints if it can trick a user into visiting it while they have an active session.
Always use explicit origins or the + shortcut in production.
Keep Web Origins Minimal
Only include origins that genuinely need cross-origin access. If your app runs on https://myapp.com and https://admin.myapp.com, add only those two. Do not add origins “just in case.”
Audit Origins Regularly
As environments change, old origins accumulate. Review your Web Origins periodically and remove entries for decommissioned staging environments, old domain names, or development URLs that should not be in production clients.
Separate Clients Per Environment
Use different Keycloak clients for development, staging, and production. This way, development origins like http://localhost:3000 never appear in your production client’s Web Origins.
Use HTTPS in Production
Always use HTTPS origins in production. Keycloak will accept http:// origins in Web Origins, but serving authentication flows over plain HTTP exposes tokens to network interception.
Validate Redirect URIs Tightly
Since the + shortcut derives Web Origins from redirect URIs, keep your redirect URIs as specific as possible. Avoid overly broad patterns like https://myapp.com/* when https://myapp.com/callback is sufficient.
Troubleshooting Checklist
When you hit a CORS error with Keycloak, work through this checklist:
| Step | Check | Action |
|---|---|---|
| 1 | Is the origin in Web Origins? | Add the exact origin or use + |
| 2 | Is the origin format correct? | No trailing slash, no path, include port if non-standard |
| 3 | Are you using the correct client? | Verify the client_id in your app matches the client you configured |
| 4 | Is a reverse proxy interfering? | Check that the proxy passes CORS headers from Keycloak unchanged |
| 5 | Is the proxy adding its own CORS headers? | Remove duplicate CORS headers from the proxy config |
| 6 | Did you save the client settings? | Keycloak applies changes immediately, but only after you save |
| 7 | Is caching involved? | Clear browser cache and retry, or test in an incognito window |
| 8 | Are preflight requests reaching Keycloak? | Check Keycloak server logs for incoming OPTIONS requests |
| 9 | Is the Keycloak URL correct? | Verify the hostname, port, and realm name in your app config |
| 10 | Is the client type correct? | Public clients for SPAs, confidential for backends |
Wrapping Up
CORS configuration in Keycloak comes down to one setting: Web Origins on the client. For most browser-based applications, setting Web Origins to + and keeping your Valid Redirect URIs accurate is the simplest and most maintainable approach. For production, always use explicit origins, never wildcards.
If you are building a new application with Keycloak and want to skip the infrastructure management, Skycloak provides managed Keycloak instances with CORS, SSL, and networking configured out of the box. You can focus on your application while Skycloak handles the identity platform.
Ready to simplify your authentication?
Deploy production-ready Keycloak in minutes. Unlimited users, flat pricing, no SSO tax.