Search code examples
iosswiftalamofirebing-api

iOS - Swift - Bing Image Search API Authentication with Alamofire


Trying to use Bing API to retrieve images in Swift, but with no success. From what I've gathered from other questions like this on stackoverflow as well as the Bing API documentation (https://onedrive.live.com/view.aspx?resid=9C9479871FBFA822!112&app=Word&authkey=!ANNnJQREB0kDC04) is that you have to send the request to the api with the Authorization header set to a base64 encoded version of your Bing API Account Key. So I tried the following:

let url = NSURL(string: Settings.bingImageApi + "&Query=" + keyword)!
let plainText = bingAPIKey.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let base64 = plainText!.base64EncodedStringWithOptions(nil)

let manager = Alamofire.Manager.sharedInstance
manager.session.configuration.HTTPAdditionalHeaders = [
  "Authorization": "Basic \(base64)"
]

manager
  .request(.POST, url, parameters: nil, encoding: .JSON)
  .responseJSON { (request, response, data, error) -> Void in
    println(response)
}

And the println(error) statement produces the following:

{ status code: 401, headers {
    "Access-Control-Allow-Credentials" = false;
    "Access-Control-Allow-Headers" = "Content-Type, Authorization, DataServiceVersion, MaxDataServiceVersion";
    "Access-Control-Allow-Methods" = "GET, POST, PUT, DELETE, OPTIONS";
    "Access-Control-Allow-Origin" = "*";
    "Access-Control-Expose-Headers" = "DataServiceVersion, MaxDataServiceVersion";
    "Access-Control-Max-Age" = 604800;
    "Content-Length" = 91;
    Date = "Thu, 16 Jul 2015 00:38:34 GMT";
    Server = "Microsoft-IIS/8.0";
    "Www-Authenticate" = "Basic Realm=\"\"";
    "X-Content-Type-Options" = nosniff;
    "X-Powered-By" = "ASP.NET";
}

Authorization usually requires username and password but in this case password is all that's needed, while username can be blank. How would I go about specifying just the password value? The problem is something either with that or something wrong the base64 encoding I believe.


Solution

  • Got it. Needed to encode the whole username:password string instead of just one value or the other. After I fixed that I was getting a 400 error (bad request), but I solved it by adding single quotes around the Query string. The final code looks like:

    let keyword = "'\(currentSearchTerm)'".stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())!
    let url = NSURL(string: Settings.bingImageApi + "&Query=" + keyword)!
    
    let credentials = ":\(Settings.bingApiKey)"
    let plainText = credentials.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
    let base64 = plainText!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
    
    let manager = Alamofire.Manager.sharedInstance
    manager.session.configuration.HTTPAdditionalHeaders = [
      "Authorization": "Basic \(base64)"
    ]
    
    manager
      .request(.POST, url, parameters: nil, encoding: .JSON)
      .responseJSON { (request, response, data, error) -> Void in
        println(data)
    }