Keycloak angular No 'Access-Control-Allow-Origin' header is present

Viewed 100191

I Have integrated keycloak with an angular app. Basically, both frontend and backend are on different server.Backend app is running on apache tomcat 8. Frontend app is running on JBoss welcome content folder.

Angular config

angular.element(document).ready(function ($http) {
    var keycloakAuth = new Keycloak('keycloak.json');
    auth.loggedIn = false;
    keycloakAuth.init({ onLoad: 'login-required' }).success(function () {
        keycloakAuth.loadUserInfo().success(function (userInfo) {
            console.log(userInfo);  
        });
        auth.loggedIn = true;
        auth.authz = keycloakAuth;
        auth.logoutUrl = keycloakAuth.authServerUrl + "/realms/app1/protocol/openid-connect/logout?redirect_uri=http://35.154.214.8/hrms-keycloak/index.html";
        module.factory('Auth', function() {
            return auth;
        });
        angular.bootstrap(document, ["themesApp"]);
    }).error(function () {
            window.location.reload();
        });

});
module.factory('authInterceptor', function($q, Auth) {
    return {
        request: function (config) {
            var deferred = $q.defer();
            if (Auth.authz.token) {
                Auth.authz.updateToken(5).success(function() {
                    config.headers = config.headers || {};
                    config.headers.Authorization = 'Bearer ' + Auth.authz.token;
                    deferred.resolve(config);
                }).error(function() {
                        deferred.reject('Failed to refresh token');
                    });
            }
            return deferred.promise;
        }
    };
});
module.config(["$httpProvider", function ($httpProvider)  {
    $httpProvider.interceptors.push('authInterceptor');
}]);

Request Header

Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:authorization
Access-Control-Request-Method:GET
Connection:keep-alive
Host:35.154.214.8:8080
Origin:http://35.154.214.8
Referer:http://35.154.214.8/accounts-keycloak/
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36

Error on web console.

XMLHttpRequest cannot load http://35.154.214.8:8080/company/loadCurrencyList. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://35.154.214.8' is therefore not allowed access.

Cors filter on backend

@Component
public class CORSFilter implements Filter {
    static Logger logger = LoggerFactory.getLogger(CORSFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");
        chain.doFilter(request, response);
    }

    public void destroy() {
    }
}
12 Answers

The solution that worked for me was setting the Web Origins URL (Of my Client, not the Realm) from for example: http://localhost:3000/ to http://localhost:3000 (Notice the lack of / at the end). This way you are not opening it to all URLS by using *.

It's important to note that setting your web origin to "*" opens a gaping security hole. It allows any script from any domain to make requests on behalf of a user, within that user's browser.

Whenever you find yourself disabling a security feature in a way like this, you need to consider why the security feature exists.

See "Web Origins" in 8.1.1 of the Keycloak docs

I had the same issue and (at least) for Keycloak Server Version 8.0.1 you can add a '+' as input of the 'Web Origins' field, which seems to be the best choice.

The '+' effect should be the same as adding (see screenshot below) 'http://localhost:4200' as 'Web Origins' entry.

This is what the 'Web Origins' field tooltip is saying:

"Allowed CORS origins. To permit all origins of "Valid Redirect URIs", add '+'. To permit all origins, add '*'." (see screenshot below)

enter image description here

I had same CORS error. New to KeyCloak. Tried setting web-origin to '*', '+' and specific urls. Nothing worked. Until I changed 'Access Type' on client setting to public. Then both options of setting web-origin to specific url and + worked. Since setting it to * is not secured, did not try.

When access type set to confidential it started giving CORS error again. I was trying Authorization Flow with PKCE (code flow).

Using version 10.0.2.

Screenshot of setting that worked:

enter image description here

It's a rather old question, but I am answering it anyway. It may help somebody. In keycloak admin page go to clients->your client. There you can see the below a field called web origins. There you enter your url and your issue will be resolved.

enter image description here

You gave the answer to your own question, adding WebOrigin as * at client-level (NOT at Realm-level!), which worked for you, but in my own case it didn't. Actually, removing the * was the trick for me, because KC sent the CORS headers twice - removing it, stripped it to one time...

Thanks to your answer, I luckily found the answer on my problems...

What we all agree on is the KC documentation is at the least very poor.

It is written for dummies, but.... we are not dummies, neither the subject is...

It does not explain technical details. For instance, what are the responses from the endpoints. Searching the web (two weeks) does give a little - but why isn't it laid out in the documentation?

One example. But I have several...

Can we help with the documentation?

I had the same problem and in my case it was caused by using an options object in keycloak js adapter creation, where the url to the auth server was falsely set to http instead of https:

const keycloak = Keycloak({
    url: 'http://my-keycloak-auth-server/auth',
    realm: 'myRealm',
    clientId: 'myClient'
});

but correct was

const keycloak = Keycloak({
    url: 'https://my-keycloak-auth-server/auth',
    realm: 'myRealm',
    clientId: 'myClient'
});

Faced this same problem working with Angular 6, Spring Boot for REST Web Services, and Keycloak.

Keycloak address: KEYCLOAK
Angular 6 App Address: ANGULAR_APP
Two REST WS secured with Keycloak and Spring Autoconfiguration: AA, BB

Flow was: Angular App request(GET) AA, AA request(GET) BB

Using XMLHttpRequest error was something like: Cannot load AA. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'ANGULAR_APP' is therefore not allowed access.

Using Observable from Angular it was: Failed to load AA: Redirect from 'BB' to 'KEYCLOAK' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'ANGULAR' is therefore not allowed access.

Tried with web origins: * to no solution

Never knew why Keycloak was doing that redirect that caused problem

Problem magically dissapeared when I switched security in service AA from Keycloak + Autoconfigure to Keycloak + Spring Security according to: https://developers.redhat.com/blog/2017/05/25/easily-secure-your-spring-boot-applications-with-keycloak/

Lost many days of sleep because of this. Just leaving this in case someone faces something similar.

I add this line on init...

this.keycloakAuth.init({ onLoad: 'login-required', flow: 'implicit' })

Fought with a similar error with keycloak-js although not in Angular: I could successfully login with the code from the documentation:

keycloak.init({
  onLoad: 'login-required',
}).then(function(authenticated) {
  alert(authenticated ? 'authenticated' : 'not authenticated');
}).catch(function() {
  alert('failed to initialize');
});

But consecutive calls (keycloak.loadUserProfile() in my case, calling the account endpoint) would end up in CORS errors.

I later found out that I'd rigged my code in a bad way so that the consecutive calls had race conditions with init! Obvious in hindsight but..

TLDR; If you call keycloak endpoints before the init call is finished, the response will lack CORS headers and you'll get a CORS error! It just means you're not authenticated.

I had a similar issue after upgrading from keycloak 12 to 15. After also upgrading the keycloak.js file, found here: https://your-keycloak-server/auth/js/keycloak.js in my web application, it started working again.

Related