I’m working on an ionic-angular (Angular 17 and Ionic/Angular 7) app with standalone components and like to integrate with Keycloak (keycloak-angular 15.0.0 and keycloak-js 22.0.5). I’ve done a few working applications with Angular and Keycloak before but all based on NgModule. I have an AccountService that handles all the Keycloak interactions and an AuthGuard to protect access to certain components. Both are referring to the KeycloakService and it seems like it gets initialized twice.

Here’s the relevant code pieces. The app should support multiple tenants so I have to re-initialize Keycloak with the required realm upon login.

main.ts

  const providers = [
    provideIonicAngular(),
    {
      provide: RouteReuseStrategy,
      useClass: IonicRouteStrategy
    },
    provideRouter(routes),
    provideHttpClient(),
    KeycloakService,
    Storage,
  ];

  const app = await bootstrapApplication(AppComponent, {
    providers: providers,
  });

  try {
    await initKeycloak(app.injector.get(KeycloakService), environment.realm);
  } catch (error: any) {
    console.error(error);
  }

account.service.ts

  constructor(
    private readonly keycloakService: KeycloakService, ...) {}

  ...
  login(email: string, realm: string): void {
    const loginOptions: KeycloakLoginOptions = {
      loginHint: email,
      redirectUri: window.location.origin + '/tabs',
    };
    this.onInitKeycloak(realm);
    this.keycloakService.login(loginOptions).then(() => this.afterInitKeycloak());
  }
  ...

export function initKeycloak(keycloakService: KeycloakService, realm: string) {
  return keycloakService.init({
    config: {
      url: environment!.authUrl,
      realm: window.localStorage.getItem(SessionStateService.tenantKey) || realm,
      clientId: environment!.clientId
    },
    initOptions: {
      enableLogging: !environment!.production,
      onLoad: 'check-sso',
      silentCheckSsoRedirectUri: `${window.location.origin}/assets/silent-check-sso.html`,
    },
    enableBearerInterceptor: true,
    bearerExcludedUrls: ['/assets', '/styles', '/api'],
    loadUserProfileAtStartUp: true,
    shouldAddToken: (request: any) => true
  });
}

auth.guard.ts

  constructor(
    protected override readonly router: Router,
    protected readonly keycloakService: KeycloakService
  ) {
    super(router, keycloakService);
  }
  ...
  public async isAccessAllowed(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Promise<boolean> {
    if (!this.authenticated) {
      this.router.navigateByUrl('/login').then();
    }
    return this.authenticated;

The login itself seems to work but then the redirect to the requested (protected) component does not work because AuthGuard.isAccessAllowed returns false. Could it be that the KeycloakService injected in AuthGuard is not the same instance as in AccountService?

I have checked other questions like here and here without success so far. I have even tried to switch back to the NgModule approach but then I have a different issue that <app-root> remains empty and AppComponent does not render. Any hints appreciated, it’s driving me nuts.