Keycloak Angular 2 - Check authenticated status Keycloak object
Asked Answered
D

2

6

I'm implementing the Keycloak authentication service in my Angular 2 project. I use a service for logging in, logging out etc.

Authenticating a user and logging out seems to work. I'm now trying to protect some routes. I now have a working AuthGuard. To check if the user is logged in (in the AuthGuard), I have a isAuthenticated() method in the service. This is the service:

import { Injectable } from '@angular/core';

declare let Keycloak: any;

@Injectable()
export class KeycloakService {
  private keycloak = new Keycloak('app/keycloak/keycloak.json');

  constructor() {
    this.keycloak.init({onload: 'check-sso'});
    console.log(this.keycloak);
  }

  public login() {
    this.keycloak.login();
  }

  public logout() {
    this.keycloak.logout();
  }

  public isAuthenticated() {
    return this.keycloak.authenticated;
  }
}

Flow: User logs in, user tries to reach protected route, AuthGuard checks if user is logged in via isAuthenticated().

Note: I don't want to authenticate the user for the complete Angular app. Only for some routes.

Problem

After the user logs in, the user is redirected to the Angular app. After this, the isAuthenticated() method returns still false. Here is why:

I logged the Keycloak object to the console. I found something I didn't understand.

Keycloak object after login redirect

Keycloak object after login redirect


Same Keycloak object after login redirect (but expanded)

Same Keycloak object after login redirect (but expanded)

First the authenticated property is false. After expanding the authenticated property is true.

Question

Is the way I try to maintain my Keycloak object the correct way?

Consulted sources

And others

Dram answered 24/12, 2016 at 13:33 Comment(0)
F
5

Basing on the community provided Angular2 example in keycloak's github you can spot some differences in interacting with keycloak js adapter. Mainly the actual check on the authenticated (and possibly userName) is done on the promise returned from init.

  static init(): Promise<any> {
    let keycloakAuth: any = new Keycloak('keycloak.json');
    KeycloakService.auth.loggedIn = false;

      return new Promise((resolve, reject) => {
        keycloakAuth.init({ onLoad: 'login-required' })
          .success(() => {
            KeycloakService.auth.loggedIn = true;
            KeycloakService.auth.authz = keycloakAuth;
            KeycloakService.auth.logoutUrl = keycloakAuth.authServerUrl + "/realms/demo/protocol/openid-connect/logout?redirect_uri=/angular2-product/index.html";
            resolve();
          })
          .error(() => {
            reject();
          });
      });
}

Also the official keycloak js adapter's documentation uses promise for the authenticated check

<head>
    <script src="keycloak.js"></script>
    <script>
        var keycloak = Keycloak();
        keycloak.init().success(function(authenticated) {
            alert(authenticated ? 'authenticated' : 'not authenticated');
        }).error(function() {
            alert('failed to initialize');
        });
    </script>
</head>
Fatherinlaw answered 12/1, 2017 at 13:38 Comment(3)
Thanks for the answer. The biggest challenge right now is when a page refresh occurs, a new Keycloak object is created and my status is lost.Dram
Hi, do I understand correctly that your original question was answered? If so please accept the answer provided. As for your next challenge I would suggest a new question.Fatherinlaw
You can also check the code in github.com/atende/angular-spa with is a Angular 2 Library that integrates Keycloak and provide a more complete feature set. Disclaimer: I'm the author, you can send me feedback ;-)Heiskell
O
1
  1. If you use check-sso as a parameter to init function, the browser will be routed back to the application if the user is not logged in and will remain unauthenticated.You should use login-required instead to fix this problem.

  2. If you don't want to authenticate the user for the complete App, you should detach the logic of creating the adapter, to make things easier if you have more than one secured component. for exemple you can create a HOC.

PS : in the example below, I am using Reactjs, I hope you can find a similar way to do this in angular:

export default (WrappedComponent) => {
  return (props) => {
  const [isAutenticated, setIsAutenticated] = useState(false);
  const [keycloak, setKeycloak] = useState();

  const loadConfig = useCallback(() => {
    const keycloak = Keycloak("/keycloak.json"); //The configuration of the adapter in JSON format
    keycloak.init({ onLoad: "login-required" }).then((authenticated) => {
      setKeycloak(keycloak);
      setIsAutenticated(authenticated);
      });
  }, [Keycloak]);

  useEffect(() => {
    loadConfig();
  }, [loadConfig]);

  if (keycloak) {
    if (isAutenticated) {
      return <WrappedComponent {...props} keycloak={keycloak} />;
    } else return <AuthError message="Unable to authenticate" />;
  }
  return <Loader />;
  };
};
  1. you can find a useful source here
Overstride answered 11/7, 2020 at 15:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.