-
Notifications
You must be signed in to change notification settings - Fork 0
Oauth support on restkit
The sample iOS application for client authorization with OAuth 2 authentication server at telegraphy-interactive/OAuthClientSetup has a pluggable architecture for authorized operations. It includes a class, OACSAuthOpRK
that provides a RestKit RKObjectManager
operation for making an authorized request.
The strategy used there is to wrap the request inside of the authorization. The authorization checks the currency of the OAuth2 authorization token. Finding the token current, it tries the request and checks the return status. Finding the token expired, or finding a 401 status return from the request, it will refresh the authorization token and try the request one more time.
Here is the meat of the OACSAuthOpRK
class:
- (void)queueOpWith:(NSString*)authToken callback:(void (^)())callback
{
[self.objectManager.HTTPClient setDefaultHeader:@"Authorization" value:[NSString stringWithFormat:@"Bearer %@", authToken]];
[self.objectManager getObjectsAtPath:self.path parameters:nil success:^(RKObjectRequestOperation *rkop, RKMappingResult *res) {
self.operation = rkop;
self.mappingResult = res;
self.hasHTTPStatus = true;
RKHTTPRequestOperation *op = rkop.HTTPRequestOperation;
NSHTTPURLResponse *response = op.response;
self.httpStatusCode = response.statusCode;
self.wasSuccessful = YES;
self.error = nil;
callback();
} failure:^(RKObjectRequestOperation *rkop, NSError *rkerr) {
self.operation = rkop;
self.mappingResult = nil;
self.hasHTTPStatus = true;
RKHTTPRequestOperation *op = rkop.HTTPRequestOperation;
NSHTTPURLResponse *response = op.response;
self.httpStatusCode = response.statusCode;
self.wasSuccessful = NO;
self.error = rkerr;
callback();
}];
}
The retry logic in the OACSAuthClient
class is as follows:
- (void)authorizedOp:(id<AuthOp>)op
onSuccess:(void (^)())success
onFailure:(void (^)(NSString *))failure
retry:(BOOL) doRetry {
if (!self.creds) {
failure(@"Application is not authorized");
}
else if (self.creds.expired && doRetry) {
[self refreshAndRetry:op onSuccess:success onFailure:failure];
}
else {
[op queueOpWith:[self.creds accessToken]
callback:^(void)
{
if ([op wasSuccessful]) {
success();
}
else {
long status = [op hasHTTPStatus] ? [op httpStatusCode] : 0;
if (doRetry && 401 == status) {
[self refreshAndRetry:op
onSuccess:success
onFailure:failure];
}
else {
if (400 <= status && status < 500) {
[self resignAuthorization];
}
NSError *error = [op error];
failure(error.userInfo[@"NSLocalizedDescription"]);
}
}
}];
}
}
- (void)refreshAndRetry:(id<AuthOp>)op onSuccess:(void (^)())success onFailure:(void (^)(NSString *))failure {
if (self.creds.refreshToken) {
[self.oauthClient
authenticateUsingOAuthWithPath:self.token_path
refreshToken:self.creds.refreshToken
success:^(AFOAuthCredential *credential) {
[AFOAuthCredential storeCredential:credential
withIdentifier:self.oauthClient.serviceProviderIdentifier];
self.creds = credential;
[self authorizedOp:op onSuccess:success onFailure:failure retry:NO];
}
failure:^(NSError *error) {
failure(@"Failed to authorize");
}];
}
else {
failure(@"Application is not authorized");
}
}