Authentication Challenge

Hey everyone.

I would like to make an authentication challenge to the browser (Safari) to allow users log in my application.

What I am doing actually in my API is to save a cookie in the browser to persist session. Is it possible to request the cookie from my app?

Thank you in advance
Answered by Systems Engineer in 628273022
It looks like there are two questions here so I will address each separately:

I would like to make an authentication challenge to the browser (Safari) to allow users log in my application.

For web based client authentication challenges, HTTP Basic or Client Certificate, in a native app you could look at using WKWebView. For example, the following is certainly not exhaustive but should get you going:

Code Block swift
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
/* Evaluate Server Trust etc.. */
}
else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic {
/* HTTP Basic */
}
else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate {
/* Client Certificate */
}
else {
/* Default fallback */
completionHandler(.performDefaultHandling, nil)
}
}


What I am doing actually in my API is to save a cookie in the browser to persist
session. Is it possible to request the cookie from my app?

Depending upon your use case here, ASWebAuthenticationSession might be what you are looking for with first party cookies, or better yet, a token based authentication mechanism.

Take a look at an example of using ASWebAuthenticationSession in the documentation here.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Accepted Answer
It looks like there are two questions here so I will address each separately:

I would like to make an authentication challenge to the browser (Safari) to allow users log in my application.

For web based client authentication challenges, HTTP Basic or Client Certificate, in a native app you could look at using WKWebView. For example, the following is certainly not exhaustive but should get you going:

Code Block swift
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
/* Evaluate Server Trust etc.. */
}
else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic {
/* HTTP Basic */
}
else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate {
/* Client Certificate */
}
else {
/* Default fallback */
completionHandler(.performDefaultHandling, nil)
}
}


What I am doing actually in my API is to save a cookie in the browser to persist
session. Is it possible to request the cookie from my app?

Depending upon your use case here, ASWebAuthenticationSession might be what you are looking for with first party cookies, or better yet, a token based authentication mechanism.

Take a look at an example of using ASWebAuthenticationSession in the documentation here.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Thank you for your answer, I think I understand.

In my case, what my login needs to use is a client certificate that I have previously installed on the device, so I guess maybe I can access it from the web view to perform the authentication. There is any way I can get the response directly from my web view method code?

what my login needs to use is a client certificate that I have previously installed on the device, so I guess maybe I can access it from the web view to perform the authentication.

Keep in mind that you will need access to a Digital Identity here (PKCS#12 / p12) to build your URLCredential, with your loaded certificate, to perform client authentication. Something like that might look like:

Code Block swift
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate {
// Load an identity here that contains your leaf certificate and an array of certificates
// that builds a chain of trust from the leaf to the root.
// NOTE: Every server is different and may not require the intermediate or root certificates.
//
//
//let identity = < Load identity here, could be from a P12 etc... >
//let certArrayFromKeychain = getCertArrayFromKeychain()
//let credential = URLCredential(identity: identity,
// certificates: [certArrayFromKeychain], persistence: .forSession)
//completionHandler(.useCredential, credential)
}


There is any way I can get the response directly from my web view method code?
Yes, for viewing the response, checkout:

Code Block swift
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
}



Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Thank you for your reply once again Matt.

I think the solution is pretty close.

I have the PKCS#12/p12 Digital Identity already installed on my device (as a profile).

Can I access it through getCertArrayFromKeychain()?. If this is possible, what would be the code of this function, or how can I access that Digital Identity?

I am already doing it obtaining the Digital Identity directly from the assets of my project, but I need to do this for every user that wants to use the app (needs to be dynamic, not static), so I need to access that profile installed on the device. This is the code I actually used to do it.

Code Block
let pathToCert = Bundle.main.path(forResource: "aLosada7", ofType: "p12")
let localCertificate = NSData(contentsOfFile: pathToCert! )!
let options = [String(kSecImportExportPassphrase):"yourpassword"]
var items: CFArray? = nil
let result = SecPKCS12Import(localCertificate, options as CFDictionary, &items)
if (result != errSecSuccess) {
print(result)
}
let info = (items! as NSArray).firstObject! as! NSDictionary
let identity = info[String(kSecImportItemIdentity)] as! SecIdentity
let credentials = URLCredential(identity: identity, certificates: nil, persistence: .forSession)


Thank you once again for your time. I really appreciate it so much.

Authentication Challenge
 
 
Q