CORS issue when redirecting from Angular UI to Keycloak (Ver 23.0.5) for authentication, using a Spring Security backend

I’m currently dealing with a CORS issue in my web app setup involving an Angular UI hosted on localhost:4200, Keycloak (Ver. 23.0.5) hosted on localhost:9999, and a Spring Security backend on localhost:8080.

Here’s the problem:

  1. When an unauthenticated user on the UI attempts to access a resource on the backend, they are correctly redirected to Keycloak for authentication.

  2. However, when Keycloak responds with the login page, the browser throws a CORS error: “No ‘Access-Control-Allow-Origin’ header is present on the requested resource.”

Access to XMLHttpRequest at 'http:// 127.0.0.1:9999/realms/uaa/protocol/openid-connect/auth?response_type=code&client_id=gtw&scope=openid%20profile%20roles%20offline_access&state=6BzS-HGf2CgxbY0aQogMcs3TFDuQuBdAuUdmzz0Gagw%3D&redirect_uri=http:// localhost:4200/login/oauth2/code/keycloak&nonce=n9L8mSN3E8T0Y8dtLdrycJi39SDaJJaMVMUEj9fSTvI' (redirected from 'http:// localhost:4200/principal') from origin 'http:// localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Here is my Keycloak Client configuration:

{
  "clientId": "gtw",
  "name": "",
  "description": "",
  "rootUrl": "",
  "adminUrl": "",
  "baseUrl": "",
  "surrogateAuthRequired": false,
  "enabled": true,
  "alwaysDisplayInConsole": true,
  "clientAuthenticatorType": "client-secret",
  "redirectUris": [
    "*"
  ],
  "webOrigins": [
    "http://127.0.0.1:4200",
    "*"
  ],
  "notBefore": 0,
  "bearerOnly": false,
  "consentRequired": false,
  "standardFlowEnabled": true,
  "implicitFlowEnabled": false,
  "directAccessGrantsEnabled": true,
  "serviceAccountsEnabled": true,
  "publicClient": false,
  "frontchannelLogout": true,
  "protocol": "openid-connect",
  "attributes": {
    "client.secret.creation.time": "1706544831",
    "oauth2.device.authorization.grant.enabled": "false",
    "backchannel.logout.revoke.offline.tokens": "false",
    "use.refresh.tokens": "true",
    "oidc.ciba.grant.enabled": "false",
    "backchannel.logout.session.required": "true",
    "client_credentials.use_refresh_token": "false",
    "tls.client.certificate.bound.access.tokens": "false",
    "require.pushed.authorization.requests": "false",
    "acr.loa.map": "{}",
    "display.on.consent.screen": "false",
    "token.response.type.bearer.lower-case": "false",
    "login_theme": "",
    "frontchannel.logout.url": "",
    "backchannel.logout.url": ""
  },
  "authenticationFlowBindingOverrides": {
    "browser": "dbb28714-c0c5-400b-9141-58c651da8e53"
  },
  "fullScopeAllowed": false,
  "nodeReRegistrationTimeout": -1,
  "protocolMappers": [
    {
      "name": "Client Host",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-usersessionmodel-note-mapper",
      "consentRequired": false,
      "config": {
        "user.session.note": "clientHost",
        "introspection.token.claim": "true",
        "id.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "clientHost",
        "jsonType.label": "String"
      }
    },
    {
      "name": "Client IP Address",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-usersessionmodel-note-mapper",
      "consentRequired": false,
      "config": {
        "user.session.note": "clientAddress",
        "introspection.token.claim": "true",
        "id.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "clientAddress",
        "jsonType.label": "String"
      }
    },
    {
      "name": "Client ID",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-usersessionmodel-note-mapper",
      "consentRequired": false,
      "config": {
        "user.session.note": "client_id",
        "introspection.token.claim": "true",
        "id.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "client_id",
        "jsonType.label": "String"
      }
    }
  ],
  "defaultClientScopes": [
    "web-origins",
    "acr",
    "roles",
    "profile",
    "email"
  ],
  "optionalClientScopes": [
    "address",
    "phone",
    "offline_access",
    "microprofile-jwt"
  ],
  "access": {
    "view": true,
    "configure": true,
    "manage": true
  },
  "authorizationServicesEnabled": true
}

Here are the relevant parts of my Spring configuration

app:
  idp:
    serverUrl: http:// 127.0.0.1:9999
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: ${app.idp.serverUrl}/realms/uaa
      client:
        provider:
          keycloak:
            authorization-uri: ${app.idp.serverUrl}/realms/uaa/protocol/openid-connect/auth
            token-uri: ${app.idp.serverUrl}/realms/uaa/protocol/openid-connect/token
            user-info-uri: ${app.idp.serverUrl}/realms/uaa/protocol/openid-connect/userinfo
            jwk-set-uri: ${app.idp.serverUrl}/realms/uaa/protocol/openid-connect/certs

  • Configuring web-origins in Keycloak to accept *, http:// localhost:4200 and http:// 127.0.0.1:4200
  • Changing Keycloak access level to Confidential as well as Public
  • Upgrading to newest version of Keycloak (23.0.5)

Hello, I’m having a similar issue with an Angular SPA using the angular-oauth2-oidc module. It was working fine with Keycloak 22, but after the migration to Keycloak 23 I’m getting the CORS issue.
My client config is: Auth code + PKCE (public client)

The auth flow works fine, and the get token endpoint responses with the access_token and refresh_token but it’s blocked by the browser because the response header “Access-Control-Allow-Origin” is missing.

Auth flow: Go to http://localhost:4200 → Redirect to Keycloak login page → Go back to localhost:4200 with the auth code in the URL → Get the token response code is 200 but blocked by CORS

Testing scenarios for both Keycloak versions:

  • Angular v16 + angular-oauth2-oidc v15
  • Angular v16 + angular-oauth2-oidc v16
  • Angular v17 + angular-oauth2-oidc v17

Hope it helps to find a solution.
Best regards

I found a solution for my problem. I was using the following client configuration that causes the problem in dev environment (in production you must specify the allowed redirectUris):

redirectUris: ["*"],
"webOrigins": ["+"],

Using the + in webOrings when redirectUris is * causes the problem. If I change the webOrigins to * it works, but the good solution is:

redirectUris: ["http://localhost:4200/*"],
"webOrigins": ["+"],

Hope it helps
Best regards

Dear @kr-rruiz have you resolved your issue?

Because I’m also facing same issue …

If you help you in this

Thank you