Reputation: 1317
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
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