Angular-auth-oidc-client: How do I use application root for redirect_uri?

Created on 6 Aug 2018  路  4Comments  路  Source: damienbod/angular-auth-oidc-client

Thanks for this great library!

In my application (part CMS, part SPA), it is not possible to use Angular routes for various reasons, so I have to set the 'redirect_url' to my application root url.

However, that causes some redirect loop, when the STS server (Azure B2C AD) returns an access token.

Here is my Auth guard:

constructor(private injector: Injector) {
}

canActivate(): Observable<boolean> | boolean {            
    console.log('checking if online...');

    if (this.oidcSecurityService === undefined) {
        this.oidcSecurityService = this.injector.get(OidcSecurityService);
    }
    return this.oidcSecurityService.getIsAuthorized().pipe(
        map((isAuthorized: boolean) => {
        console.log('AuthorizationGuard, canActivate isAuthorized: ' + isAuthorized);

        if (isAuthorized) {
            console.log('auth guard returns true');
            return true;
        }
        console.log('auth guard returns false');
        this.oidcSecurityService.authorize();
        return false;
    })
);`

And here is my app-module:

```
export class AppModule {
constructor(
private oidcSecurityService: OidcSecurityService,
private oidcConfigService: OidcConfigService,
) {
console.log('ctor appModule');
this.oidcConfigService.onConfigurationLoaded.subscribe(() => {

        const openIDImplicitFlowConfiguration = new OpenIDImplicitFlowConfiguration();
        openIDImplicitFlowConfiguration.stsServer = 'https://login.microsoftonline.com/tfp/myb2caad.onmicrosoft.com/B2C_1_policy/oauth2/v2.0/';
        openIDImplicitFlowConfiguration.redirect_url = 'https://myapp.local';
        openIDImplicitFlowConfiguration.client_id = environment.b2cClientID;
        openIDImplicitFlowConfiguration.response_type = 'id_token token';
        openIDImplicitFlowConfiguration.scope = 'openid https://myb2caadonmicrosoft.com/apidemo/user_impersonation';
        openIDImplicitFlowConfiguration.post_logout_redirect_uri = 'https://myapp.local';
        openIDImplicitFlowConfiguration.post_login_route = '/';
        openIDImplicitFlowConfiguration.forbidden_route = '/';
        openIDImplicitFlowConfiguration.unauthorized_route = '/';
        openIDImplicitFlowConfiguration.auto_userinfo = false;
        openIDImplicitFlowConfiguration.log_console_warning_active = true;
        openIDImplicitFlowConfiguration.log_console_debug_active = !environment.production;
        openIDImplicitFlowConfiguration.max_id_token_iat_offset_allowed_in_seconds = 30;

        const authWellKnownEndpoints = new AuthWellKnownEndpoints();
        authWellKnownEndpoints.setWellKnownEndpoints(this.oidcConfigService.wellKnownEndpoints);

        this.oidcSecurityService.setupModule(openIDImplicitFlowConfiguration, authWellKnownEndpoints);
    });

    console.log('APP STARTING');
}

}
````

So my question is, how and where do I handle the authorizedCallback() when I cannot set a specific callback page other than application root?

enhancement documentation

Most helpful comment

Hi @bmadhan90

Basically, I used code from all of the samples shown on the frontpage, but I can add some of my code here, if thats what you are asking:

import { Injectable, Injector } from '@angular/core';
import { Router, CanActivate } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { map } from 'rxjs/operators';
import { OidcSecurityService } from 'angular-auth-oidc-client';

@Injectable()
export class AuthGuardService implements CanActivate
{
    private oidcSecurityService: OidcSecurityService;

    constructor(
        private router: Router,
        private injector: Injector) {
    }

    canActivate(): Observable<boolean> | boolean {            
        //console.log('checking if online...');

        if (this.oidcSecurityService === undefined) {
            this.oidcSecurityService = this.injector.get(OidcSecurityService);
        }
        return this.oidcSecurityService.getIsAuthorized().pipe(
            map((isAuthorized: boolean) => {
            console.log('AuthorizationGuard, canActivate isAuthorized: ' + isAuthorized);

            if (isAuthorized) {
                return true;
            }

            if (!window.location.hash) {
                this.router.navigate(['/unauthorized']);
            }
            return false;
        })
    ).catch(
        (err) => {
          return Observable.of(false);
        });
    }
}

Code from the unauthorized component: (I know its named RedirectComponent and not unauthorized...)

import { Component, OnInit, OnDestroy } from '@angular/core';
import { OidcSecurityService } from 'angular-auth-oidc-client';

@Component({
  template: '<p>Signing in...</p>'
})

export class RedirectComponent implements OnInit, OnDestroy {

  constructor(private oidcSecurityService: OidcSecurityService) {
    // this.message = 'UnauthorizedComponent constructor';
    this.oidcSecurityService.onModuleSetup.subscribe(() => { this.onModuleSetup(); });
    console.log('unauth comp ctor');
}

  ngOnInit() {
    console.log('redirecting...');
    if (this.oidcSecurityService.moduleSetup) {
      this.onModuleSetup();
    }
  }

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

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

App.component.ts:

export class AppComponent {

    constructor(
       public oidcSecurityService: OidcSecurityService
    ) {

        if (this.oidcSecurityService.moduleSetup) {
            this.doCallbackLogicIfRequired();
        } else {
            this.oidcSecurityService.onModuleSetup.subscribe(() => {                
                this.doCallbackLogicIfRequired();                
            });
        }
    }

    private doCallbackLogicIfRequired() {
        if (window.location.hash) {
            this.oidcSecurityService.authorizedCallback();
        }
    }
}

I guess thats the interesting classes, rest is boilerplate code from the documentation :)

Hope it helps!

best regards

All 4 comments

Closing, since I got around it by using pieces from all of the examples in the doc

Hi jhossy,

share reference you followed.

Thanks

Hi @bmadhan90

Basically, I used code from all of the samples shown on the frontpage, but I can add some of my code here, if thats what you are asking:

import { Injectable, Injector } from '@angular/core';
import { Router, CanActivate } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { map } from 'rxjs/operators';
import { OidcSecurityService } from 'angular-auth-oidc-client';

@Injectable()
export class AuthGuardService implements CanActivate
{
    private oidcSecurityService: OidcSecurityService;

    constructor(
        private router: Router,
        private injector: Injector) {
    }

    canActivate(): Observable<boolean> | boolean {            
        //console.log('checking if online...');

        if (this.oidcSecurityService === undefined) {
            this.oidcSecurityService = this.injector.get(OidcSecurityService);
        }
        return this.oidcSecurityService.getIsAuthorized().pipe(
            map((isAuthorized: boolean) => {
            console.log('AuthorizationGuard, canActivate isAuthorized: ' + isAuthorized);

            if (isAuthorized) {
                return true;
            }

            if (!window.location.hash) {
                this.router.navigate(['/unauthorized']);
            }
            return false;
        })
    ).catch(
        (err) => {
          return Observable.of(false);
        });
    }
}

Code from the unauthorized component: (I know its named RedirectComponent and not unauthorized...)

import { Component, OnInit, OnDestroy } from '@angular/core';
import { OidcSecurityService } from 'angular-auth-oidc-client';

@Component({
  template: '<p>Signing in...</p>'
})

export class RedirectComponent implements OnInit, OnDestroy {

  constructor(private oidcSecurityService: OidcSecurityService) {
    // this.message = 'UnauthorizedComponent constructor';
    this.oidcSecurityService.onModuleSetup.subscribe(() => { this.onModuleSetup(); });
    console.log('unauth comp ctor');
}

  ngOnInit() {
    console.log('redirecting...');
    if (this.oidcSecurityService.moduleSetup) {
      this.onModuleSetup();
    }
  }

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

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

App.component.ts:

export class AppComponent {

    constructor(
       public oidcSecurityService: OidcSecurityService
    ) {

        if (this.oidcSecurityService.moduleSetup) {
            this.doCallbackLogicIfRequired();
        } else {
            this.oidcSecurityService.onModuleSetup.subscribe(() => {                
                this.doCallbackLogicIfRequired();                
            });
        }
    }

    private doCallbackLogicIfRequired() {
        if (window.location.hash) {
            this.oidcSecurityService.authorizedCallback();
        }
    }
}

I guess thats the interesting classes, rest is boilerplate code from the documentation :)

Hope it helps!

best regards

Code sample shown here is no longer relevant :(

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Expelz picture Expelz  路  4Comments

toddtsic picture toddtsic  路  4Comments

revok picture revok  路  4Comments

brentos99 picture brentos99  路  4Comments

yelhouti picture yelhouti  路  4Comments