Search code examples
angularsecuritykeycloak

How to avoid "timeout when waiting for 3rd party check iframe message" with Keycloak and Angular


I'm trying to securize an Angular app with a Keycloak server. I've followed some tutorials that give more or less the same instructions in order to do so, but I got stuck with the following error:

Timeout when waiting for 3rd party check iframe message.

I start my keycloak server using the following docker-compose configuration:

auth:
  container_name: nerthus-tech-auth
  image: quay.io/keycloak/keycloak:17.0.1
  command: start-dev
  environment:
    KEYCLOAK_ADMIN: admin
    KEYCLOAK_ADMIN_PASSWORD: admin
    KC_DB: postgres
    KC_DB_URL: jdbc:postgresql://database:5432/keycloak
    KC_DB_USERNAME: keycloak
    KC_DB_PASSWORD: str0ngP@ssword
  ports:
    - 10010:8080

I've created a realm (nerthus) and a client (blog) which is public and has the following configuration:

  • Root URL: http://localhost:4200
  • Valid redirect URLs: http://localhost:4200/* (which in my understanding I should be able to abbreviate as *)
  • Web origins: +

On the Angular app side, I've installed the keycloak-angular and keycloak-js dependencies:

"keycloak-angular": "^9.1.0",
"keycloak-js": "^16.1.1"

I've also registered an initializer for Keycloak:

providers: [
  {
    provide: APP_INITIALIZER,
    useFactory: initializeKeycloak,
    multi: true,
    deps: [KeycloakService]
  }
]
function initializeKeycloak(keycloakService: KeycloakService) {
  return () => keycloakService.init({
                                      config: {
                                        url: 'http://localhost:10010',
                                        realm: 'nerthus',
                                        clientId: 'blog'
                                      }
                                    });
}

For that one I also tried to use initOptions.onLoad (with "login-required" and "check-sso"), but that causes the app to require authentication to access any page, which is not the intended behaviour.

I want only the guarded page to require authentication. Hence the guard I set up:

@Injectable({
  providedIn: 'root'
})
export class AuthGuard extends KeycloakAuthGuard {
  constructor(protected override readonly router: Router,
              protected override readonly keycloakAngular: KeycloakService) {
    super(router, keycloakAngular);
  }

  async isAccessAllowed(route: ActivatedRouteSnapshot,
                        state: RouterStateSnapshot): Promise<boolean | UrlTree> {
    if (!this.authenticated) {
      await this.keycloakAngular.login({ redirectUri: window.location.origin + state.url });
    }

    return this.authenticated;
  }
}

Surely I'm missing something, but I can't make it work. I tried to be succinct, so if some important information is missing, please ask me.


Solution

  • My solution is set the checkLoginIframe to false. Below is my configuration:

     keycloak.init({
      config: {
          url: 'http://localhost:10010',
          realm: 'nerthus',
          clientId: 'blog'
      },
      initOptions: {
        
        pkceMethod: 'S256', 
        // must match to the configured value in keycloak
        redirectUri: 'http://localhost:4200/your_url',   
        // this will solved the error 
        checkLoginIframe: false
      }});
    

    Hopes it will helps. =)