42

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() {
    }
}
boycod3
  • 5,033
  • 11
  • 58
  • 87

15 Answers15

57

I was fighting with KeyCloak and CORS and all of this for about two weeks, and this is my solution (for keycloak 3.2.1):

Its all about configuring KeyCloak server. It seems to be, that WebOrigin of your Realm needs to be

*
Only one origin "*".

Thats all, what was needed for me.

If you enter your server as WebOrigin, the trouble begins. When you call keycloak.init in JavaScript, keycloak does not generate CORS headers, so you have to configure them manually, and as soon as you do so, and call keycloak.getUserInfo after successful init - you get double CORS headers, which is not allowed.

Somewhere deep inside of keycloak mailing lists is stated, that you need to set enable-cors=true in your keycloak.json, but there is nothing about that on keycloak.gitbooks.io. So it seems not to be true.

They also don't mention CORS when describing JavaScript and Node.Js adapters, and I don't know why, seems not to be important at all.

It also seems to be, that you should not touch WildFly configuration to provide CORS headers.

Besides, CORS in OIDC is a special KeyCloak feature (and not a bug).

Hopefully this answer serves you well.

subrob sugrobych
  • 1,034
  • 8
  • 12
  • `enable-cors`is described and explained on the Keycloak's documentation in the Java adapters section. – Sébastien Blanc Sep 22 '17 at 12:13
  • 28
    Doing this in production is awful and goes against the reason for using keycloak in the first place (eg security) – Phil Aug 03 '18 at 12:12
  • 2
    "enable-cors is described and explained on the Keycloak's documentation in the Java adapters section" over 2 years of intermittent experimentation I am still unable to determine with any certainty whether "enable-cors" does anything at all. One thing it has definitely never done anywhere I have tried it: enable CORS headers. – tekHedd Dec 19 '18 at 00:34
  • 5
    Its such a pain – DJ MERKEL Mar 30 '20 at 14:57
  • 4
    I am using Keycloak 10.0.1 I added a + for the client Web Origins and it worked in my Angular 9.1 app. – Richard K. Campion May 21 '20 at 01:44
  • Thanks! You saved me. – Rajat Aug 17 '21 at 10:45
  • 7
    Wow the accepted answer opens up a security loophole. This is really bad as anyone who implements this will just be an open door for hackers. Hope no one ever does this in production. – Namphibian Dec 20 '21 at 03:22
  • 1
    that's like stopping your house from burning down by blowing it up with a nuke... unbelievable this has so many upvotes – Krusty the Clown Sep 07 '22 at 20:23
  • What I didn't understood was: In a OpenID, SSO environment, I WILL call keycloak from another domain. So.. enabling CORS will block my app from www.domain1.com to ask login flow from www.mykeycloakdomain.com .... This is what I have now. My Angular app facing CORS block because my keycloak is at another host.... – Magno C Jul 26 '23 at 12:12
36

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 *.

Juan Espinosa
  • 369
  • 3
  • 4
  • 1
    I had the same issue with a non localhost web origin and removing the trailing slash also worked for me. Thanks – Franck LEVEQUE Aug 07 '20 at 09:34
  • This solution also worked for me. It should be the accepted answer. – Micah Parks Mar 04 '21 at 02:42
  • Yes, even with 15.0.2, this worked for me, the slashes being very important :| `Valid Redirect URIs: http://localhost:9700/*` `Base URL: http://localhost:9700` `Web Origins: http://localhost:9700` – Narayana Sep 17 '21 at 12:41
30

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

Daniel Rose
  • 17,233
  • 9
  • 65
  • 88
GuyPaddock
  • 2,233
  • 2
  • 23
  • 27
  • 6
    I tried setting the url and even tried *. I still get the same error. Any idea? I am accessing my backend endpoint(secured by keycloak) using ajax – pvpkiran Feb 24 '20 at 10:26
  • 1
    Don't be afraid. God will protect your server. – Magno C Jul 26 '23 at 12:14
23

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

Nils Heumer
  • 289
  • 2
  • 7
  • 2023 August I am using keycloak-21.1.1 , I am using client authentication on, flows "standard". "direct access", "implicit". I earlier tried with Web Origins + didn't work for me, Later I used * (asterisk ) , The CORS issue solved – Seyon Seyon Aug 17 '23 at 07:53
15

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

meDev
  • 877
  • 1
  • 9
  • 17
  • 3
    did you resolve the confidential access type issue? I have the same problem but I don't want to use the public access type. could this be related to the samesite cookie policies? – fjahan May 02 '21 at 09:05
9

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

kaushik
  • 2,308
  • 6
  • 35
  • 50
4

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?

Dutchboy
  • 181
  • 4
  • 7
    Sure you can help, it's all Open Source, send your pull requests to https://github.com/keycloak/keycloak-documentation , we will be mmore than happy to review it. – Sébastien Blanc Sep 22 '17 at 12:11
  • 1
    completely agree with @SébastienBlanc, complaining about something doesn't make it better. – stevenferrer Jul 22 '18 at 04:26
4

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'
});
2

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.

Galo
  • 31
  • 3
1

I add this line on init...

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

1

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.

oskarth
  • 927
  • 2
  • 9
  • 18
  • I'm having this same exact problem: login and logout work perfectly, but I get CORS errors when requesting the account (I just want to display the username). I tried calling `loadUserProfile()` later, but I still keep getting CORS errors. I tried everything, adding * or + to web origins, nothing is working. – Aron Fiechter Jan 14 '22 at 14:55
1

I got this working by changing the header setting from

add_header Referrer-Policy "no-referrer";

to

add_header Referrer-Policy "same-origin";

CORS blocking issue then dissappeared in my case. Make sure your not running a cached vers of the application to verify the results. Try same url with incognito mode in the browser.

user7023213
  • 3,460
  • 2
  • 11
  • 15
0

Seems people have different answers depending what version of Keycloak they are using and what oidc library to connect to it in their Angular app. I am using Keycloak 21.1.2 and Angular 16. I am using the angular-auth-oidc-client to connect to keycloak.

This is my keycloak client's Access Settings:

enter image description here

This is my auth module in Angular where I setup the oidc library settings to connect to keycloak:

enter image description here

It didn't work for ages because I didn't add the authWellknownEndpointUrl config setting. Worked after I added that.

Alan Smith
  • 1,069
  • 4
  • 19
  • 23
0

I fixed it when I faced a similar issue by sending POST data as x-www-form-urlencoded

import { HttpClient, HttpHeaders, HttpParams } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";
import { environment } from "src/environments/environment";

@Injectable({
  providedIn: "root",
})
export class KeycloakHttpService {
  constructor(private http: HttpClient) {}

  signIn(username: string, password: string): Observable<any> {
    const url = `${environment.KEYCLOAK_BASE_URL}/realms/realmename/protocol/openid-connect/token`;

    // Convert the form data to URL-encoded format
    const formData = new HttpParams()
      .set("client_id", "frontend")
      .set("username", username)
      .set("password", password)
      .set("grant_type", "password");

    // Set the headers for x-www-form-urlencoded
    const headers = new HttpHeaders({
      "Content-Type": "application/x-www-form-urlencoded",
    });

    // Send the POST request with the data
    return this.http.post<any>(url, formData.toString(), { headers });
  }
}
-1

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.

Maudrid
  • 127
  • 1
  • 8