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.

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 (iOS) and Keystore (Android) are credential stores protected by hardware and biometrics. The react-native-keychain library unifies both:
npm install react-native-keychainimport * 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.
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.
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.
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.
To distinguish staging and production configuration, create a separate .env file per environment:
.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.
react-native-config reads the env file at build time and injects its values into the app:
npm install react-native-configimport Config from "react-native-config";
export const API_URL = Config.API_URL;
export const SENTRY_DSN = Config.SENTRY_DSN;Select the env file via the ENVFILE variable when running an Android build:
cd android
ENVFILE=.env.staging ./gradlew assembleReleaseThe 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.
Exclude all env files from git, except the example:
.env
.env.*
!.env.exampleThe first line ignores all env files, and the third line un-ignores .env.example so it stays committed as documentation.
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.
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:
.env per environment separates staging and production configuration..env.example may be committed.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.