Silent Renewal in Ionic 3 with Identity Server 4

2019-06-09 02:51发布

问题:

So I am trying to implement silent renewal in an ionic 3 application, I am still learning about the whole thing so I'll try to be as descriptive as possible please correct me if I am wrong.

Authentication

I am using Implicit flow for my authentication using the In App Browser.

  1. The user is redirected to the authentication server page
  2. After a success authentication I retrieve the id-token & access-token

As I understand the id-token is for authentication and access-token is for authorization with the API.

I have followed this article to help me set this up (Particularly the "Deploy to Mobile Device" section) for my Identity Server.

As done in the article I am using angular-oauth2-oidc to assist me with storing information about redirect links, issuer, etc...

I have attempted to achieve this in 3 different ways, 2 of them work but I don't understand how to retrieve the new access-token and id-token, and the last one returns an error. each of them left me with questions.

First: oauthService

The angular-oauth2-oidc library has a silentRefresh() method, and this github MD describes how to use it using a hidden iframe very vaguely so I barely understand how this works. I have created a silent-refresh.html page in the same directory, but using http://localhost:8000/silent-refresh.html return's a 404. Calling the silentRefresh() method successfully re-authenticates on the server side but the request times-out on the client side, as said in the MD file, something is wrong with the iframe.

Question 1: Does the library create a new iframe and then waits for a response to the http://localhost:8000/silent-refresh.html page but is never found so I never get my response? How to proceed to retrieve my tokens?

Second: iframe

So here I follow this article where I create an iframe and add it to the body. I create my own url (similar to the one made by the silentRefresh() method), and assign it to the src of the iframe. Again on the server side everything is fine and it tries to return the tokens to http://localhost:8000.

public startRenew(url: string) {
        this._sessionIframe.src = url;

        return new Promise((resolve) => {
            this._sessionIframe.onload = () => {
                resolve();
            }
        });
}

Question 2: How to proceed to retrieve the tokens? as it doesn't update my tokens automatically, and I don't see how the code above can do it.

Third: In App Browser I thought this would work fine as I already know how to process the request using the In App Browser. So I tried to use the same url that worked for the iframe in the 2nd part. However this returns an error: prompt=none was requested. But user is not authenticated. on the server side, which tells that the server can't find the session so it doesn't know who is requesting the token renewal.

Question 3: Is there a specific reason this won't work other than I made a mistake?

NOTE: Took longer than expected to write this will edit this in a bit.

回答1:

oAuthService

So I looked in to the implementation of the silent refresh, to see what it does. It creates an iframe with a default id, unless you override it. That cleared up a lot of confusion as to what was actually happening.

The next mistake I did was placing the silent-refresh.html file in the src/ folder, that makes it inaccessible to the iframe. Instead the file should have been placed in the www/ folder.

Then inside the iframe I kept getting the net::ERR_CONNECTION_REFUSED error. This was due to CORS and is solved by editing the Client int the Config.cs file on the Authentication Server: AllowedCorsOrigins = { "http://localhost:8100", "http://<ip>:8100/", "http://<ip>:8100/silent-refresh.html" },

WARNING: This didn't work once I wanted to take this outside serving in the browser (ionic serve) or emulating on my device with ionic cordova run android -c-l-s, these made the root url return something like http://<ip>/. But once ran with ionic cordova run android (without the flags), window.location.href would return file:///<example>/<something>/index.html, using this sort of path (file:///<example>/<something>/silent-refresh.html) as a redirect url caused an ERR_UNSAFE_REDIRECT error to display in the iframe.

Perhaps silentRefresh() is an Angular only solution?

In App Browser

The mistake that caused the original error was having clearsessioncache and clearcache set to yes when creating the browser, caused the session to be wiped so the authentication server didn't know who it was duh, now reduced to this:

const browser = window.cordova.InAppBrowser.open(oauthUrl, '_blank',
     'location=no, hidden=yes'
);

Regular redirect url of http://localhost:8100 could be used to catch the request with the new tokens. And the silent-refresh.html page is not needed.

Here is the code for creating the oauthUrl:

buildOAuthRefreshUrl(nonce): string {
    return this.oauthService.issuer + '/connect/authorize?' +
      'response_type=id_token%20token' +
      '&client_id=' + this.oauthService.clientId +
      '&state=' + nonce +
      '&redirect_uri=' + encodeURIComponent(this.oauthService.redirectUri) +
      '&scope=' + encodeURI(this.oauthService.scope) +
      '&nonce=' + nonce +
      '&prompt=none';
}

The rest of the code is pretty much identical to the originally mentioned article