Client Certificate Handling on iOS

Client Certificate Handling on iOS


2 min read

Client Certificate Authentication, a.k.a. mutual certificate-based authentication, means that the client provides its Client Certificate to the server to prove its identity. This happens as a part of the SSL Handshake (optional).

How Mutal Authentication Works

Users can install digital identities (certificates plus their associated private keys) onto their iOS devices by downloading them from within Safari, by opening them as email attachments, and by installing them with configuration profiles (MDM!).

Once done the SafariViewController or the Safari app can open the page successfully because the certificate is in the Apple keychain access group.

BUT your apps using URLSession or WKWebView will receive an HTTP 400 response because of a missing client certificate ?!?!

That's because ...

Apps can only access keychain items in their own keychain access groups. This means that items in the Apple access group are only available to Apple-provided apps such as Safari or Mail.

The solution is

... you will need to write code to import them. This typically means reading in a PKCS#12-formatted blob and then importing the contents of the blob into the app's keychain using the function SecPKCS12Import documented in Certificate, Key, and Trust Services Reference.

This way, your new keychain items are created with your app's keychain access group.

This statement comes from Apple.

Additional work is needed.

I created an iOS application to demonstrate all this better. Use this app to access in various ways

  • URLSession.dataTask
  • WKWebView
  • SFSafariViewController
  • Open link in Safari

The website requires a valid user certificate. Otherwise the server returns HTTP 400.

I added (downloaded from as a bundle resource for convenience. This allows you to test the successful authentication with a user certificate using URLSession and WKWebView.

Note: If the certificate no longer works (expires Dec 4, 2023), try to download the latest version from

The source code of the app is publicly available on GitHub.

Did you find this article valuable?

Support Marco Eidinger by becoming a sponsor. Any amount is appreciated!