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:
Reblogged this on Help Drive and commented:
Excellent npm package for Angular and Identity Server 4 Implicit flow implementation
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
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.
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.
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.
Thanks a lot for the post. I have implemented autologin functionality, I have few routes which doesn’t need user to be logged in. This solution is auto redirecting to login page even for routes which doesn’t need authorization. Any help is highly appreciated.
Anyone faced above issue. I need to resolve this. Please help me out.
@damienbod, Can this be updated to latest version(10)? Also how can I enable silent renew?
sounds like a good idea, will do, when I get time
Greetings Damien
Damien, Do you have any timeline for this?
Hello Damien,
Hope you are doing great !!
I have been using the angular-auth-oidc-client library to integrate oidc in my Angular 7 project.
I would like to pass the “acr-values: idp:AdAzure” in the auth url parameter. I cannot find any property as such (alike “custome_param:” used in angular-oauth2-oidc library).
Could you please let me know is there any update on this library or documented anywhere ?
My purpose is to: use the acr_values – to get auto redirect to external login page from Identity server 4. This can be only achieved if i pass the IDP value in client url.
This is used to bypass home realm discovery(HRD). This is provided via the “idp:” prefix to the acr parameter on the authorize request.
I need your pointers on this sooner, Appreciate your help !
Should the auto-login work with IE also? App does not redirect to STS for authentication?
How I can pass “acr-values: idp:AdAzure” in the auth url parameter? I cannot find any property in angular-auth-oidc-client library.
you can use the custom parameters to add this
Thanks Damien! Got it.
this.oidcSecurityService.setCustomRequestParameters({ ‘acr_values’: ‘idp:windowsidp’ });
Found the way.
cool, got it’s wroking
Greetings Damien
How I can pass the “acr-values: idp:AdAzure” in the auth url parameter. I cannot find any property in angular-auth-oidc-client library).Please help!
First of all, thank you for developing this library. We are using angular CLI : 8.3.0 with angular-auth-oidc-client: 10.0.15.
We observed that in the below code getIsAuthorized() subscribe is taking around 5 seconds always.
Do you have any solution for this?