Keycloak-angular: No way to get logged user when application starts up.

Created on 18 Nov 2018  路  10Comments  路  Source: mauriciovigolo/keycloak-angular

- [x] bug report -> please search for issues before submitting
- [ ] feature request

Versions.

keycloak-angular: 4.0.2
angular: 7.0.0

Repro steps.

I'm trying to simply show logged username in the application header. So I init the library as follows (and was taken from documentation):

In app.module providers:

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

init func impl:

function appInitializer( kk: KeycloakService ): () => Promise<any> {
    return () => kk.init( {
        initOptions: {
            onLoad: 'check-sso',
            checkLoginIframe: true
        },
        loadUserProfileAtStartUp: true,
        enableBearerInterceptor: true
    } );
}

In the main component I'm trying to get that info:

    constructor( private keycloakAngular: KeycloakService ) {
    }

    ngOnInit(): void {
        this.keycloakAngular
            .isLoggedIn()
            .then( result => {
                this.loggedIn = result;
                this.userName = this.loggedIn
                    ? this.keycloakAngular.getUsername()
                    : '';
            } )
            .catch( reason => console.log( reason ) );
    }

As the application starts it's being redirected to keycloak service (it's ok), then back and.. either I was logged in or not before I've got nothing as a result. And only when I go to some protected by keycloak route, my application redirects (again) and username is retrieved.

What am I doing wrong? How can I get currently logged user (if so) when application just starts? Thank you!

I've tried to save taken tokens to localStorage and then read and put them in init() function - in this case at the beginning everything was ok, but if refresh token is obsolete after some time, application crashes with unhandled 401 realm response with no way to continue. And I can't find a way to handle that error: it is happening somewhere inside the library and throws as Zone exception.

Desired functionality.

Please add/fix the way to load logged user info during startup 芯r add documentation/workaround examples for such case.

Question

All 10 comments

I haven't tried it yet but what happens if you use "loadUserProfileInStartUp"? The documentation seems to imply it would do what you are asking doesn't it?

See compatibility table:

| keycloak-angular | Angular | Keycloak | SSO-RH |
| :--------------: | :-----: | :------: | :----: |
| 1.3.x | 4 and 5 | 3 | 7 |
| 2.x.x | 4 and 5 | 4 | - |
| 3.x.x | 6 | 3 | 7 |
| 4.x.x | 6 | 4 | - |
| 5.x.x | 7 | 3 | 7 |
| 6.x.x | 7 | 4 | - |

If you use keycloak-angular v6.x.x with angular 7.x works fine. My test:

_app.init.ts_

return (): Promise<any> => keycloak.init({
        config: {
            url: 'http://localhost:8080/auth',
            realm: 'realm-name',
            clientId: 'client-name'
        },
        initOptions: {
            onLoad: 'login-required',
            checkLoginIframe: false
        },
        enableBearerInterceptor: true,
        loadUserProfileAtStartUp: true,
        bearerExcludedUrls: ['/assets']
    });

_app.component.ts_

ngOnInit(): void
    {
        this.keycloakAngular
            .isLoggedIn()
            .then( loggedIn => {
                if( loggedIn ) {
                    console.log(this.keycloakAngular.getUsername());
                }
            })
            .catch( reason => console.log ( reason ));
    }

Other option is delete loadUserProfileAtStartUp: true and call function this.keycloakAngular.loadUserProfile()

_app.component.ts_

ngOnInit(): void
    {
        this.keycloakAngular
            .isLoggedIn()
            .then( loggedIn => {
                if( loggedIn ) {
                    this.keycloakAngular.loadUserProfile()
                        .then(profile => {
                            console.log('UserProfile: ', profile);
                        })
                        .catch( reason => {console.log( reason )});
                }
            })
            .catch( reason => console.log ( reason ));
    }

@jpaniorte, nope, you set onLoad to 'login-required', that's why for you everything is fine. But the issue describes case where user don't have to be logged in (but he might) and in this case I want to get user profile.

@nmcbride, nothing happens. Application behaves as if user has been never logged in.

Hello @koldoon, how are you?

The loadUserProfileAtStartUp: true will force the application flow to login if the user is not logged in, as for requiring the user data you have to be logged in.

Also, for requiring the user profile your clientId must have the view_account scope from account clientId. This is a configuration you have to do in your keycloak server.

Thanks!

@koldoon sorry, my fault.

anyway, the loadUserProfileAtStartUp is true by default:

  /**
   * Forces the execution of loadUserProfile after the keycloak initialization considering that the
   * user logged in.
   * This option is recommended if is desirable to have the user details at the beginning,
   * so after the login, the loadUserProfile function will be called and it's value cached.
   *
   * The default value is true.
   */
  loadUserProfileAtStartUp?: boolean;

Accordingly, we have 4 scenarios in this funcion:

this.keycloakAngular.isLoggedIn().then(
            isLogged => {
                if ( isLogged ) {
                    this.username = this.keycloakAngular.getUsername();
                }
            }
        )
  1. If the user is logged and loadUserProfileAtStartUp: false:

You need call load this.keycloakAngular.loadUserProfile()

  1. If the user is logged and loadUserProfileAtStartUp: true:

You can call this.keycloakAngular.getUsername()

  1. If the user is not logged and loadUserProfileAtStartUp: false:

You need can call this.keycloakAngular.login(), this.keycloakAngular.loadUserProfile() and this.keycloakAngular.getUsername()

  1. If the user is not logged and loadUserProfileAtStartUp: true:

You need can call this.keycloakAngular.login() and this.keycloakAngular.getUsername()


I think that loadUserProfileAtStartUp: true is usefull for disable profile cached.

I hope I have been able to help you!

@jpaniorte thanks a lot for your attention!

My case is 2nd: "user is logged and loadUserProfileAtStartUp: true". And when I execute the code below:

    ngOnInit(): void {
        this.keycloakAngular
            .isLoggedIn()
            .then( isLogged => {
                this.loggedIn = isLogged;
                this.userName = this.loggedIn
                    ? this.keycloakAngular.getUsername()
                    : '';
            } )
            .catch( reason => console.log( reason ) );
    }

I've got isLogged == undefined. Of course, type is treated as false in this case, but anyway, I don't get the actual username. The important fact: the whole code runs in component that is _not_ protected by keycloak. If I go to pages, that protected from the beginning - everything is fine: i've got redirected to keycloak service, then back, and page is loaded with username displayed as expected.

Hi, @mauriciovigolo !
I don't require user to be logged in, but if he is, I need to get profile and show the name. In this case I expect that keycloak checks the session and if it is not expired, load the profile before (when) application starts. I almost achieved such effect when stored tokens in localStorage and then applied them to keycloak constructor, but when tokens are expired, library crashes somewhere inside so I can't catch that error. If it would be possible at least wrap that error that would be great.

Hi @koldoon,

I replicate the scenario and works as expected. In my case:

  • keycloak-angular: "^6.0.0"
  • Angular: ^7.0.0
  • ClientId have the view_account scope.

Do you have the same versions/config?

I will close this issue because it seems to be solved, we can reopen it, okay. Thanks.

Was this page helpful?
0 / 5 - 0 ratings