Auto redirect to an STS server in an Angular app using oidc Implicit Flow

This article shows how to implement an auto redirect in an Angular application, if using the OIDC Implicit Flow with an STS server. When a user opens the application, it is sometimes required that the user is automatically redirected to the login page on the STS server. This can be tricky to implement, as you need to know when to redirect and when not. The OIDC client is implemented using the angular-auth-oidc-client npm package.

Code: https://github.com/damienbod/angular-auth-oidc-sample-google-openid

The angular-auth-oidc-client npm package provides an event when the OIDC module is ready to use and also can be configured to emit an event to inform the using component when the callback from the STS server has been processed. These 2 events, can be used to implement the auto redirect to the STS server, when not authorized.

The app.component can subscribe to these 2 events in the constructor.

constructor(public oidcSecurityService: OidcSecurityService,
	private router: Router
) {
	if (this.oidcSecurityService.moduleSetup) {
		this.onOidcModuleSetup();
	} else {
		this.oidcSecurityService.onModuleSetup.subscribe(() => {
			this.onOidcModuleSetup();
		});
	}

	this.oidcSecurityService.onAuthorizationResult.subscribe(
		(authorizationResult: AuthorizationResult) => {
			this.onAuthorizationResultComplete(authorizationResult);
		});
}

The onOidcModuleSetup function handles the onModuleSetup event. The Angular app is configured not to use hash (#) urls so that the STS callback is the only redirect which uses the hash. Due to this, all urls with a hash can be sent on to be processed from the OIDC module. If any other path is called, apart from the auto-login, the path is saved to the local storage. This is done so that after a successful token validation, the user is redirected back to the correct route. If the user is not authorized, the auto-login component is called.

private onOidcModuleSetup() {
	if (window.location.hash) {
		this.oidcSecurityService.authorizedCallback();
	} else {
		if ('/autologin' !== window.location.pathname) {
			this.write('redirect', window.location.pathname);
		}
		console.log('AppComponent:onModuleSetup');
		this.oidcSecurityService.getIsAuthorized().subscribe((authorized: boolean) => {
			if (!authorized) {
				this.router.navigate(['/autologin']);
			}
		});
	}
}

The onAuthorizationResultComplete function handles the onAuthorizationResult event. If the response from the server is valid, the user of the application is redirected using the saved path from the local storage.

private onAuthorizationResultComplete(authorizationResult: AuthorizationResult) {
	console.log('AppComponent:onAuthorizationResultComplete');
	const path = this.read('redirect');
	if (authorizationResult === AuthorizationResult.authorized) {
		this.router.navigate([path]);
	} else {
		this.router.navigate(['/Unauthorized']);
	}
}

The onAuthorizationResult event is only emitted if the trigger_authorization_result_event configuration property is set to true.

constructor(public oidcSecurityService: OidcSecurityService) {

 let openIDImplicitFlowConfiguration = new OpenIDImplicitFlowConfiguration();
 openIDImplicitFlowConfiguration.stsServer = 'https://accounts.google.com';
 ...
 openIDImplicitFlowConfiguration.trigger_authorization_result_event = true;

 this.oidcSecurityService.setupModule(openIDImplicitFlowConfiguration);
}

The auto-login component redirects correctly to the STS server with the correct parameters for the application without any user interaction.

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Router } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';
import { OidcSecurityService, AuthorizationResult } from 'angular-auth-oidc-client';

@Component({
    selector: 'app-auto-component',
    templateUrl: './auto-login.component.html'
})

export class AutoLoginComponent implements OnInit, OnDestroy {
    lang: any;

    constructor(public oidcSecurityService: OidcSecurityService
    ) {
        this.oidcSecurityService.onModuleSetup.subscribe(() => { this.onModuleSetup(); });
    }

    ngOnInit() {
        if (this.oidcSecurityService.moduleSetup) {
            this.onModuleSetup();
        }
    }

    ngOnDestroy(): void {
        this.oidcSecurityService.onModuleSetup.unsubscribe();
    }

    private onModuleSetup() {
        this.oidcSecurityService.authorize();
    }
}

The auto-login component is also added to the routes.

import { Routes, RouterModule } from '@angular/router';
import { AutoLoginComponent } from './auto-login/auto-login.component';
...

const appRoutes: Routes = [
    { path: '', component: HomeComponent },
    { path: 'home', component: HomeComponent },
    { path: 'autologin', component: AutoLoginComponent },
    ...
];

export const routing = RouterModule.forRoot(appRoutes);

Now the user is auto redirected to the login page of the STS server when opening the Angular SPA application.

Links:

https://www.npmjs.com/package/angular-auth-oidc-client

https://github.com/damienbod/angular-auth-oidc-client

Advertisements

5 comments

  1. noumanbhatti · · Reply

    Reblogged this on Help Drive and commented:
    Excellent npm package for Angular and Identity Server 4 Implicit flow implementation

  2. noumanbhatti · · Reply

    I implemented this but my code first shows the home page and than redirects to login page (expternal idp) How to add a progress bar or spinner on home page if user is not login

    I’m using Angular5 and tried few npm packages, but not able to make it work

  3. Everything seems to work except I get this error when directed back to my SPA ‘authorizedCallback incorrect nonce’. Any idea what I could have done wrong? I see the nonce is set to an empty string and isAuthorized is false in session storage.

    1. I figured it out I had the code example inside of a service instead of a component.
      Not sure why this was an issue but once I moved it to a component it worked.

    2. Are you calling the authorize twice? If the nonce does not match, the authorize request was sent before , or a different client. If the nonce does not match, all data is reset and client app, user is not authorized.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: