Common pitfalls when using Keychain Sharing on iOS

Jan 16 2020 11:00 AM

DISCLAIMER: this is not a tutorial on how to use the Keychain or Keychain Sharing.

I am a huge fan of app extensions, since they allow us to expose our app’s functionality to other parts of the system without requiring the user to necessarily launch the app if they want to get something done quickly.

Eventually, when you’re working on an app that requires some sort of authentication or stores any type of sensitive data, you’ll have to use the Keychain. If you want to be able to access those Keychain items in your app extensions, you are going to have to enable the “Keychain Sharing” capability in your project’s code signing settings.

Seems simple enough, just check a box and be done. Right? Right? Well, not quite.

That’s a problem with the “Signing & Capabilities” pane in Xcode: it is very easy to add and edit capabilities, but there’s very little information about how to actually use those capabilities in your code. I feel like every capability should come with a “Learn More” link that takes you to extensive documentation about what it does and some sample code, but I digress.

adding the keychain capability

Here are some of the common issues I’ve found while working with Keychain Sharing and their respective solutions.

Group name incorrect

When you add the Keychain Sharing capability, you can add different group names to the list, and a default one is also created for you. You might be tempted to just copy that name verbatim and paste it in your code, but oftentimes when you do that, it just doesn’t work.

What I found is that for some weird reason, you have to include the team ID prefix in code when referring to a Keychain Sharing group. Just in case you don’t know what I’m talking about, that’s the code you see below your name in the developer portal.

A simple way to check what the “full name” of your keychain group is would be to run jtool on the final binary. I often use it to make sure my entitlements are the way I expect them to be.

checking entitlements with jtool

So in my example, instead of using codes.rambo.KeychainDemo in code, I’d use 8C7439RJLG.codes.rambo.KeychainDemo.

Simulator

I’m not a fan of the iOS Simulator, unless we’re talking about quick tests on different device sizes or taking screenshots for the App Store. There are just way too many features that don’t work properly in the Simulator, or that behave differently from real-world devices. One of them is Keychain Sharing. So if you’re using Keychain Sharing, forget about using the Simulator.

Confusion

I’ve made this mistake before, so I thought it’d be a good idea to include a warning about it here. There is a separate, unrelated type of entitlement which is called “App Groups”.

An App Group lets you share preferences and other things with extensions and other apps from the same developer, but it does not add any keychain-related functionality. So be careful not to confuse the two.

Keychain items that won’t go away

When you delete an app that uses Keychain Sharing from a device, if there’s another app that includes that group, the items won’t be deleted. Even after you delete the last app from the group, they won’t be deleted immediately.

So if you need to test with a fresh keychain, I suggest adding a debug flag to your app that allows you to wipe the keychain group during development.

Capabilities are configured per-target

If you want to share your keychain items between an app and an extension, don’t forget that your app extension is a separate target from your main app. That means you need to go into your project settings, select your extension target and add the same Keychain Sharing group capability to the extension, otherwise it won’t have access to the shared items.

Oh, by the way, only executable targets such as apps and app extensions have entitlements, so even if you’re implementing your keychain code in a separate target, such as a framework, the capability needs to be added to the targets that are linking against that framework.

Debugging tip

Frequently when trying to use a system API, you’re going to come across error messages that are not very helpful since they don’t say much about the underlying problem that’s going on.

A simple debugging trick that’s helped me countless times in those situations is to use Console. Launch the Console app on your Mac, select your iOS device on the sidebar, enable info and debug messages in the “Action” menu and use the search bar to filter for a keyword related to what you’re trying to debug, such as “keychain”.

Below is an example of what happens if an app extension tries to save an item to the Keychain specifying a group that it doesn’t have the entitlement for. As you can see, the message is very clear about what’s wrong:

debugging with Console

This was just a brain dump of the pitfalls I’ve found while working with Keychain Sharing on iOS. If you have anything to add, feel free to reach me out on Twitter.

App identifier (added on 01/16/20)

Patrick shared an excellent insight about a quirk with the Keychain Sharing entitlement which doesn't happen with any other type of capability:

If you're not sure about what he means by "app-specific ID", he's talking about the way app IDs used to work before there was a single team ID prefix shared by all apps from the same development team. I'm not sure when this changed, but a long time ago each app would have its own bundle ID prefix. So if you are the developer of one of these "legacy" apps, you won't be able to use keychain sharing between separate apps because the app ID prefix will be different between them.

Sharing between app groups (added on 01/16/20)

As noted by @KhaosT, it is now possible to use an App Group to also share keychain items. This is explained on this document by Apple. As explained in the document, you should still use a Keychain Sharing group if you only intend to share keychain items.