In this episode we cover how to authenticate with an OAuth2 provider for user authentication. As an example, we authenticate with Instagram using the Client Profile, which is most suited to a mobile application.
Episode Links Episode Source Code OAuth2 homepage OAuth2 Spec Instagram Developer Documentation Implementing Custom URL Schemes - This is Apple's official documentation on how to have your application open for a custom URL Scheme Authenticating a User #define INSTAGRAM_AUTH_URL_FORMAT @"https://instagram.com/oauth/authorize/?client_id=%@&redirect_uri=%@&response_type=token" - (void)authenticateWithClientID:(NSString *)clientId callbackURL:(NSString *)callbackUrl { NSString *urlString = [NSString stringWithFormat:INSTAGRAM_AUTH_URL_FORMAT, clientId, callbackUrl]; NSURL *url = [NSURL URLWithString:urlString]; [[UIApplication sharedApplication] openURL:url]; } Note here that we're just launching MobileSafari with the auth url. We could use our own web view, launched modally in our application too. We can then call this with the appropriate client id & callback URL: #define INSTAGRAM_CLIENT_ID @"1f074f314d1347789cc9d9a9d19ee342" - (void)authenticateWithInstagram { NSString *callbackUrl = @"nsscreencast://instagram_callback"; [[InstagramClient sharedClient] authenticateWithClientID:INSTAGRAM_CLIENT_ID callbackURL:callbackUrl]; } Responding to the callback This custom callback URL scheme must match the settings in your Instagram application at http://instagram.com/developer. We need to then respond to this URL in the info.plist: With this in place, we'll have to implement application:handleOpenURL: in order to grab the details from the callback. The access token we need will be a query string parameter on this URL. - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url { [[InstagramClient sharedClient] handleOAuthCallbackWithURL:url]; return YES; } Here we delegate to our InstagramClient object, which is defined like this: - (void)handleOAuthCallbackWithURL:(NSURL *)url { NSError *regexError = nil; NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[^#]*#access_token=(.*)$" options:0 error:®exError]; NSString *input = [url description]; [regex enumerateMatchesInString:input options:0 range:NSMakeRange(0, [input length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { if ([result numberOfRanges] > 1) { NSRange accessTokenRange = [result rangeAtIndex:1]; self.accessToken = [input substringWithRange:accessTokenRange]; NSLog(@"Access Token: %@", self.accessToken); } }]; } Here we just extract the access token using a regular expression match. Once we've set the access token, we can use it to sign future requests. We could do this by having each request add this parameter manually, or we can use AFNetworking to intercept all outgoing requests and add the parameter on the way out. Automatically adding request parameters with AFNetworking If we want to add this URL parameter to all outgoing requests, we can do so like this: -(AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)urlRequest success:(void (^)(AFHTTPRequestOperation *, id))success failure:(void (^)(AFHTTPRequestOperation *, NSError *))failure { NSMutableURLRequest *request = [urlRequest mutableCopy]; NSString *separator = [request.URL query] ? @"&" : @"?"; NSString *newURLString = [NSString stringWithFormat:@"%@%@access_token=%@", [request.URL absoluteString], separator, self.accessToken]; NSURL *newURL = [[NSURL alloc] initWithString:newURLString]; [request setURL:newURL]; return [super HTTPRequestOperationWithRequest:request success:success failure:failure]; } In a real application you might want to only do this for GET requests, but the idea is still the same.