I'm working on an iOS app which connects to an ASP.NET Web API through Restful services. I want to use a custom delegate to handle authentication challenge. But the delegate method doesn't get called.
The http request is written in the following method within a view controller:
- (IBAction)test:(UIButton *)sender
{
//Get Bearer Token
KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"BearerToken" accessGroup:nil];
NSString *bearerToken = [keychainItem objectForKey:(__bridge id)(kSecValueData)];
//Configure request
NSURL *url = [NSURL URLWithString:@"......"]; //Replace the .... with real IP Address
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"GET"];
[request setValue:[NSString stringWithFormat:@"Bearer %@", bearerToken] forHTTPHeaderField:@"Authorization"];
//Configure session
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AuthChallengeDelegate *authChallengeDel = [[AuthChallengeDelegate alloc] init];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
delegate:authChallengeDel
delegateQueue:nil];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request];
[task resume];
}
In the AuthChallengeDelegate class, I have implemented the following method:
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
NSLog(@"%@", response);
}
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition,
NSURLCredential *credential))completionHandler
{
NSLog(@"did receive challenge method called");
NSLog(@"%@", challenge.protectionSpace.authenticationMethod);
}
The first method (didReceiveResponse) get called and the response status code is 401 with "Www-Authenticate" = Bearer in the header field. But the second method (didReceiveChallenge) is not called. Anyone here could give me an idea of why it's not called?
(I'm using Xcode 6 and simulating in iOS8)
Thanks.
There are two different challenge/response handlers in NSURLSession's delegates. The first, which you're implementing, is at the session level, and basically handles server-level authentication. From the documentation:
For session-level challenges—NSURLAuthenticationMethodNTLM, NSURLAuthenticationMethodNegotiate, NSURLAuthenticationMethodClientCertificate, or NSURLAuthenticationMethodServerTrust—the NSURLSession object calls the session delegate’s URLSession:didReceiveChallenge:completionHandler: method. If your app does not provide a session delegate method, the NSURLSession object calls the task delegate’s URLSession:task:didReceiveChallenge:completionHandler: method to handle the challenge.
For non-session-level challenges (all others), the NSURLSession object calls the session delegate’s URLSession:task:didReceiveChallenge:completionHandler: method to handle the challenge. If your app provides a session delegate and you need to handle authentication, then you must either handle the authentication at the task level or provide a task-level handler that calls the per-session handler explicitly. The session delegate’s URLSession:didReceiveChallenge:completionHandler: method is not called for non-session-level challenges.
So, you probably want to handle task-level authentication by adding protocol support for NSURLSessionTaskDelegate in your delegate object, and supplying a handler at the task level, i.e.
URLSession(_:task:didReceiveChallenge:completionHandler:)
.
From iOS developer library
Important: The URL loading system classes do not call their delegates to handle request challenges unless the server response contains a WWW-Authenticate header.
From where we understand that didReceiveChallenge
methods should be called BUT the method URLSession:task:didReceiveChallenge:completionHandler:
gets called only when the header looks like 'WWW-Authenticate':'Basic'
I haven't found any solution how to handle token based authentication where header is 'WWW-Authenticate':'Bearer'
as in question using Authentication Challenges.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With