Installation
Add the package to a bare React Native app or an Expo app, set up what biometrics needs, and check that it works.
The package is a regular native library: a TurboModule that autolinking picks up in a bare app and in an Expo app with a dev build. On Android there is nothing to configure; on iOS, biometrics needs one line in Info.plist.
Requirements
- 0.80 or newer.
- The New Architecture only.
- iOS 15.1 or newer, the minimum of React Native.
- iPadOS and Mac Catalyst too.
- minSdk 24 or higher.
- The passcode options need Android 11 (API 30).
- SDK 54 or newer.
- A dev build, EAS Build or prebuild; not Expo Go.
Two ways to add it
npm install @apexnative/keychainExpoAn Expo appInstall the package and add its config plugin; prebuild writes the native settings.npx expo install @apexnative/keychainA bare app
Add the package:
$ npm install @apexnative/keychainInstall the pods:
cd ios && pod install
The pod links Security and LocalAuthentication, which are part of the iOS SDK. On Android the package brings androidx.biometric 1.1.0 as its own Gradle dependency, and the prompt uses the app's ReactActivity; there is nothing to add to the manifest.
Face ID description
If any item uses an accessControl with biometrics, iOS needs to tell the user why the app asks for Face ID. Add NSFaceIDUsageDescription to ios/<App>/Info.plist:
<key>NSFaceIDUsageDescription</key>
<string>Face ID unlocks your account without a password.</string>
Without it, on a device with Face ID, a write or a read of an item with biometrics, and canUseAccessControl for it, fail with MISSING_USAGE_DESCRIPTION instead of crashing the app.
Optional settings
| Setting | Where | What it does |
|---|---|---|
ApexKeychainClearOnReinstall = YES | Info.plist | Removes the package's items on the first run after a reinstall. See Reinstalls. |
| Keychain Sharing capability | Xcode, Signing & Capabilities | Adds the keychain-access-groups entitlement that an accessGroup needs. See Sharing between apps. |
Rebuild the app after changing Info.plist or the entitlements:
npx react-native run-ios
npx react-native run-android
An Expo app
Add the package:
npx expo install @apexnative/keychain
Add the config plugin to app.json. On prebuild it writes NSFaceIDUsageDescription, and, when you ask for them, ApexKeychainClearOnReinstall and the keychain-access-groups entitlement; Android needs nothing.
{
"expo": {
"plugins": [
[
"@apexnative/keychain",
{
"faceIDPermission": "Face ID unlocks your account without a password.",
"clearOnReinstall": true,
"accessGroups": ["com.example.shared"]
}
]
]
}
}
Every option is optional. Without faceIDPermission, the plugin writes a default Face ID text; accessGroups take the group without the team prefix, which the plugin adds. Config plugin has every option. Then build the app with its native code:
npx expo prebuild
npx expo run:ios
npx expo run:android
EAS Build runs prebuild for you: eas build with the plugin in app.json is enough.
Expo Go
Expo Go ships with a fixed set of native modules, and this package isn't one of them. In Expo Go the import works, and the first call throws UNSUPPORTED with a message that says a development build is needed, rather than Cannot read property … of null. Use a development build.
Check the setup
A round trip through the default keychain shows that the native module is linked:
import { AccessControl, canUseAccessControl, keychain } from '@apexnative/keychain';
await keychain.setItem('setup-check', 'ok');
console.log(await keychain.getItem('setup-check')); // 'ok'
await keychain.removeItem('setup-check');
// Whether this device can lock an item behind the biometrics enrolled today.
console.log(await canUseAccessControl(AccessControl.BiometryCurrentSet));
// { available: true } or { available: false, reason: 'notEnrolled' }
Tests and the web
On the web every method throws UNSUPPORTED: browsers have no keychain to put a secret in. For Jest, the package has an in-memory mock with the same validation at @apexnative/keychain/jest; Testing sets it up.