Angular-oauth2-oidc: Ionic 4 mobile app with angular-auth2-oidc

Created on 28 Apr 2020  路  12Comments  路  Source: manfredsteyer/angular-oauth2-oidc

Hi
I could successfully launch the ionic app in mobile. But the identity server login page is getting launched in external browser. But I want to launch the page in inappbrowser for both android and iOS.

How can I achieve the same with angular-auth2-oidc and ionic cordova.

question

Most helpful comment

@jeroenheijmans is it possible to turn this from a question into a feature request? The Ionic community is huge and we would profit a lot from such a well-maintained lib as this one, if it offered the option to use an own redirect instead of a static one.

Another useful feature request for Ionic would be being able to provide your own httpClient in order to use a cordova-http-client (with HTTPS pinning) for logout calls etc.

Or is Ionic support out of question in general?

All 12 comments

Hmm, that's a bit broad question, we're but a small community, typically focused on helping out on bugs and feature requests. I suggest trying your luck to find someone who created a tutorial on your scenario, or be the first to write it. Otherwise, we'd have to hope for a community member here to pop up to answer your question...

Hi, sorry if I missed anything.
The existing code angular-auth2-oidc is launching the url in external browser in mobile app.
How to open the same in inapp browser if there is a facility already there.

Hello, @CodeDangler

I would also like to use this library in mobile applications, as it is one of the best I have found.

I tried to implement a solution suggested by @nhance without success:

But I found another library, not as good as angled-oauth2-oidc from @manfredsteyer but that somehow works:

@jeroenheijmans is it possible to turn this from a question into a feature request? The Ionic community is huge and we would profit a lot from such a well-maintained lib as this one, if it offered the option to use an own redirect instead of a static one.

Another useful feature request for Ionic would be being able to provide your own httpClient in order to use a cordova-http-client (with HTTPS pinning) for logout calls etc.

Or is Ionic support out of question in general?

OP kicked off this thread with:

How can I achieve the same with angular-auth2-oidc and ionic cordova.?

In that I read a question for guidance around using this library within a specific ecosystem.

I'm happy to change the labels (they're just labels anyways) to a 'feature request', but then what is the specific _feature_ being requested?

If it's about getting a specific tutorial for using the library within Ionic, I'm not sure if the community around this library is big enough to support that. It would possibly be written by someone, but then quickly go out of date. I much prefer then someone takes up the gauntlet of writing one, and we add it to the list of Tutorials.

In fact.... if you look at that list, there is already an external "Ionic" sample linked.

What do you think, does this make sense?

@jeroenheijmans Thanks for the quick reply. I am aware of that tutorial, but the solution used there (additionally using an okta plugin) works around many of the features that this lib (angular-oauth2-oidc) already provides, thus reducing the benefits of this lib. If you take a look at this chunk of code from the tutorial:

oktaLogin(): Promise<any> {
  return this.oauthService.createAndSaveNonce().then(nonce => {
    let state: string = Math.floor(Math.random() * 1000000000).toString();
    if (window.crypto) {
      const array = new Uint32Array(1);
      window.crypto.getRandomValues(array);
      state = array.join().toString();
    }
    return new Promise((resolve, reject) => {
      const oauthUrl = this.buildOAuthUrl(state, nonce);
      const browser = window.cordova.InAppBrowser.open(oauthUrl, '_blank',
        'location=no,clearsessioncache=yes,clearcache=yes');
      browser.addEventListener('loadstart', (event) => {
        if ((event.url).indexOf('http://localhost:8100') === 0) {
          browser.removeEventListener('exit', () => {});
          browser.close();
          const responseParameters = ((event.url).split('#')[1]).split('&');
          const parsedResponse = {};
          for (let i = 0; i < responseParameters.length; i++) {
            parsedResponse[responseParameters[i].split('=')[0]] =
              responseParameters[i].split('=')[1];
          }
          const defaultError = 'Problem authenticating with Okta';
          if (parsedResponse['state'] !== state) {
            reject(defaultError);
          } else if (parsedResponse['access_token'] !== undefined &&
            parsedResponse['access_token'] !== null) {
            resolve(parsedResponse);
          } else {
            reject(defaultError);
          }
        }
      });
      browser.addEventListener('exit', function (event) {
        reject('The Okta sign in flow was canceled');
      });
    });
  });
}

all this response parameters parsing is something that you already have in the lib. It would be better if one could pass that window.cordova.InAppBrowser.open into the lib and let the URL parsing etc be handled by the lib as with Angular for the web.

And as mentioned above, one should be able to provide a custom httpClient for HTTPS-pinning (I would see that in a separate feature).

So basically, I am asking for "real" Ionic support, not documentation or a tutorial. Is this something that this lib could provide in the future or do you not want to open that can of worms?

