In certain situations where the server certificate is not configured properly, or when using self signed SSL certificates, requests validation fails with URLSession
. URLSession
provides delegate methods which can be used in situations like this and can be used as a workaround until the certificate gets fixed on the server end. We can also use manual certification validation if we want to pin to a particular certificate. To do this, we need to assign a delegate for the URLSession
object and handle the validation as shown in the snippet below.
class NetworkService: NSObject {
private lazy var opsQueue: OperationQueue = {
let q = OperationQueue.init()
q.name = "api queue"
q.qualityOfService = QualityOfService.background
return q
}()
private lazy var session: URLSession = {
return URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: opsQueue)
}()
}
extension NetworkService: URLSessionDelegate {
/// Customise server trust evaluation in case where server certificate validation fails.
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let protectionSpace: URLProtectionSpace = challenge.protectionSpace
if protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
if let trust: SecTrust = protectionSpace.serverTrust {
let cred = URLCredential(trust: trust)
completionHandler(URLSession.AuthChallengeDisposition.useCredential, cred) // Say, custom SSL, so allow
} else {
completionHandler(URLSession.AuthChallengeDisposition.performDefaultHandling, nil)
}
} else {
completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
}
}
}
Here the URLCredential
object containing the SecTrust
is passed to the completionHandler
which makes the request go through. We can also do additional validation on the URLProtectionSpace
and so on.