We're developing our first App Clip, and having issues with accessing the keychain. At the moment, we've been running the App Clip from Xcode with the environment variable, _XCAppClipURL
, set to a URL the app clip responds to.
This is the failing call:
var addquery: [CFString: Any] = [ kSecClass: kSecClassGenericPassword,
kSecAttrLabel: "secretKey",
kSecAttrAccount: userID]
if let accessGroup = accessGroup {
addquery[kSecAttrAccessGroup] = accessGroup
}
SecItemDelete(addquery as CFDictionary)
addquery[kSecAttrAccessible] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
addquery[kSecUseDataProtectionKeychain] = true
addquery[kSecValueData] = key
let status = SecItemAdd(addquery as CFDictionary, nil)
guard status == errSecSuccess else {
throw MercuryError(message: "Failed storing db encryption key: \(status)")
}
The status that is reported has the value -34018, which I haven't tried to compare to the massive list of constants.
The trouble seems to be kSecAttrAccessGroup
, to which we're our App Group value, e.g. group.com.bundle.different.string
as shown below. Both full app and clip belong to this group.
We've also tried setting kSecAttrAccessGroup
to the keychain access group setup for the full app, but we can't seem to add a keychain sharing entitlement to the app clip... at least not in the UI. So we're unsure if setting the param to this is supposed to work in this case.
If instead we avoid setting kSecAttrAccessGroup
altogether, the call to SecItemAdd
succeeds in the App Clip. The full app seems to be able to later access the stored key. But this is less safe, right? Given that previous versions of the full app are currently using the App Group for this call, changing it would be a disruption for our users.
For completeness, the full app works with the app group passed in or not as always.
Setup Stuff
- Full App Bundle ID is something like:
com.bundle.ident
- App Clip has the default suffix added:
com.bundle.ident.Clip
App Clip Entitlements:
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>webcredentials:domain.com?mode=developer</string>
<string>webcredentials:domain2.com?mode=developer</string>
<string>applinks:domain.com?mode=developer</string>
<string>applinks:domain2.com?mode=developer</string>
</array>
<key>com.apple.developer.parent-application-identifiers</key>
<array>
<string>$(AppIdentifierPrefix)com.bundle.ident</string>
</array>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.bundle.different.string</string>
</array>
</dict>
I don't seem to be able to add the keychain-access-groups
key to this one, but, given that we're scoping the keychain access to the App Group, it shouldn't matter(?).
Relevant Full App Entitlements:
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>webcredentials:domain.com?mode=developer</string>
<string>webcredentials:domain2.com?mode=developer</string>
<string>applinks:domain.com?mode=developer</string>
<string>applinks:domain2.com?mode=developer</string>
</array>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.bundle.different.string</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.bundle.third.string</string>
</array>
</dict>
What's missing here is the com.apple.developer.associated-appclip-app-identifiers
, but I understand that's added automatically when I archive, so that it shouldn't be relevant here.