Secrets: expo-secure-store
AsyncStorage does not encrypt data, so login tokens and other secrets must not be kept in it. The expo-secure-store module saves strings in the system's protected storage: the Keychain on iOS, and encryption with a key from the Android Keystore on Android.
Installing
In the blog project run:
npx expo install expo-secure-storeThe module works in Expo Go on a phone and in an emulator. It is not available in a browser.
Methods
| Method | What it does |
|---|---|
SecureStore.setItemAsync(key, value) | Saves a string |
SecureStore.getItemAsync(key) | Returns a string or null |
SecureStore.deleteItemAsync(key) | Removes a value |
A key may contain only Latin letters, digits and the characters ., - and _.
A module for the token
Suppose that after login the server issued a token, a string to send with every request. Create the file:
// lib/auth.ts
import * as SecureStore from 'expo-secure-store';
const KEY = 'auth_token';
export function saveToken(token: string) {
return SecureStore.setItemAsync(KEY, token);
}
export function getToken() {
return SecureStore.getItemAsync(KEY);
}
export function deleteToken() {
return SecureStore.deleteItemAsync(KEY);
}All three functions return promises, just like in AsyncStorage.
Using it on the profile screen
// app/(tabs)/profile.tsx
import { useEffect, useState } from 'react';
import { Button, Text, View } from 'react-native';
import { deleteToken, getToken, saveToken } from '@/lib/auth';
export default function Profile() {
const [token, setToken] = useState<string | null>(null);
useEffect(() => {
getToken().then(setToken);
}, []);
async function logIn() {
await saveToken('demo-token-123');
setToken('demo-token-123');
}
async function logOut() {
await deleteToken();
setToken(null);
}
return (
<View style={{ flex: 1, padding: 16, gap: 12 }}>
<Text>{token ? 'You are logged in' : 'You are not logged in'}</Text>
{token ? <Button title="Log out" onPress={logOut} /> : <Button title="Log in" onPress={logIn} />}
</View>
);
}Tap "Log in", close the app and open it again: the "Profile" tab still says "You are logged in". "Log out" removes the token from storage.
What goes where
| Data | Storage |
|---|---|
| Tokens, passwords, keys | expo-secure-store |
| Settings, drafts, cache | AsyncStorage |
| Many records with search | expo-sqlite |
Secure storage is meant for small values, about 2 KB per key, so large objects do not go there.
Common mistake
Saving the user's password to log in automatically later. Even in secure storage a password is an unnecessary risk. Keep the token the server issued: it can be revoked, and it does not unlock other services where the person uses the same password.