Oauth2 Implicit Flow with single-page-app refreshing access tokens

I am using Thinktecture AuthorizationServer (AS) and it is working great.

I would like to write a native javascript single page app which can call a WebAPI directly, however implicit flow does not provide a refresh token.

If an AJAX call is made, if the token has expired the API will send a redirect to the login page, since the data is using dynamic popups it will this will interrupt the user.

How does Facebook or Stackoverflow do this and still allow the javascript running on the page to call the APIs?

Proposed Solution

Does the below scenario sound sensible (assuming this can be done with iframes):

My SPA directs me to the AS and I obtain a token by Implicit Flow. Within AS I click allow Read data scope, and click Remember decision, then Allow button.

Since I have clicked Remember decision button, whenever I hit AS for a token, a new token is passed back automatically without me needing to sign in ( I can see FedAuth cookie which is remembering my decision and believe this is enabling this to just work).

With my SPA (untrusted app), I don't have a refresh-token only an access token. So instead I:

  1. Ensure user has logged in and clicked remember decision (otherwise iframe wont work)
  2. Call WebAPI, if 401 response try and get a new token by the below steps...
  3. Have a hidden iframe on the page, which I will set the URL to get a new access-token from the Authorisation Server.
  4. Get the new token from the iframe's hash-fragment, then store this in the SPA and use for all future WebAPI requests.

I guess I would still be in trouble if the FedAuth cookie is stolen.

Any standard or recommended way for the above scenario?

Answers:

Answer

In Google o-Auth , the access token will only be valid for 1 hour, so you need to programmatically update your access token in each one hour, simple you can create web api to do so,you need to have a refresh token, and also that refresh token will not be expired , using c# code, I have done this.

 if (dateTimeDiff > 55)
            {
                var request = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/oauth2/v3/token");
                var postData = "refresh_token=your refresh token";
                postData += "&client_id=your client id";
                postData += "&client_secret=your client secrent";
                postData += "&grant_type=refresh_token";

                var data = Encoding.ASCII.GetBytes(postData);            
                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";
                request.ContentLength = data.Length;
                request.UseDefaultCredentials = true;

                using (var stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }
                var response = (HttpWebResponse)request.GetResponse();
                string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

            }

you need to save the last updated date time of the access token somewhere(say in database), so that , whenever you have to make a request , so you can subtract that with current date time , if it is more than 60 minutes , you need to call the webapi to get new token .

Answer

I understand that your problem is that the user will experience an interruption when the access token has expired, by a redirection to the login page of the authorization server. But I don't think you can and should get around this, at least, when using the implicit grant.

As I'm sure you already know, the implicit grant should be used by consumers that can NOT keep their credentials secret. Because of this, the access token that is issued by an authorization server should have a limited ttl. For instance google invalidates their access token in 3600 sec. Of course you can increase the ttl, but it should never become a long lived token.

Also something to note is that in my opinion the user interruption is very minimal, i.e if implemented correctly, the user will only have to authenticate once with the authorization server. After doing that (for example the first time when also authorizing the application access to whatever resources the user controls) a session will be established (either cookie- or token based) and when the access token of the consumer (web app using implicit grant) expires, the user will be notified that the token has expired and re authentication with the authorization server is required. But because a session already has been established, the user will be immediately redirected back to the web app.

If however this is not what you want, you should, in my opinion, consider using the authorization code grant, instead of doing complicated stuff with iframes. In that case you need a server side web application because then you can keep your credentials secret and use refresh tokens.

Answer

Sounds like you need to queue requests in the event that an access token expires. This is more or less how Facebook and Google do it. A simple way using Angular would be to add a HTTP Interceptor and check for HTTP401 responses. If one is returned, you re-authenticate and queue any requests that come in after until the authentication request has completed (i.e. a promise). Once that's done, you can then process the outstanding queue with the newly returned access token from your authentication request using your refresh token.

Happy Coding.

Answer

Not sure if I understand your question but,

I would like to write a native javascript single page app which can call a WebAPI directly, however implicit flow does not provide a refresh token.

Summarize facts,

refresh token is sometimes used to be a part of A: Authorization Grant

https://tools.ietf.org/html/rfc6749#section-1.5

and as you said in implicit flow you dont get back refresh token, but only in Authorization Grant part

https://tools.ietf.org/html/rfc6749#section-4.2.2

so you can get back refresh token when issuing access token (refresh tokens are always optional)

https://tools.ietf.org/html/rfc6749#section-5.1

With my SPA (untrusted app), I don't have a refresh-token only an access token. So instead I:

1) Ensure user has logged in and clicked remember decision (otherwise iframe wont work)

2) Call WebAPI, if 401 response try and get a new token by the below steps...

3) Have a hidden iframe on the page, which I will set the URL to get a new access-token from the Authorisation Server.

4) Get the new token from the iframe's hash-fragment, then store this in the SPA and use for all future WebAPI requests.

1) SPA(you) have no idea if user selected remember decision. Its in AS direction and should be complete blackbox. Skip this step.

2) You can try to use access token and wait for result, always.

3) If access token has expired and you dont have refresh token, you still can create hidden iframe and and try to get new access token.

4) Lets assume your AS provide option to remember decision and wont change it in future, then: your iframe will get new access token without user interaction, then you will get result back in some unknown time limit. Result can be checked by setInterval for read specific cookie or iframe postmessage. If you dont get back data in time limit, then one from following scenarios occured:

  • lag, AS is slow, connection is slow or time limit is too tight
  • user didnt select remember decision

In this case:

5) show iframe with login

I consider scenario above as good practise if AS doesnt provide refresh tokens, but I also guess every AS like that wont provide remember option as well.

StackOverflow <---> Google scenario (I can only guess)

1) User login, authorization request occured

2) User logs in, SO gets access token

3) SO tries to use access token

4) SO gets back result + refresh token

5) SO saves refresh token

6) SO has permanent access to users Google account

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.