How to keep session active while using keycloak in Angular 7?

I'm using this plugin https://github.com/mauriciovigolo/keycloak-angular in Angular 7 project.

Version:

keycloak-angular : 6.1.0
angular : 7.1.4

After logged in successfully , this is the response I get from /protocol/openid-connect/token:

expires_in : 1980
refresh_expires_in : 1800

It automatically logs out the user and redirecting to login page after 30 minutes. This behavior is annoying. I want this to behave as if nothing has happened as long as user is interacting with the application. In other words do not automatically log out after 30 minutes, it should keep the session active.

Could someone guide me what exact steps are needed to achieve this?

Edit 1

As @thijsfranck suggested in his answer I modified the code like this, and it worked.

app-init.ts

import {KeycloakService} from 'keycloak-angular';
export function initializer(keycloak: KeycloakService) {
  return () => {
    return new Promise(async (resolve, reject) => {
      try {
        const _REALM = "realm";
        const _URL = "http://example.com";
        const _CLIENT_ID = "id"

        await keycloak.init({
          config: {
            realm: _REALM,
            url: _URL,
            clientId: _CLIENT_ID,
          },
          initOptions: {
            onLoad: 'login-required',
            checkLoginIframe: false
          },
          enableBearerInterceptor: true,
          bearerExcludedUrls: ['/assets', '/clients/public']
        })

        const keycloakAuth = keycloak.getKeycloakInstance();

        const updateToken = async (): Promise < string > => {
          const {success,error} = keycloakAuth.updateToken(5);
          return new Promise < string > ((res, rej) => {
            success(() => res(keycloakAuth.token));
            error(rej);
          });
        }
        const login = async (): Promise < void > => {
          const {success,error} = keycloakAuth.login();
          return new Promise < void > ((res2, rej2) => {
            success(res2);
            error(rej2);
          });
        }


        keycloakAuth.onTokenExpired = () => {
          if (keycloakAuth.refreshToken) {
            updateToken();
          } else {
            login();
          }
        }

        resolve();
      } catch (error) {
        reject(error);
      }
    });
  };
}

Here is app.module.ts

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

Upvotes: 3

Views: 9867

Answers (1)

thijsfranck
thijsfranck

Reputation: 808

When your auth token expires, you can use your refresh token (if you have a valid one) to retrieve a new token.

See the code snippet below. I haven't used keycloak-angular specifically, but keycloak-js (which your library also uses) emits an event called onTokenExpired when your auth token expires. You can use that event to trigger the token refresh. If I'm reading the docs correctly, you should have access to the keycloakAuth object in your initializer() function.

import Keycloak from 'keycloak-js';

private keycloakAuth: Keycloak.KeycloakInstance;

/**
 * Whenever the token expires and a refresh token is available, try to refresh the access token.
 * Otherwise, redirect to login.
 */
this.keycloakAuth.onTokenExpired = () => {
    if (this.keycloakAuth.refreshToken) {
        this.updateToken();
    } else {
        this.login();
    }
};

async updateToken(): Promise<string> {
    const { success, error } = this.keycloakAuth.updateToken(5);
    return new Promise<string>((resolve, reject) => {
        success(() => resolve(this.keycloakAuth.token));
        error(reject);
    });    
}

async login(): Promise<void> {
    const { success, error } = this.keycloakAuth.login();
    return new Promise<void>((resolve, reject) => {
        success(resolve);
        error(reject);
    });    
}

Upvotes: 2

Related Questions