Reputation: 13
I am trying to retrieve JSON from my app's server which needs a user/password authentication. Does anyone know why I am not being allowed entry into the server? I tried including an authorization header with the credentials needed but still get this error.
func retrieveJSON(){
let login = "[email protected]"
let password = "password"
let url = NSURL(string: "http://server/admin/data.json")
let request = NSMutableURLRequest(url: url! as URL)
let config = URLSessionConfiguration.default
let userPasswordString = "\(login):\(password)"
let userPasswordData = userPasswordString.data(using: String.Encoding.utf8)
let base64EncodedCredential = userPasswordData!.base64EncodedString()
let authString = "Basic \(base64EncodedCredential)"
config.httpAdditionalHeaders = ["Authorization" : authString]
let session = URLSession(configuration: config)
let task = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
debugPrint(response)
}
task.resume()
}
Response message with 401 error
Upvotes: 0
Views: 1674
Reputation: 437372
Your web site does not appear to be using “basic” auth. It would appear to be using some different authentication scheme, which we cannot determine from an image of the HTML login page.
If it were using “Basic” auth (which it likely is not in your particular case), you could simplify the code a bit, removing NSURL
, NSMutableURLRequest
, the casts, etc. Also, if you’re going to create a URLSession
, you will want to finishTasksAndInvalidate
:
func retrieveJSON() {
let login = "[email protected]"
let password = "password"
let url = URL(string: "http://server/admin/data.json")!
let request = URLRequest(url: url) // use `var` if you really need it to be mutable
let config = URLSessionConfiguration.default
let base64EncodedCredential = (login + ":" + password)
.data(using: .utf8)!
.base64EncodedString()
config.httpAdditionalHeaders = ["Authorization": "Basic " + base64EncodedCredential]
let session = URLSession(configuration: config)
let task = session.dataTask(with: request) { data, response, error in
debugPrint(response ?? "No response")
}
task.resume()
session.finishTasksAndInvalidate()
}
Alternatively, rather than building the Authorization
header yourself, you can call CFHTTPMessageAddAuthentication
to add authentication headers to a request. And, as an aside, adding the authentication to the request itself, you don’t have to create your own URLSession
, but can use the shared instance.
func retrieveJSON() {
let login = "[email protected]"
let password = "password"
let url = URL(string: "http://server/admin/data.json")!
var request = URLRequest(url: url)
request.updateBasicAuth(for: login, password: password)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
debugPrint(response ?? "No response")
}
task.resume()
}
Where
extension URLRequest {
/// Update request for HTTP authentication
///
/// - parameter username: The username
/// - parameter password: The password
/// - parameter authentication: The type of authentication to be applied
mutating func updateBasicAuth(for username: String, password: String, authentication: String = kCFHTTPAuthenticationSchemeBasic as String) {
let message = CFHTTPMessageCreateRequest(kCFAllocatorDefault, httpMethod! as CFString, url! as CFURL, kCFHTTPVersion1_1).takeRetainedValue()
if !CFHTTPMessageAddAuthentication(message, nil, username as CFString, password as CFString, authentication as CFString?, false) {
print("authentication not added")
}
if let authorizationString = CFHTTPMessageCopyHeaderFieldValue(message, "Authorization" as CFString)?.takeRetainedValue() {
setValue(authorizationString as String, forHTTPHeaderField: "Authorization")
} else {
print("didn't find authentication header")
}
}
}
But refinements to the “Basic” authentication are somewhat academic if your server is using a different authentication scheme.
Upvotes: 1