Search code examples
iosoauth-2.0afnetworkingafnetworking-2

How to automatically refresh expired token with AFOAuth2Manager?


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.


Solution

  • 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.