mauriciovigolo / keycloak-angular

Easy Keycloak setup for Angular applications.
MIT License
725 stars 278 forks source link

Loop after keycloak redirect to angular website #524

Closed DeltaFox0018 closed 10 months ago

DeltaFox0018 commented 10 months ago

Bug Report

- [x] bug report
- [ ] feature request

Versions.

Angular core : 16.2.11 Keycloak-angular: 14.1.0 Keycloak-js: 22.0.5 Keycloak: 22.0.5

Repro steps.

This is the function that inizialize keycloak

function initializeKeycloak(keycloak: KeycloakService) {
  return async () => {
    keycloak.init({
      config: {
        url: environment.keycloakUrl,
        realm: environment.keycloakRealm,
        clientId: environment.keyclokaID
      },
      initOptions: {
        onLoad: 'check-sso'
      }
    });
  }
}

{
      provide: APP_INITIALIZER,
      useFactory: initializeKeycloak,
      multi: true,
      deps: [KeycloakService]
    }

When i click on login button i run this cose that open keycloak

 this.keycloakService.login({ redirectUri: window.location.origin + '/' + this.currentLang + '/mycollection', locale: this.currentLang });

After logging in to keycloak a redirect to the angular site is performed and an almost infinite redirect between keycloak and angular begins

After logging in to keycloak a redirect to the angular site is performed and an almost infinite redirect between keycloak and angular begins

Without async in the initializeKeycloak function I don't have this problem

How can I solve it?

DeltaFox0018 commented 10 months ago

``Investigating, I found that the problem is the AuthGuard that when it runs the control

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

returns false even though the user is logged in correctly

Complete AuthGuard Code

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

@Injectable()
export class AuthGuard extends KeycloakAuthGuard {
  constructor(
    protected override router: Router,
    protected keycloakService: KeycloakService
  ) {
    super(router, keycloakService);
  }

  isAccessAllowed(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Promise<boolean> {
    return new Promise((resolve, reject) => {
      let permission;
      if (!this.authenticated) {
        this.keycloakService.login().catch((e) => console.error(e));
        return reject(new Error('Not Authenticated'));
      }

      const requiredRoles: string[] = route.data['roles'];
      if (!requiredRoles || requiredRoles.length === 0) {
        permission = true;
      } else {
        if (requiredRoles.every((role) => this.roles.indexOf(role) > -1)) {
          permission = true;
        } else {
          permission = false;
        };
      }
      if (!permission) {
        this.router.navigate(['/']);
      }
      resolve(permission)
    });
  }
}

Analyzing the Cookies in the keycloak IP/DNS I see some data saved but shortly afterwards it is removed

cre8 commented 10 months ago

@DeltaFox0018 have you found a fix? I am stuck with the same error

DeltaFox0018 commented 10 months ago

Hi @cre8

I didn't put await in keycloak.init

my code

function initializeKeycloak(keycloak: KeycloakService) {
  return async () => {
    await keycloak.init({
      config: {
        url: environment.keycloakUrl,
        realm: environment.keycloakRealm,
        clientId: environment.keyclokaID
      },
      initOptions: {
        onLoad: 'check-sso'
      }
    });
  }
}
cre8 commented 10 months ago

Still failling for me when the user loads the webpage and the first route is protected with the authguard

cre8 commented 10 months ago

In my case the auth gaurd function is triggered before the init method is passed. That's strange because I thought all init methods need to be passed before the any canActivate route can be triggered

cre8 commented 10 months ago

Okay, found my error. I had blocking enabled in my router like:

RouterModule.forRoot(appRoutes, {
      initialNavigation: 'enabledBlocking',
    }),

From the docs: When set toenabledorenabledBlocking`, the initial navigation starts before the root