iosobjective-ccurlgithub-apinsurlrequest

Authentication Error with GitHub API on iOS


I am working with GitHub's REST API for iOS and am having trouble getting it to work correctly with basic authentication. I have written the following code to view a users GitHub repositories:

NSString *requestString = [NSString stringWithFormat:@"https://%@:%@@api.github.com/user/repos",userName,password];
NSURL *url = [NSURL URLWithString:requestString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];

NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    NSString *strData = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@", strData);
}];
    
[dataTask resume];

I am getting the following response back:

{"message":"Requires authentication","documentation_url":"https://developer.github.com/v3"}

However when I do the following in my terminal:

curl -i GET  https://userName:password@api.github.com/user/repos

I get the expected result back from GitHub. I'm not sure what authentication I am missing for my iOS app because I don't have anything in my curl statement that I don't have in my iOS code. Any help explaining what I'm missing is greatly appreciated.


Solution

  • It seems that something in NSURLSession doesn't like the username/password encoded in the URL (and to be honest, it isn't very secure as it can be exposed in proxy logs and is also prone to problems on the server side), so you have to encode the authorisation details into the HTTP headers.

    This worked for me -

    NSString *requestString = @"https://api.github.com/user/repos";
    NSURL *url = [NSURL URLWithString:requestString];
    NSURLRequest *req = [NSURLRequest requestWithURL:url];
    
    NSData *userPasswordData = [[NSString stringWithFormat:@"%@:%@", userName, password] dataUsingEncoding:NSUTF8StringEncoding];
    NSString *base64EncodedCredential = [userPasswordData base64EncodedStringWithOptions:0];
    NSString *authString = [NSString stringWithFormat:@"Basic %@", base64EncodedCredential];
    
    NSURLSessionConfiguration *sessionConfig=[NSURLSessionConfiguration defaultSessionConfiguration];
    sessionConfig.HTTPAdditionalHeaders=@{@"Authorization":authString};
    
    self.session=[NSURLSession sessionWithConfiguration:sessionConfig];
    
    NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
        NSString *strData = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"%@", strData);
    }];
    
    [dataTask resume];