Quickstart
Quickstart — React Native
Add HelloJohn authentication to your React Native app with Expo. Sign in, protect screens, and manage sessions with the useAuth hook.
Time: ~15 minutes Prerequisites: A HelloJohn account (Cloud) or a self-hosted server running locally. An Expo project (SDK 49+).
Install the SDK
npm install @hellojohn/react-native expo-secure-store expo-web-browseryarn add @hellojohn/react-native expo-secure-store expo-web-browserpnpm add @hellojohn/react-native expo-secure-store expo-web-browserexpo-secure-store is used to persist the session token securely. expo-web-browser handles OAuth redirects. Run npx expo install after to ensure compatible versions.
Wrap your app with HelloJohnProvider
import { HelloJohnProvider } from '@hellojohn/react-native'
import { Slot } from 'expo-router'
export default function RootLayout() {
return (
<HelloJohnProvider publishableKey="pk_live_XXXXXXXXXXXXXXXX">
<Slot />
</HelloJohnProvider>
)
}Add a sign-in screen
import { SignIn } from '@hellojohn/react-native'
import { View, StyleSheet } from 'react-native'
export default function SignInScreen() {
return (
<View style={styles.container}>
<SignIn redirectUrl="/(tabs)" />
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 24,
},
})Protect screens with useAuth
import { useAuth } from '@hellojohn/react-native'
import { useRouter } from 'expo-router'
import { useEffect } from 'react'
import { Text, View, Button } from 'react-native'
export default function HomeScreen() {
const { isSignedIn, user, signOut } = useAuth()
const router = useRouter()
useEffect(() => {
if (!isSignedIn) {
router.replace('/sign-in')
}
}, [isSignedIn])
if (!isSignedIn) return null
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Welcome, {user?.name}!</Text>
<Button title="Sign out" onPress={signOut} />
</View>
)
}Use the auth guard with Expo Router
For Expo Router v3+, add a root layout guard using the (auth) group pattern:
import { useAuth } from '@hellojohn/react-native'
import { Redirect, Stack } from 'expo-router'
export default function AuthLayout() {
const { isSignedIn } = useAuth()
if (!isSignedIn) {
return <Redirect href="/sign-in" />
}
return <Stack />
}Token storage
Tokens are stored using expo-secure-store, which uses the device's secure enclave (Keychain on iOS, Keystore on Android). Tokens are never stored in plaintext.
On web (Expo for Web), the SDK falls back to localStorage with a warning.