I'm starting to understand a little better.

I'm asking for "real" Ionic support...
Is this something that this lib could provide?

I think it's good to have interception points in the library, as long as they're not _tightly coupled_ to another framework such as Ionic: we don't want to give _all_ users of the library Ionic-specific features, I think?

I have not read through the tutorial, nor do I know much about Ionic. The code you posted does look off to me indeed, you shouldn't need that when using the library. But it could also be that you could do better than that specific tutorial? I just don't know.

What we really need to know what the actual, concrete _feature request_ is. Because "real Ionic support" is still too vague for me. And with that, a bit too hard to know if it'd be a good fit.

Would you have a concrete prototype or proposed change for the library, that would make it more useful in e.g. Ionic environments?

@jeroenheijmans This is what I had in mind, sounds good 馃憤

I will make two new feature-requests with detailed requirements. EDIT:

        if (isMobile) {
            implicitFlowConfig.openUri = (uri) => {
                const browser = this.iab.create(uri, "_blank",
                    "location=no,clearsessioncache=yes,clearcache=yes");
                browser.on("loadstart").subscribe(event => {
                    if ((event.url).indexOf("http://localhost:8100") === 0) {
                        browser.close();
                        const responseParameters = ((event.url).split('#')[1]).split('&');
                        const parsedResponse: any = {};
                        for (let i = 0; i < responseParameters.length; i++) {
                            parsedResponse[responseParameters[i].split('=')[0]] =
                                responseParameters[i].split('=')[1];
                        }

                        const idToken = parsedResponse.id_token;
                        const accessToken = parsedResponse.access_token;
                        const keyValuePair = `#id_token=${encodeURIComponent(idToken)}&access_token=${encodeURIComponent(accessToken)}`;
                        this.oauthService.tryLogin({
                            customHashFragment: keyValuePair,
                            disableOAuth2StateCheck: true
                        }).then(sucess => {
                             if (success) { /* after-login-actions, like redirect to welcome page */}
                        });
                    }
                });
                browser.show();
            };
        }
        this.oauthService.configure(implicitFlowConfig);

If you have any idea how to change it to code-flow, that would be greatly appreciated. The code flow seems not to receive a URL based response at all? This part is never executed for me when I change to code-flow: if ((event.url).indexOf("http://localhost:8100") === 0) {...}

Thx @philly-vanilly!

Fair warning: the community at the library is small, and PRs sometimes move a bit slow. I moderate the issues a lot, but it's largely the core maintainer looking at a bunch of PRs all at once every few months. So you might not get fast or huge interaction (but the effort is still appreciated! <3).

I assume, with code flow, I would need to use customRedirectUri instead of customHashFragment?

Hi @philly-vanilly ,
thanks for your code snippet!
Did you fine a solution for code flow?

I've been looking for a similair solution. After lots of debugging and looking at the source code of this library I figured out what to do when using capacitor.
Our current setup: Angular 8
angular-oauth2-oidc: 10.0.3
capacitor: 2.4.2

Implicit flow was working fine at first, but the code flow+PKCE gave some issues which where caused by an outdated version of angular-oauth2-oidc, but was resolved in this PR

The little bit of code that was needed to get things working:

import {NgZone} from '@angular/core';
import {Plugins} from '@capacitor/core';
import {OAuthService} from 'angular-oauth2-oidc';
import {Router} from '@angular/router';

const {App, Browser, Device} = Plugins;

export class AppComponent {

  constructor(
    private zone: NgZone,
    private oauthService: OAuthService,
    private router: Router,
  ) {
    this.listenForOAuthRedirect();
  }

  private async listenForOAuthRedirect() {
    // example of the important stuff
    const oauthParameters = {
      responseType: 'code',
      // the IDP must redirect to the App URI (it should be whitelisted)
      redirectUri: 'custom-app-uri://localhost',
      // open a new browser window when starting implicit flow
      openUri: url => Browser.open({url})
    };

    this.oauthService.configure(oauthParameters);

    App.addListener('appUrlOpen', async data => {
      const platform = (await Device.getInfo()).platform as Platform;

      // because reasons
      if (platform === 'ios') {
        await Browser.close();
      }

      await this.zone.run(async () => {
        await this.oauthService.tryLogin({customHashFragment: data.url.substr(data.url.indexOf('?'))});

        const hasValidAccessToken = await this.oauthService.hasValidAccessToken();

        if(hasValidAccessToken){
          await this.router.navigate(['/your-protected-route-after-login']);
        }
      });
    });
  }

}

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jeroenheijmans picture jeroenheijmans  路  4Comments

PandaaAgency picture PandaaAgency  路  3Comments

Swissbite picture Swissbite  路  4Comments

medokin picture medokin  路  4Comments

zulander1 picture zulander1  路  4Comments