nxtbgthng / OAuth2Client

Client library for OAuth2 (currently built against draft 10 of the OAuth2 spec)
855 stars 217 forks source link

How to manually perform token refresh #179

Open emersonku opened 9 years ago

emersonku commented 9 years ago

Hi team! First of all thanks for the great work on the framework it's great.

I got a question though - I am using this library (for authentication) to work with Restkit (for resource retrieval). I have successfully got access token from the service provider (we built it too). However, I can't find any information on how to monitor if token has expired and manually refresh the token by presenting the refreshToken (which we got from the server in the same request). I guess I need to use notification, and I have tried to all some notification but they are never called even when the token is expired (we have set the TTL value very short just to test).

Appreciating for the help in advance.

cowboyrushforth commented 9 years ago

Hi,

My app uses both Restkit and this library as well, its a good combo.

For the refresh token part, OAuth2Client seems to only handle the automatic refreshing if your using it as a full end to end solution for fetching data.

When I use Restkit, I just grab a signed request from the OAuth2Client, and then I have run Restkit run this request and turn the JSON api results into core data objects.

Because of this, OAuth2Client isn't handling the response from the server, so it has no idea if the access token is expired.

One possible way of solving this is by checking the results of your request coming back from rest kit, and if it's a 401 you would then need to use the refresh token to obtain a new access token, and/or alert your user that the request failed and possibly even log them out, depending on your use case I suppose.

An example of the above:

NSArray *accounts = [[NXOAuth2AccountStore sharedStore] accountsWithAccountType:@"account.identifier"];

 assert([accounts count] >0);  

 NXOAuth2Request *oauthRequest = [[NXOAuth2Request alloc] initWithResource:[NSURL URLWithString:@"http://my.awesome.api.com/endpoint"]
                                                                       method:@"GET"
                                                                   parameters:nil];
 oauthRequest.account = [accounts firstObject];
 NSURLRequest *signedRequest = [oauthRequest signedURLRequest];

 [[RKObjectManager sharedManager] managedObjectRequestOperationWithRequest:signedRequest 
managedObjectContext:[[RKObjectManager sharedManager] managedObjectStore].mainQueueManagedObjectContext 
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
        // request was good
} 
failure:^(RKObjectRequestOperation *operation, NSError *error) {
       // request failed
     if([[error.userInfo objectForKey:@"AFNetworkingOperationFailingURLResponseErrorKey"] statusCode] == 401) {
     // the error code was 401, so the token may be invalid, expired
     // accounts is an array of NXOAuth2Account objects, and NXOAuth2Account each have an NXOAuth2AccessToken object.  so you can find the refreshToken at [accounts firstObject].accessToken.refreshToken i believe.
   }
}];                                                                                          

So the obvious part missing here is the actual http work needed to go and fetch the updated token, and then retry this request, and/or fail the entire chain of events if it still can't get past the 401. I have read the code here:

https://github.com/nxtbgthng/OAuth2Client/blob/develop/Sources/OAuth2Client/NXOAuth2Connection.m#L418

and here:

https://github.com/nxtbgthng/OAuth2Client/blob/develop/Sources/OAuth2Client/NXOAuth2Client.m#L469

Which are very relevant to your question. I hope to use/re-use this and implement a solution to get the refresh token working for the rest kit integration, but this is basically where I am until more time allows.

Hope this helps. If you do come up with a good solution I would be most interested to hear. cheers.

emersonku commented 9 years ago

Hi thanks for your reply. This is exactly the sore point. There's a lack of documentation on how to do this (my own complain to this framework). I have invested a lot of time on this and still getting nowhere.