mauriciovigolo / keycloak-angular

Easy Keycloak setup for Angular applications.
MIT License
730 stars 280 forks source link

Loop after keycloak redirect to angular website #524

Closed DeltaFox0018 closed 1 year ago

DeltaFox0018 commented 1 year 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 1 year 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 1 year ago

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

DeltaFox0018 commented 1 year 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 1 year ago

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

cre8 commented 1 year 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 1 year 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