How to automatically refresh expired token with AFOAuth2Manager?
Asked Answered
H

4

10

I'm writing a small iOS client for a server protected with OAuth2.

I'm wondering if is it possible using AFOAuth2Manager [here] auto-refreshing the expired token.

The idea is that the logic for refreshing the client when the server responds with a 401, or raise an error when the refresh method returns a 401 should be quite common, so probably it is integrated in some library.

Hedy answered 9/3, 2015 at 15:58 Comment(3)
Have you found any solutions?Ingot
not so far. I implemented my own logicHedy
can you post your sample or explain what you did? i am looking for the same.Baal
H
14

I created a subclass of AFOAuth2Manager

In this subclass I override this method:

- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request
                                                    success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                                                    failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure {
    return [self HTTPRequestOperationWithRequest:request
                                         success:success
                                         failure:failure
                           checkIfTokenIsExpired:YES];
}

calling a custom method with an additional parameter: checkIfTokenIsExpired. This is required in order to avoid infinite loops.

The implementation of this method is straigth forward: if we don't need to check the token just call the super class.

if (!checkIfTokenIsExpired) {
        return [super HTTPRequestOperationWithRequest:request
                                              success:success
                                              failure:failure];
    }

otherwise we perform the request with a custom failure block

else {
        return [super HTTPRequestOperationWithRequest:request
                                              success:success
                                              failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
            if (operation.response.statusCode == ERROR_CODE_UNAUTHORIZED) { //1
                [self reauthorizeWithSuccess: ^{ //2
                    NSURLRequest *req = [self.requestSerializer requestByAddingHeadersToRequest:request]; //3
                    AFHTTPRequestOperation *moperation = [self HTTPRequestOperationWithRequest:req //4
                                                                                       success:success
                                                                                       failure:failure
                                                                         checkIfTokenIsExpired:NO];

                    [self.operationQueue addOperation:moperation]; //5
                }                    failure: ^(NSError *error) {
                    failure(nil, error);
                }];
            }
            else {
                failure(operation, error); //6
            }
        }];
    }
  • //1: check the http status code, if 401 try to automatically re-authorize.
  • //2: reauthorize is a private mathod that uses AFOAuthManager to refresh the token.
  • //3: In this case we are re-authorized with success and we want to resubmit a copy of the previous request. The method requestByAddingHeadersToRequest: just copy all the header fields from the previous request.
  • //4: Create a copy of the previous request, but this time the last parameter is false because we don't want check again! The successBlock and failureBlock are the same of the previous request.
  • //5: Add the operation to the queue.
  • //6: If the reauthorize method fails just call the failure block.
Hedy answered 24/8, 2015 at 8:13 Comment(2)
This is a fantastic response! I'm curious: how would you implement the reauthorizeWithSuccess: method to ensure that not more than one request to refresh tokens fires at the same time? Similarly: if you're in the middle of refreshing tokens, you don't want other requests to fire off with the current, expired token. What's a simple way to implement that? Suspending the queue seems kind of hairy...Soulsearching
If you like the response can you vote up? :) About your questions, there is no specific check for multiple requests. In my project there is not way to have multiple request at the same time so for me is ok. Otherwise I will suggest two approach: 1. do nothing special. Even if you have 3 calls in parallel and you are refreshing the tocken you will end up with 3 unnecessarely requests is this a big deal? depends on the projet. 2. Add a flag variable (atomic) and put it to true during the refresh token task. If your request fails and this boolean is true, just retry afer 0.1sec.Hedy
H
2

Unfortunately I didn't found any framework for solve this problem so I wrote a short wrapper around AFNetworking (if someone is interested I can publish on github) The logic is to execute the request, and in case of http response 401, try to refresh the auth-token and when it's done to re-execute the previous request.

Hedy answered 22/8, 2015 at 17:5 Comment(2)
Could you put it on GitHub, please?Slavish
hi IgnazioC, please provide example Thanks!Blip
B
0

I was searching an answer for this problem and "Matt", the creator of AFNetworking, suggest this:

the best solution I've found for dealing with this is to use dependent NSOperations to check for a valid, un-expired token before any outgoing request is allowed to go through. At that point, it's up to the developer to determine the best course of action for refreshing the token, or acquiring a new one in the first place.

Simple, but effective?, trying now, will edit with report...

Blip answered 7/4, 2017 at 19:44 Comment(0)
H
0

Swift solution with Alamofire 4.0. Based on RequestAdapter and RequestRetrier protocols: example link

Horripilation answered 6/9, 2018 at 12:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.