react-native-sensitive-info: hardware-backed secrets for React Native
🔐 React Native secure storage, rebuilt with Nitro Modules ⚡️ Biometric-ready, StrongBox-aware, and metadata-rich for modern mobile apps
At a glance
- What is it?
- react-native-sensitive-info stores secrets in the iOS Keychain and the Android Keystore, encrypted with AES-GCM and bound to a hardware protected key, and exposes them through a Promise API and a set of React hooks. Version 6 rebuilt the native layer on Nitro Modules, dropped Windows, and added an integrity tag that is checked before any biometric prompt appears.
- Who is it for?
- react-native-sensitive-info fits a React Native app that stores a session token or a payment credential and wants the value in hardware backed storage with a biometric gate, a metadata field that tells the app what protection it actually got, and typed errors instead of string matching.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 21 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The promise is that the value never sits in plain storage
react-native-sensitive-info is hardware-backed secure storage for React Native. Secrets are encrypted with AES-GCM, gated by biometrics or device credentials, and stored in the system Keychain on iOS or the Android Keystore, behind a Promise-based API and React hooks.
The security model is described in one dense paragraph in the README, and it is worth reading carefully because it explains the behaviour you will actually observe at runtime.
Every secret is encrypted with AES-GCM and bound to a hardware-protected key. Each entry carries an HMAC-SHA256 integrity tag that is recomputed on every read, and a mismatch raises an IntegrityViolationError before any biometric prompt fires.
That last clause is the design decision worth noticing. The integrity check happens first, so a tampered or corrupted entry is rejected without asking the user for their face or fingerprint and then failing anyway. It also means the failure mode is distinguishable: a cancelled prompt and an integrity violation are different errors, and the library ships typed predicates for exactly that, importable from react-native-sensitive-info/errors, with isAuthenticationCanceledError, isKeyInvalidatedError and isIntegrityViolationError among them.
The metadata is the other half of the story. A read returns the value and metadata, and the metadata includes a securityLevel field, with secureEnclave as an example value, which is how an app can tell whether the platform gave it the protection it asked for or a fallback.
v6 is a rewrite, and Windows is gone
The upgrade note at the top of the README is the first thing to read if you have used version 5.
Upgrading from v5? There is a migration guide in the docs folder. v6 requires the New Architecture with React Native 0.76 or newer, and it requires react-native-nitro-modules. Windows support was removed.
So this is not a minor release with new methods. The native layer has been rebuilt on Nitro Modules, which is why the installation now pulls in a second package, and the platform list has shrunk.
The practical consequence for the platform table is that React Native itself needs 0.76.0 or newer, and the New Architecture is not optional. A team that is still on the old architecture is not looking at an upgrade, it is looking at a migration with a different set of constraints.
The removal of Windows is the quieter change. It is a narrowing of scope rather than a break, and the package's own metadata reflects the new shape, with a podspec for the iOS side, a separate android/ directory, an app.plugin.js for the Expo config plugin, a nitro.json describing the Nitro specification, and a scripts/ directory that includes a release artefact verifier and a smoke test that runs as part of the release preparation.
Six platforms, with different protection on each
The platform table is short and the notes column is where the interesting information is.
React Native needs 0.76.0 or newer, with the New Architecture and react-native-nitro-modules required. iOS needs 13.0, and you add NSFaceIDUsageDescription to Info.plist if you use biometric prompts. macOS needs 11.0, through Catalyst or native macOS, using the system keychain.
visionOS needs 1.0 and is Secure Enclave-backed, with the biometric user experience adapting to visionOS. watchOS needs 7.0, with paired-device authentication and storage syncing through the watchOS keychain.
Android needs API 23, and here the note matters most: StrongBox requires API 28 or newer, and below that the library falls back to the strongest available authenticator.
That fallback is the kind of behaviour that has to be a design decision rather than an accident, and it is also the one an application developer most needs to know about. A device on API 23 or API 27 will not get a StrongBox backed key, and the securityLevel in the metadata is how you find out. Which is why the API includes getSupportedSecurityLevels for a snapshot of device capabilities, covering biometrics, Secure Enclave and StrongBox, and canUseAccessControl to check whether a given access control policy is supported on this device before you rely on it.
Installing it, and the Expo trap
Installation is a single npm command, and the second package is not optional.
npm install react-native-sensitive-info react-native-nitro-modulesThere is no manual linking step, because Nitro handles autolinking. On iOS you run pod install, and on Android you add two permissions to the manifest.
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />The Expo section is the part to read twice, because it has a warning rather than a step. Expo Go does not include native Nitro modules, so you have to use a custom development client or an EAS build. The configuration is a plugin entry in app.json followed by a prebuild, since the native code has to be generated into the project.
{
"expo": {
"plugins": ["react-native-sensitive-info"]
}
}And then the command is npx expo prebuild --clean, with the clean flag because the prebuild regenerates the native directories and stale ones cause confusing errors. There is a longer Expo walkthrough in the docs folder as well.
The API, and the key rotation that is easy to miss
The method list is a normal key-value store with some additions. setItem writes a secret using the strongest available security policy, getItem reads a secret and its metadata, and it accepts includeValue: false to skip the payload when you only want the metadata. hasItem checks existence with no biometric prompt, deleteItem removes a secret and returns true if something was deleted, getAllItems lists a service, and clearService removes every secret in a service namespace.
Then there are three methods that go beyond a key-value store. getSupportedSecurityLevels gives a snapshot of the device capabilities, canUseAccessControl checks whether a given access control policy is supported, and rotateKeys bumps the active key version, after which subsequent reads transparently re-encrypt older entries.
That last one deserves attention because it is the feature that makes long lived secrets manageable. Rotating a key without rotating every secret by hand is the difference between a rotation policy you can actually run and one you cannot.
The options are equally considered. The service option is the logical namespace and defaults to the bundle ID or default, accessControl defaults to secureEnclaveBiometry with the native layer picking the strongest supported fallback, authenticationPrompt carries the localized strings for the biometric and device credential prompts, iosSynchronizable controls iCloud Keychain sync and is false by default, and keychainGroup selects a custom Keychain access group.
The quick start shows the shape of a call, and the read returning metadata alongside the value is the point of the whole library.
Hooks for the React side, and typed errors
The hooks API is marked as recommended, and its selling point is that it handles the parts a component would otherwise get wrong.
import { setItem, getItem, deleteItem } from 'react-native-sensitive-info'
await setItem('session-token', 'abc123', { service: 'auth' })
const item = await getItem('session-token', { service: 'auth' })
console.log(item?.value)
console.log(item?.metadata.securityLevel)Six hooks are listed. useSecureStorage lists, adds and removes all the secrets in a service, with an includeValues option. useSecret fetches a single secret with read and write mutations. useHasSecret is a lightweight existence check that does not decrypt. useSecurityAvailability queries device capabilities and is auto-cached. useKeyRotation rotates the master key for a service. And useBiometryStatusWatcher subscribes to biometric enrollment state transitions, which is the one that matters when a user adds or removes a fingerprint from the system settings.
All the hooks auto-cancel in-flight requests on unmount, and the docs folder has a HOOKS.md with the advanced patterns.
The error handling is where the library is most opinionated, and it is a good sign. The errors are typed rather than strings, and you import the predicates you need from react-native-sensitive-info/errors, so a catch block can tell a user cancelling a prompt from a key that was invalidated by a biometric enrolment change, which are very different situations for an application to handle.
Editorial conclusion
react-native-sensitive-info fits a React Native app that stores a session token or a payment credential and wants the value in hardware backed storage with a biometric gate, a metadata field that tells the app what protection it actually got, and typed errors instead of string matching. It does not fit a project on the old architecture, on Windows, or on Expo Go, since v6 requires the New Architecture with React Native 0.76 or newer and react-native-nitro-modules, and Expo Go does not include native modules. Verify three things before you upgrade from v5: that you are prepared for the New Architecture and the Nitro dependency, that your target device falls back gracefully, since StrongBox needs API 28 and older devices get the strongest authenticator available instead, and that you read the migration guide, because the v5 to v6 change is described as breaking and the note in the README points to a dedicated migration document for the details.
Frequently asked questions
What do I need to install react-native-sensitive-info?
React Native 0.76 or newer with the New Architecture, plus react-native-nitro-modules, and the package itself. Run npm install react-native-sensitive-info react-native-nitro-modules, then pod install on iOS, add the biometric permissions to AndroidManifest.xml, and no manual linking is required because Nitro handles autolinking.
Does react-native-sensitive-info work with Expo Go?
No. The README warns that Expo Go does not include native Nitro modules, so you need a custom development client or an EAS build. You add the plugin to app.json and run npx expo prebuild --clean, with a longer walkthrough in the Expo documentation.
How is a secret protected on Android?
The secret is encrypted with AES-GCM and bound to a hardware-protected key, with an HMAC-SHA256 integrity tag recomputed on every read. Android support starts at API 23, but StrongBox requires API 28 or newer, and below that the library falls back to the strongest available authenticator, which the securityLevel in the returned metadata will show.
What changed between v5 and v6?
v6 requires the New Architecture with React Native 0.76 or newer and react-native-nitro-modules, and Windows support was removed. The README points to a migration guide in the docs folder, so that is the document to read before upgrading an existing application.
How do I rotate a key with react-native-sensitive-info?
There is a rotateKeys method that bumps the active key version, after which subsequent reads transparently re-encrypt the older entries, and a useKeyRotation hook for the React side. The method list also includes getSupportedSecurityLevels for a snapshot of device capabilities and canUseAccessControl to check whether a given access control policy is supported on the device.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/mcodex-react-native-sensitive-info)Was this useful?