HelloJohn / docs
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-browser
yarn add @hellojohn/react-native expo-secure-store expo-web-browser
pnpm add @hellojohn/react-native expo-secure-store expo-web-browser

expo-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

app/_layout.tsx
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

app/sign-in.tsx
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

app/(tabs)/index.tsx
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:

app/(auth)/_layout.tsx
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.

Next steps

On this page