Learn React Native - Secure Storage & Credentials
Episode 13 of 23

Learn React Native - Secure Storage & Credentials

This episode covers credential security: Keychain and Keystore for tokens, why AsyncStorage isn't enough, per-build .env configuration with react-native-config, and habits that keep secrets out of the bundle and the repository.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Login tokens and credentials are the keys to your app's house. If a token falls into the wrong hands, all user data can be stolen. In episode 9 you stored ordinary data; now it's time to handle data that must not leak.

Episode 13 covers secure storage: Keychain on iOS and Keystore on Android for storing tokens, why AsyncStorage isn't the right choice for sensitive data, per-build .env configuration, and habits that keep secrets from ever being committed to the repository.

Keychain and Keystore

Installing react-native-keychain

Keychain (iOS) and Keystore (Android) are credential stores protected by hardware and biometrics. The react-native-keychain library unifies both:

Install react-native-keychain
npm install react-native-keychain

Storing and Reading Tokens

JSStoring a token in Keychain
import * as Keychain from "react-native-keychain";
 
async function simpanToken(token) {
  await Keychain.setGenericPassword("auth", token, {
    service: "com.example.myapp",
  });
}
 
async function bacaToken() {
  const kredensial = await Keychain.getGenericPassword();
  return kredensial ? kredensial.password : null;
}

setGenericPassword("auth", token) stores a generic username and password. In practice, the username field can hold the user identity and the password field the token. The data is stored in the device's secure storage, not in an ordinary app file.

Why Not AsyncStorage

AsyncStorage stores data as a plain text file that anyone with device or backup access can read. Tokens must not go there. Secure storage uses encryption and restricted system access — that's the right place for credentials.

Keeping Secrets Out of the Bundle

What Is a Bundle

At release, React Native packages JavaScript into a single bundle file included in the app. Anyone can unpack an APK or IPA and read the bundle. That means API keys and secrets written as strings in code are automatically exposed.

No Matter How Secure the Storage, the Bundle Remains Readable

Even values in .env injected at build time can be found in the bundle after unpacking. Understand the security level: .env and react-native-config protect secrets from the repository, not from reverse engineering. Truly sensitive secrets — server keys, signing secrets — must never be in a client app.

Env and Build Config

.env per Environment

To distinguish staging and production configuration, create a separate .env file per environment:

Env file structure
.env.example
.env.development
.env.staging
.env.production

.env.example contains placeholders without real values and is the only env file allowed to be committed.

Reading Configuration with react-native-config

react-native-config reads the env file at build time and injects its values into the app:

Install react-native-config
npm install react-native-config
JSReading configuration
import Config from "react-native-config";
 
export const API_URL = Config.API_URL;
export const SENTRY_DSN = Config.SENTRY_DSN;

Choosing the Env at Build Time

Select the env file via the ENVFILE variable when running an Android build:

Android build with staging env
cd android
ENVFILE=.env.staging ./gradlew assembleRelease

The command above produces a release APK that uses values from .env.staging. For Expo projects, environment selection is done through EAS Build profiles in eas.json.

Habits That Keep Secrets from Leaking

.gitignore for All Envs

Exclude all env files from git, except the example:

Rules in .gitignore
.env
.env.*
!.env.example

The first line ignores all env files, and the third line un-ignores .env.example so it stays committed as documentation.

Audit and Rotation

If a secret was ever committed, consider it already leaked — rotate immediately. Make secret scanning part of code review and the pipeline: scan the repository with secret-detection tools before merging. Episode 14 will discuss reverse engineering mitigation further.

Warning

A committed secret can't be considered safe just because it was removed in the next commit. Git history keeps it forever. Rotating the credential is the only correct fix.

Closing

Episode 13 secured credentials: tokens stored in Keychain and Keystore instead of AsyncStorage, secrets assumed exposed in the bundle, .env per build separating configuration, and .gitignore preventing secrets from entering the repository.

Key takeaways:

  • Keychain and Keystore are the right place for tokens.
  • AsyncStorage is not secure for sensitive data.
  • App bundles can be unpacked; secrets in code are considered public.
  • .env per environment separates staging and production configuration.
  • Only .env.example may be committed.
  • Any leaked secret must be rotated.

In the next episode, episode 14, we'll discuss network security and TLS: the Android network security config, App Transport Security on iOS, certificate pinning, plus reverse engineering mitigation and app hardening.

Learn React Native - Secure Storage & Credentials | Learn React Native