Handle TLS authentication challenges to fix Microsoft device compliance (#806)

WKWebView rejects all authentication challenges by default when
webView(_:didReceive:completionHandler:) is not implemented, using
.rejectProtectionSpace. This silently breaks TLS client-certificate
flows like Microsoft Entra ID Conditional Access, which verifies
device compliance via a certificate stored in the system keychain
by MDM enrollment.

By implementing the delegate method and returning
.performDefaultHandling, the system's standard URL-loading behaviour
takes over: the keychain is searched for matching client identities,
MDM-installed root CAs are trusted, and any configured SSO extensions
(e.g. Microsoft Enterprise SSO) can intercept the challenge.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Connor Callison 2026-03-04 15:48:18 -08:00 committed by GitHub
parent 102931d975
commit 80eca0de48
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -3081,6 +3081,24 @@ private class BrowserNavigationDelegate: NSObject, WKNavigationDelegate {
loadErrorPage(in: webView, failedURL: failedURL, error: nsError)
}
func webView(
_ webView: WKWebView,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
) {
// WKWebView rejects all authentication challenges by default when this
// delegate method is not implemented (.rejectProtectionSpace). This
// breaks TLS client-certificate flows such as Microsoft Entra ID
// Conditional Access, which verifies device compliance via a client
// certificate stored in the system keychain by MDM enrollment.
//
// By returning .performDefaultHandling the system's standard URL-loading
// behaviour takes over: the keychain is searched for matching client
// identities, MDM-installed root CAs are trusted, and any configured SSO
// extensions (e.g. Microsoft Enterprise SSO) can intercept the challenge.
completionHandler(.performDefaultHandling, nil)
}
func webView(_ webView: WKWebView, webContentProcessDidTerminate: WKWebView) {
NSLog("BrowserPanel web content process terminated, reloading")
webView.reload()