This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.

Using Clerk

Edit page

Learn how to add Clerk authentication and user management in your Expo and React Native projects.

Android
iOS
Web

Clerk is an authentication and user management platform that provides sign-up, sign-in, multi-factor authentication, social sign-in, organizations, and a hosted user database. The @clerk/expo SDK gives you React hooks, control components, hosted authentication, and prebuilt native UI components that render with Jetpack Compose on Android and SwiftUI on iOS.

This guide shows you how to install @clerk/expo, wrap your app in <ClerkProvider>, and choose the integration approach that fits your project. It targets @clerk/expo 4.x, which supports Expo SDK 54 and later.

Choose your integration approach

@clerk/expo supports three approaches. Pick the one that matches your needs. You can change later without rewriting your app.

ApproachWhat you buildRuns in Expo GoBest for
Hosted authenticationA button that opens Clerk's Account Portal in a browser authentication sessionThe fastest setup, with every method enabled in your dashboard
Native UI componentsDrop in <AuthView />, <UserButton />, and <UserProfileView /> from @clerk/expo/nativeA complete native sign-in and account management UI
Custom flowYour own React Native screens that call hooks such as useSignUp() and useSignIn()Maximum UI control

Prerequisites

Prerequisites

4 requirements

1.

Create a Clerk account and application

Sign up at the Clerk Dashboard and create an application.

2.

Enable the Native API

Open the Native applications page in the Clerk Dashboard and ensure Native API is on. This is required for any Expo integration that uses @clerk/expo.

3.

Use Expo SDK 53 or later

@clerk/expo Core 3 has a peer dependency of expo: >=53 <56.

4.

Use a development build for native features

The native UI components and the native sign-in hooks require a development build. The hosted authentication and custom flow approaches also work in Expo Go.

Install and configure Clerk

1

Install @clerk/expo and expo-secure-store

Use npx expo install so versions match your Expo SDK:

Terminal
npx expo install @clerk/expo expo-secure-store

expo-secure-store is a peer dependency. Clerk uses it through @clerk/expo/token-cache to encrypt session tokens with the iOS Keychain and the Android Keystore.

For hosted authentication, also install the packages Clerk uses to open the browser authentication session:

Terminal
npx expo install expo-auth-session expo-crypto expo-web-browser

If you plan to add native Sign in with Google buttons to a custom flow, install @clerk/expo-google-signin and expo-crypto:

Terminal
npx expo install @clerk/expo-google-signin expo-crypto

For native Sign in with Apple buttons, install both expo-apple-authentication and expo-crypto:

Terminal
npx expo install expo-apple-authentication expo-crypto

You do not need any of these extra packages if you only use <AuthView /> from @clerk/expo/native, since the component handles social sign-in flows internally.

2

Verify the config plugins

Add @clerk/expo and expo-secure-store to the plugins array in your app config. If your project uses a static app.json and you installed the packages with npx expo install, Expo has already added them:

app.json
{ "expo": { "plugins": ["expo-secure-store", "@clerk/expo"] } }

