Restore Viewstate After Oauth2 Redirect
Updated 486 Days AgoPublic

In single-page apps it tends to be difficult to handle "viewstate". Ionic2 has improved this significantly as the URL is no longer the "main" driver for the viewstate, it is just another means to support bookmarking and sharing, for example.

Combining Ionic2 with OAuth2 authentication, we run into the issue redirect URLs must not be dynamic as they are to be registered with the IdP. For example: http://www.my-ionic-app.com/. If our application now tries to handle "unauthenticated" requests gracefully, it may happen that view states like http://www.my-ionic-app.com/#/some/data require authentication - but OAuth "indirect flow" throws us back on the root page.

Here's how we solved this on a recent Ionic2 app:

import {OAuthService} from 'angular2-oauth2/oauth-service';
import {ModalController, DeepLinker} from "ionic-angular";

...

   authenticate(...) {
          this.oAuthService.loginUrl = this.idP.loginUrl;
          this.oAuthService.redirectUri = window.location.origin;
          this.oAuthService.scope = "openid email";
          window.localStorage.setItem("state", window.location.href);
          this.ngZone.onStable.subscribe(() => {
            this.oAuthService.initImplicitFlow();
          })

...

constructor(http: Http, private logger: LoggerService,
              private yaasBuilderIntegrationService: YaasBuilderIntegrationService,
              private oAuthService: OAuthService,
              private modalCtrl: ModalController,
              private ngZone: NgZone,
              private deepLinker: DeepLinker) {
...
    this.oAuthService.tryLogin({});

    var redirect = window.localStorage.getItem("state");
    if (redirect) {
      window.localStorage.removeItem("state");
      window.location.href = redirect;
      Observable.timer(1000).subscribe(()=>{
        this.deepLinker.updateLocation(redirect.substring(window.location.origin.length+2),null);
      })
    }

In a nutshell:

  • If authentication required:
    • Store current URL in localStorage.
    • Setup and trigger implicit flow: `this.oAuthService.initImplicitFlow();. Note this _must_ run in ngZone.onStable` to prevent override by Ionic2 view handlers!

(Relevant then only on the next load of our app, ie. after return from OAuth2 IdP)

  • In constructor of our service (in our case: `auth.service.js), attempt to perform parsing of OAuth2 query parameters. This is handled by library: this.oAuthService.tryLogin({});`
  • Restore `window.location.href` based on localStorage, if applicable. This will bring up the correct Ionic view - but will not manipulate the NavController accordingly.
  • In a `timeout`ed function, use Ionic DeepLinker to also reflect the restored URL in hashbang notation.
Last Author
krzysztofa
Projects
None
Subscribers
None