Search code examples
angularidentityserver4openid-connectoidc-client-js

Angular SPA with identity server and oidc-client-js: is there a pattern to trigger login when the application starts (without using a login button)?


I'm working with an angular 8 SPA, and I'm trying to use the oidc-client-js library to handle the user authentication. The identity provider is implemented by using identity server 4.

Our desired user experience is the following: when the SPA is loaded in the browser, without requiring any kind of user interaction, the login flow is started. Put in other words, we would like to trigger the login flow automatically and to avoid the need for an explicit login button in the first view of the application.

The AppComponent is the first component loaded in our application and it has the following init method:

ngOnInit() {
    this.authService.login();
  }

The auth service login is doing the following:

login() {
        return this.userManager.signinRedirect();
    }

By doing so we are able to successfully redirect the user to the identity server login form. After the login form is submitted identity server redirects the user back to the SPA application on the configured redirect uri (/signin-callback).

At that point we would like to load a component able to complete the login flow. This component should call the following method of the auth service inside of its ngOnInit method:

completeLogin() {
        return this.userManager.signinRedirectCallback().then(user => {
          console.log("Login has been completed.", user);
          return user;
        });
    }

Unfortunately this approach does not work, because when identity server redirects back to the SPA application (after the login form is submitted), the AppComponent is loaded in the browser and the login flow is started once again and an infinite redirect loop begins, until the browser finally blows up.

Is there a way for us to make this work ?

Additional notes:

  • all the examples i have found make use of an explicit login button, so I'm asking myself if our desired behaviou makes sense at all
  • the core issue is that we always call this.userManager.signinRedirect() when the application bootstraps in the browser; we should find a way to avoid the call if the login flow has already been started and the application is being loaded due to the redirect after the user logs in at the identity server level. Is there a robust way to do so ?

Update 15th September 2020

The simplest way that I've found to manage this issue is doing the sigin redirect callback inside of a static HTML page, which is not part of the angular application. You can find an example in the sample folder of the oidc client js repository


Solution

  • REQUIREMENTS

    There are 2 main aspects to making this work. It is a design pattern really, and can be implemented in any language:

    • Trigger login redirects based on whether you can get data from APIs
    • Handle the login response as part of your page load, which then makes tokens available for calling APIs, avoiding further redirects

    You'll have to figure out the Angular specifics, since I don't know that framework. I hope this gives you a few useful pointers though.

    RESOURCES OF MINE

    The code below uses plain Typescript, and you'd need to translate that to your preferred Angular syntax.

    My blog also has some more advanced samples if useful, on stuff like silent token renewal - and a Quick Start Page where you can run an online React sample with the above behaviour.