Jeff Richards
Jeff Richards

Reputation: 2140

iOS Handling requests with refreshed authentication tokens

Working on an iPhone app, I'm using the Google Plus SDK (GPPSignIn) for getting and refreshing authentication tokens.

These tokens last for 1 hour. When I make a request with an expired token the web service that I am using returns a specific http response code so that I know that my token has expired.

Upon receiving a response that my token has expired, I make a call to refresh the authentication token. Now I would like to repeat the request to the web service with the new token. And I'd like to do this all within my server request object.

If I was programming the whole works myself, I could just make the request for the token refreshing inline with the web server request and when token request is done, I could proceed with the web server request. But since the token work is done through Google Plus SDK, and they are using a delegate model for communicating the completion of the authentication request, I don't know how to hold the request to the web service until the token has been refreshed.

At present I'm trying out a "pretty bad" idea, which is shown below, where I attempt to put my request into a new thread and then put that thread to sleep for a while, at which point it wakes up and we hope that the new token is available. But there has to be a better way!

             if (error !=nil && error.code == NSURLErrorUserCancelledAuthentication) {
             //special handling of 401, which may be a Google Auth token failure.
             // if it is, then let's go get a new token.

                 User *client = [[User alloc] init];

                 if(client.email != nil && client.password != nil){

                     if (client.accountType == AuthTypeGoogle) {
                         NSLog(@"attempt to get a new token");

                         // request new token
                         [client silentGoogleAuthentication];

                         //repeat request
                         if (repeatableRequest) {
                             dispatch_async(repeatQueue, ^{
                                     [NSThread sleepForTimeInterval:4];
                                     NSLog(@"sleepytime");
                                     [self assignCredentialstoRequest];
                                     [self makeRequest:notificationName repeatableRequest:false];

                             });

                         }
                     }
                 }
             }

Any pointers would be appreciated. I've looked at a number of the iOS token refreshing tickets and I see lots of stale questions, but none with a workable solution.

Upvotes: 1

Views: 274

Answers (1)

Jeff Richards
Jeff Richards

Reputation: 2140

So after some thinking about this issue, I realized a couple things.

  1. What I really wanted was to have the [client silentGoogleAuthentication]; call do all of its processing inline. And digging further into the code, I found that even though it is GPPSSignIn trySilentAuthentication supports a delegate, but it also returns a boolean when it is done processing itself.
  2. My process is already running outside of the main thread, so the delegate has very little value for me.
  3. The GPPSSign in uses a shared instance so if the processing is done I can call up the shared instance and access the results directly.

So with those two pieces of information in hand, I was able in side of the [client silentGoogleAuthentication]; call capture the result of the trySilentAuthentication call and then with that assign the results to the correct place in the code and then just return a boolean to the function that made the initial call to [client silentGoogleAuthentication] and keep going. like so:

    // Try signing in silently so user doesn't have to be prompted again
BOOL authResponse = [signIn trySilentAuthentication];
if (authResponse) {
    NSLog(@"successful auth");
    NSLog(@"idToken is %@", [GPPSignIn sharedInstance].idToken);
    self.accountType = AuthTypeGoogle;
    self.password = [GPPSignIn sharedInstance].idToken;
    [self updateCredentials];
    return true;
} else {
    return false;
}

Upvotes: 1

Related Questions