Storing an auth token in plain AsyncStorage is a common security mistake — anyone with device access or a backup can read it. expo-secure-store encrypts small secrets using the iOS Keychain and Android Keystore, which is why it's the most-searched module for handling tokens in Expo. Here's how to use it.
Install
npx expo install expo-secure-store
Set, get, and delete a secret
The whole API is three async functions:
import * as SecureStore from "expo-secure-store"
// Save
await SecureStore.setItemAsync("session_token", "eyJhbGciOi...")
// Read (returns null if missing)
const token = await SecureStore.getItemAsync("session_token")
// Remove (e.g. on logout)
await SecureStore.deleteItemAsync("session_token")
Require device authentication
Gate a secret behind Face ID / Touch ID / device passcode:
await SecureStore.setItemAsync("private_key", value, {
requireAuthentication: true,
keychainAccessible: SecureStore.WHEN_UNLOCKED,
})
Now reading private_key prompts for biometrics before it resolves.
A practical auth pattern
Wrap SecureStore in a tiny session helper you can reuse across your app:
import * as SecureStore from "expo-secure-store"
const KEY = "session_token"
export const session = {
save: (token: string) => SecureStore.setItemAsync(KEY, token),
get: () => SecureStore.getItemAsync(KEY),
clear: () => SecureStore.deleteItemAsync(KEY),
}
On app launch, call session.get() to decide whether to show the app or the sign-in screen. This pairs directly with the Expo authentication guide.
Gotchas
- Small values only — roughly a 2KB limit per entry. Keep large data in expo-file-system or expo-sqlite.
- No web support — guard platform-specific code, or use a web fallback for universal apps.
- Keys must be alphanumeric (plus
.,-,_). - Deleting the app clears the store, so don't treat it as permanent server-side state.
Next steps
SecureStore is the storage half of auth — read the full how to add authentication to an Expo app guide next, and see where it fits among the top 10 Expo SDK modules.