@kavachos/expo brings KavachOS auth to React Native and Expo apps. It stores session tokens in any storage adapter you choose. AsyncStorage, SecureStore, or your own, and sends them via Authorization header rather than cookies.
Installation
npm install @kavachos/expo
# or
pnpm add @kavachos/expo
You also need a storage library. The most common choices:
npx expo install @react-native-async-storage/async-storage
# or for encrypted storage
npx expo install expo-secure-store
Setup
Wrap your app
// app/_layout.tsx (Expo Router) or App.tsx
import { KavachExpoProvider } from '@kavachos/expo';
import AsyncStorage from '@react-native-async-storage/async-storage';
export default function RootLayout() {
return (
<KavachExpoProvider
config={{
basePath: 'https://api.myapp.com/api/kavach',
storage: AsyncStorage,
}}
>
<Stack />
</KavachExpoProvider>
);
}
The storage prop accepts any object with getItem, setItem, and removeItem methods, the same interface as AsyncStorage and expo-secure-store.Use the hooks
import { useSignIn, useUser } from '@kavachos/expo';
export function LoginScreen() {
const { signIn, isLoading, error } = useSignIn();
async function handleLogin() {
const result = await signIn('user@example.com', 'password');
if (result.success) {
router.replace('/home');
}
}
return (
<View>
<Button onPress={handleLogin} disabled={isLoading} title="Sign in" />
{error && <Text>{error}</Text>}
</View>
);
}
Secure token storage
For production apps, use expo-secure-store to encrypt the session token at rest:
import * as SecureStore from 'expo-secure-store';
import { KavachExpoProvider } from '@kavachos/expo';
const secureStorage = {
getItem: (key: string) => SecureStore.getItemAsync(key),
setItem: (key: string, value: string) => SecureStore.setItemAsync(key, value),
removeItem: (key: string) => SecureStore.deleteItemAsync(key),
};
<KavachExpoProvider config={{ basePath: '...', storage: secureStorage }}>
{children}
</KavachExpoProvider>
OAuth (deep link redirect)
For OAuth flows in Expo, use the oauth-proxy plugin on your server alongside Linking.openURL on the client:
import { Linking } from 'react-native';
async function signInWithGitHub() {
const authUrl = 'https://api.myapp.com/api/kavach/auth/oauth/github/authorize';
await Linking.openURL(authUrl);
// Handle the redirect via Linking.addEventListener or expo-linking
}
Hooks reference
useSession
const { session, isLoading, refresh } = useSession();
useUser
const { user, isLoading, isAuthenticated } = useUser();
useSignIn
const { signIn, isLoading, error } = useSignIn();
const result = await signIn(email, password);
useSignUp
const { signUp, isLoading, error } = useSignUp();
const result = await signUp(email, password, name);
useSignOut
const { signOut } = useSignOut();
await signOut(); // clears stored token and calls server sign-out
useAgents
const { agents, create, revoke, rotate, isLoading, error } = useAgents(basePath);
Manages agent identity records for the current user. Requires the full base URL (same as the provider config).
KavachExpoConfig
| Field | Type | Description |
|---|
basePath | string | Full URL to your KavachOS mount point |
storage | KavachStorage? | Token persistence adapter. Defaults to in-memory |
The default in-memory storage loses the session when the app restarts. Always pass a real storage adapter in production.