How to send HTTPS POST request in swift using NSURLSession

5.7k views Asked by At

I've been developing using HTTP. The code below works great when connecting with the development server using HTTP. However, when I change the scheme to https, it doesn't send a successful https post to the server.

What else do I need to do to switch from HTTP POST to HTTPS POST?

class func loginRemote(successHandler:()->(), errorHandler:(String)->()) {

    let user = User.sharedInstance

    // this is where I've been changing the scheme to https
    url = NSURL(String: "http://url.to/login.page") 

    let request = NSMutableURLRequest(URL: url)

    let bodyData = "email=\(user.email)&password=\(user.password)"
    request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);

    request.HTTPMethod = "POST"

    let session = NSURLSession.sharedSession()

    // posting login request
    let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
        if let httpResponse = response as? NSHTTPURLResponse {
            if httpResponse.statusCode == 200 {
                // email+password were good

                successHandler()                    

            } else {
                // email+password were bad
                errorHandler("Status: \(httpResponse.statusCode) and Response: \(httpResponse)")
            }
        } else {
            NSLog("Unwrapping NSHTTPResponse failed")
        }
    })

    task.resume()
}
1

There are 1 answers

3
keithbhunter On

You will have to implement one of the NSURLSessionDelegate methods so that it will accept the SSL certificate.

class YourClass: Superclass, NSURLSessionDelegate {

    class func loginRemote(successHandler:()->(), errorHandler:(String)->()) {
        // ...
        let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), 
                                   delegate: self, 
                                   delegateQueue: nil)
        // ...
    }

    func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential!) -> Void) {
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            let credential = NSURLCredential(trust: challenge.protectionSpace.serverTrust)
            completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, credential)
        }
    }

}

WARNING: This will blindly accept any SSL certificate/connection that you attempt. This is not a safe practice, but it will allow you to test your server using HTTPS.

UPDATE: Swift 4+

class YourClass: Superclass, URLSessionDelegate {

    class func loginRemote(successHandler: ()->(), errorHandler:(String)->()) {
        // ...
        let session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
        // ...
    }

    func urlSession(_ session: URLSession, didReceiveChallenge challenge: URLAuthenticationChallenge, completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            if let trust = challenge.protectionSpace.serverTrust {
                completionHandler(.useCredential, URLCredential(trust: trust))
            }
        }
    }

}