Angular-auth-oidc-client: onAuthorizationResultComplete doesn't return AuthorizationResult.authorized

Created on 11 Jun 2018  路  6Comments  路  Source: damienbod/angular-auth-oidc-client

I am trying to implement some code that runs after the AuthorizationResult is complete and authorized. In my own code (based on your dotnet-angular-azure-ad-oidc sample), I consistently get AuthorizationResult.unauthorized returned when the user is unauthorized. However, I cannot get it to returnAuthorizationResult.authorized ever. To be clear, the authorization is successful, as I am able to see the token, and use the getIsAuthorized to change the nav bar.

In the constructor, I have:

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

which calls

  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']);
    }
  }

But as I said above, this only ever gets AuthorizationResult.unauthorized passed into it. My hope is to add my own post-successful login code into the AuthorizationResult.authorized code block above.

I have noticed that whether I run your sample code (pointing to our Azure AD), or my own code, that I get a TypeError: Cannot read property 'toLowerCase' of undefined, which may or may not be related.

stack:"TypeError: Cannot read property 'toLowerCase' of undefined\n    at HttpXsrfInterceptor.push../node_modules/@angular/common/fesm5/http.js.HttpXsrfInterceptor.intercept (http://localhost:4200/vendor.js:8032:29)\n    at HttpInterceptorHandler.push../node_modules/@angular/common/fesm5/http.js.HttpInterceptorHandler.handle (http://localhost:4200/vendor.js:7412:33)\n    at HttpInterceptingHandler.push../node_modules/@angular/common/fesm5/http.js.HttpInterceptingHandler.handle (http://localhost:4200/vendor.js:8085:27)\n    at MergeMapSubscriber.project (http://localhost:4200/vendor.js:7163:184)\n    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._tryNext (http://localhost:4200/vendor.js:79776:27)\n    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._next (http://localhost:4200/vendor.js:79766:18)\n    at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (http://localhost:420...

Finally, I do have the configuration set to call that event handler:

      openIDImplicitFlowConfiguration.trigger_authorization_result_event = true;

This is with Angular 6.0.5 (sample code) and 5.2.9 (my code) on Node 8.11.1.

Any suggestions or ideas?

Most helpful comment

PR 246 submitted

All 6 comments

The console.log line before the error is:

storing to storage, getting the roles
angular-auth-oidc-client.es5.js:1027

I use something like this:

this.isAuthorized$ = Observable.combineLatest(new Observable<boolean>((subscriber) => {
            if (this.oidcSecurityService.moduleSetup) {
                subscriber.next(true);
                subscriber.complete();
            }
            else {
                this.oidcSecurityService.onModuleSetup.take(1).subscribe(() => {
                    subscriber.next(true);
                    subscriber.complete();
                });
            }
        }), this.silentRenewSetupComplete$)
        .map(([setupComplete, silentRenewSetupComplete]) => {
            return setupComplete && silentRenewSetupComplete;
        })
        .filter((complete) => {
            return complete == true;
        })
        .switchMap(() => {
            var race = Observable.race<any>(
                this.oidcSecurityService.getIsAuthorized().filter((isAuthorized) => isAuthorized == true), 
                this.oidcSecurityService.onAuthorizationResult.asObservable()     
            );

            this.oidcSecurityService.refreshSession();

            return race;
        })
        .switchMapTo(this.oidcSecurityService.getIsAuthorized())
        .shareReplay(1);   

Maybe that can help you?

Thanks @profet23. I was able to get my code to work this morning by putting it in a subscription to getIsAuthorized().

That said, I'd still like to figure out why onAuthorizationResultComplete isn't called for an authorized result. I'll keep digging on that one :)

I figured it out!

Azure AD, which we are authenticating against, has not implemented the UserInfo end point. The default setting for auto_userinfo here in AuthConfiguration is "true". This causes execution to go down the path:

 if (this.authConfiguration.auto_userinfo) {
                    this.getUserinfo(
                        isRenewProcess,
                        result,
                        validationResult.id_token,
                        validationResult.decoded_id_token
                    ).subscribe(response => {
                        if (response) {
                            this.onAuthorizationResult.emit(AuthorizationResult.authorized);
                            if (!this.authConfiguration.trigger_authorization_result_event && !isRenewProcess) {
                                this.router.navigate([
                                    this.authConfiguration.post_login_route
                                ]);
                            }
                        } else {
                            this.onAuthorizationResult.emit(AuthorizationResult.unauthorized);
                            if (!this.authConfiguration.trigger_authorization_result_event && !isRenewProcess) {
                                this.router.navigate([
                                    this.authConfiguration.unauthorized_route
                                ]);
                            }
                        }
                    });

That subscribe doesn't have a catch/catchError associated with it, so it just never executes. Hence, no AuthorizationResult.authorized is ever emitted, and the onAuthorizationResultComplete is never called.

Setting openIDImplicitFlowConfiguration.auto_userinfo = false; in app.module.ts made everything work properly.

I'll submit a pull request for adding the catch for your review shortly.

PR 246 submitted

fixed in release 6.0.2

Was this page helpful?
0 / 5 - 0 ratings