The @clerk/expo plugin adds the Apple Sign In entitlement (disable it with the appleSignIn: false plugin option if your app doesn't use it), registers the Android intent filter for the hosted authentication callback, and applies the Android packaging fixes required by the underlying clerk-android SDK. If you use the native Sign in with Google buttons, also add the @clerk/expo-google-signin plugin alongside it.

Hosted authentication derives its default callback from the android.package and ios.bundleIdentifier values in your app config. Before you create a production build, add the app on the Native applications page in the Clerk Dashboard with the same Android package name and iOS bundle identifier, since production instances validate the callback against the registered values.

3

Add your Clerk Publishable Key

Copy your Publishable Key from the API keys page in the Clerk Dashboard, then add it to a .env file in the root of your project:

.env
EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_your-key-here

The EXPO_PUBLIC_ prefix is required because Expo inlines these values at build time so they are available in your JavaScript bundle. Clerk's Publishable Key is safe to expose. Do not put Secret Keys behind the EXPO_PUBLIC_ prefix.

4

Wrap your app in <ClerkProvider>

In your root layout file (src/app/_layout.tsx with Expo Router), wrap your app in <ClerkProvider> and pass the Publishable Key. Passing tokenCache explicitly is recommended:

src/app/_layout.tsx
import { ClerkProvider } from '@clerk/expo'; import { tokenCache } from '@clerk/expo/token-cache'; import { Slot } from 'expo-router'; const publishableKey = process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY!; if (!publishableKey) { throw new Error('Add your Clerk Publishable Key to the .env file'); } export default function RootLayout() { return ( <ClerkProvider publishableKey={publishableKey} tokenCache={tokenCache}> <Slot /> </ClerkProvider> ); }

In Core 3, publishableKey is required on <ClerkProvider> for Expo apps. Environment variables inside node_modules are not inlined during production React Native builds, so the prop must be passed explicitly.

tokenCache from @clerk/expo/token-cache persists the user's session across app restarts using expo-secure-store. Passing it explicitly makes the dependency clear and lets you swap in a custom cache implementation later.

Add authentication

The next step depends on which approach you chose. The tabs below show the minimum code for each.

Hosted authentication opens Clerk's Account Portal in a browser authentication session over your app. Users can complete any sign-in or sign-up method enabled for your Clerk application, and the SDK activates the resulting session in your app. Call startHostedAuth() from the useHostedAuth() hook:

src/app/index.tsx
import { useAuth } from '@clerk/expo'; import { useHostedAuth } from '@clerk/expo/hosted-auth'; import { ActivityIndicator, Button, Text, View } from 'react-native'; export default function MainScreen() { const { isLoaded, isSignedIn } = useAuth(); const { startHostedAuth } = useHostedAuth(); const handleSignUp = async () => { try { await startHostedAuth({ mode: 'sign-up' }); } catch (error) { // Handle the error in your app } }; if (!isLoaded) { return <ActivityIndicator size="large" />; } return ( <View> {isSignedIn ? ( <Text>You're signed in</Text> ) : ( <Button title="Sign up" onPress={handleSignUp} /> )} </View> ); }

After authentication completes, the SDK closes the browser session, activates the new session, and updates useAuth() with the signed-in state. The browser doesn't retain a separate active session.

startHostedAuth() opens the sign-in page by default and accepts mode: 'sign-in' | 'sign-up'. It resolves with a null createdSessionId when the user dismisses the browser without finishing, and throws when authentication fails.

This approach works in Expo Go, where Expo supplies a development callback. In a development or production build, the callback is derived from your iOS bundle identifier or Android package name, so keep the @clerk/expo config plugin in your app config and rebuild the native project after changing either identifier.

Account Portal runs in a browser, so social sign-in uses each provider's web OAuth flow rather than the native one. See the hosted authentication guide for production credential requirements and troubleshooting.

Read the signed-in user

Anywhere in your app, use useUser() and useAuth() to read user data, plus <Show> and useClerk() to protect content and sign out:

import { Show, useClerk, useUser } from '@clerk/expo'; import { Link } from 'expo-router'; import { Pressable, Text, View } from 'react-native'; export default function HomeScreen() { const { user } = useUser(); const { signOut } = useClerk(); return ( <View> <Show when="signed-in"> <Text>Hello, {user?.firstName ?? 'friend'}</Text> <Pressable onPress={() => signOut()}> <Text>Sign out</Text> </Pressable> </Show> <Show when="signed-out"> <Link href="/(auth)/sign-in"> <Text>Sign in</Text> </Link> </Show> </View> ); }

<Show> replaces the legacy <SignedIn>, <SignedOut>, and <Protect> components from earlier versions of the SDK. It also accepts when={{ role: '...' }}, when={{ permission: '...' }}, and other authorization predicates.

Run the app

For the hosted authentication and custom flow approaches, run the following command and open the project in Expo Go:

Terminal
npx expo start

Next steps

Clerk Expo quickstart

Step-by-step instructions for setting up each of the three integration approaches, with companion repositories on GitHub.

Hosted authentication

Use Clerk's Account Portal to sign users in and up from your Expo app, with callbacks, cancellation handling, and production setup.

Native components reference

API reference for AuthView, UserButton, and UserProfileView, including configuration, theming, and platform requirements.

Sign in with Google

Set up native Sign in with Google for Android and iOS with the Clerk Dashboard and the Google Cloud Console.

Sign in with Apple

Set up native Sign in with Apple to satisfy App Store Guideline 4.8.

Protect content and read user data

Use Clerk's hooks and Show component to protect routes and access user data in your Expo app.

Deploy an Expo app to production with Clerk

Configure production credentials, allowlist mobile SSO redirects, and ship with EAS Build.