DrTeeth
DrTeeth

Reputation: 1317

Why am I getting a blank page from keycloak-angular initialization?

I'm trying to secure a very simple angular application with Keycloak. The actual Keycloak client works fine from a backend Spring Boot integration (the actual REST API), but I'm trying to pull that out into an Angular front end. Trouble is when I add the provider into the application, all I get back is a blank page.

I'm largely following this blog post, which is the best I've found on the topic, but using my own existing Angular app.

Setup:

app.module.ts:

import { NgModule, APP_INITIALIZER } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule, Routes } from '@angular/router'
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { CookieService } from 'ngx-cookie-service';
import { KeycloakService } from "keycloak-angular";

import { WelcomeComponent } from './welcome/welcome.component';
import { AuthGuard } from './guard/auth.guard';
import { initializeKeycloak } from './init/keycloakinit.factory';

const routes: Routes = [
  { path: '', component: WelcomeComponent, canActivate: [AuthGuard]},
  { path: '**', redirectTo: '' }
]

@NgModule({
  declarations: [
    AppComponent,
    WelcomeComponent
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot(routes),
    HttpClientModule,
    FormsModule
  ],
  exports: [
    RouterModule
  ],
  providers: [
    CookieService,
    KeycloakService,
    {
      provide: APP_INITIALIZER,
      useFactory: initializeKeycloak,
      multi: true,
      deps: [KeycloakService],
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

(Note: if I take out the APP_INITIALIZER provider, the app works, it just isn't secured)

init/keycloakinit.factory.ts:

import { KeycloakService } from "keycloak-angular";

export function initializeKeycloak(keycloak: KeycloakService) {
  console.log("Initializing Keycloak Service.");
  return () =>
    keycloak.init({
      config: {
        url: 'http://auth-service' + '/auth',
        realm: 'SpringBootKeycloak',
        clientId: 'SpringBootKeycloak',
      }
    });
}

(Note: auth-service DNS lookup is handled by Docker swarm the container is running in, and also mapped via /etc/hosts if called from the host)

guard/auth.guard.ts:

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
import { KeycloakAuthGuard, KeycloakService } from 'keycloak-angular';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard extends KeycloakAuthGuard {

  constructor(
    protected readonly router: Router,
    protected readonly keycloak: KeycloakService
  ) {
    super(router, keycloak);
  }

  async isAccessAllowed(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Promise<boolean | UrlTree> {

    if (!this.authenticated) {
      await this.keycloak.login({
        redirectUri: window.location.origin + state.url,
      });
    }

    return this.authenticated;
  }
}

When I run this, I can see the app initialization code being called in the console:

Initializing Keycloak Service. keycloakinit.factory.ts:4:10

I can also see calls being made to the auth-service:

GET http://auth-service/auth/realms/SpringBootKeycloak/protocol/openid-connect/3p-cookies/step1.html

...
<!DOCTYPE html>
<html>
<body>
<script>
    document.cookie = "KEYCLOAK_3P_COOKIE_SAMESITE=supported; max-age=60; samesite=none; secure"
    document.cookie = "KEYCLOAK_3P_COOKIE=supported; max-age=60"
    window.location = "step2.html"
</script>
</body>
</html>
GET http://auth-service/auth/realms/SpringBootKeycloak/protocol/openid-connect/3p-cookies/step2.html

...
<!DOCTYPE html>
<html>
<body>
<script>
    if (document.cookie.indexOf("KEYCLOAK_3P_COOKIE") !== -1) {
        document.cookie = "KEYCLOAK_3P_COOKIE_SAMESITE=; expires=Thu, 01 Jan 1970 00:00:00 GMT; secure"
        document.cookie = "KEYCLOAK_3P_COOKIE=; expires=Thu, 01 Jan 1970 00:00:00 GMT"
        window.parent.postMessage("supported", "*")
    }
    else {
        window.parent.postMessage("unsupported", "*")
    }
</script>
</body>
</html>

But that's the end of the requests. The only real error reported on the console is around a timeout, but it happens almost immediately, and I can't find any information on it anywhere:

ERROR 
Object { error: "Timeout when waiting for 3rd party check iframe message." }

Any suggestions on what I'm missing in here?

Upvotes: 1

Views: 7324

Answers (1)

Midhun Mohan
Midhun Mohan

Reputation: 689

The following change, initOptions, worked for me. pls try like below once.


export function initializeKeycloak(
  keycloak: KeycloakService
  ) {
    return () =>
      keycloak.init({
        config: {
          url: 'http://localhost:8080' + '/auth',
          realm: 'dev',
          clientId: 'WebUI',
        },
        initOptions: {
        //   onLoad: 'login-required',
        //   checkLoginIframe: true
        }     
     });
}

properties(onLoad,checkLoginIframe) are not necessary to be provided when i checked

Upvotes: 2

Related Questions