Clerk logo

Clerk Docs

Ctrl + K
Go to clerkstage.dev
Check out a preview of our new docs.

Clerk Expo

Integrate Clerk into your React Native application

Overview

Clerk Expo is a wrapper around Clerk React. It is the recommended way to integrate Clerk into your React Native application.

Clerk Expo works for IOS and Android. For web based applications use Clerk React.

Clerk is the easiest way to add authentication and user management to your Expo/React Native application. This guide will walk you through the necessary steps to install and use Clerk in a new create-expo-app application.

After following this guide, you should have a working Expo app complete with the following:

  • Fully fledged sign in and sign up flows.
  • Social Logins.
  • Secure email/password authentication.

Clerk Expo provides hooks which act as helpers for implementing a seamless authentication experience. The hooks give you access to the Clerk object and a set of useful helper methods for signing in and signing up.

Looking for a quickstart? We created a demo app to show you how to add Clerk to your project.

Before you start

You need to create a Clerk Application in your Clerk Dashboard before you can set up Clerk React. For more information, check out our Setup your application guide.

Creating a new Expo app

Start by creating a new React application - this is usually done using the create-expo-app CLI:

npx create-expo-app my-app

Installing Clerk

There's an ES module for Clerk Expo, available under the @clerk/clerk-expo npm package. Use npm or yarn to install the Clerk React module.

1
npm install @clerk/clerk-expo
1
yarn add @clerk/clerk-expo

Adding <ClerkProvider/>

The ClerkProvider allows you to render Clerk Control Components and access the available Clerk React hooks in any nested component. You'll have to wrap your application once with a <ClerkProvider/>.

Render a <ClerkProvider/> component at the root of your React app so that it is available everywhere you need it.

In order to use <ClerkProvider/> first you need to locate the entry point file of your React Native app. In Expo, this is usually your src/App.js.

Finally, <ClerkProvider/> will need the publishableKey prop.

Requiring authentication

The easiest way to require authentication before showing a protected page is to use our Control Components:

  • <SignedIn/>: Renders its children only when a user is signed in.
  • <SignedOut/>: Renders its children only when there's no active user.

The following example shows you how to compose our flexible Control Components to build auth flows that match your needs. Here is an example of the <SignedIn/> component:

1
import React from "react";
2
import { Text } from "react-native";
3
import { SafeAreaProvider } from "react-native-safe-area-context";
4
import { ClerkProvider } from "@clerk/clerk-expo";
5
6
export default function App() {
7
return (
8
<ClerkProvider publishableKey="{{pub_key}}">
9
<SafeAreaProvider>
10
<Text>Hello world!</Text>
11
</SafeAreaProvider>
12
</ClerkProvider>
13
);
14
}

When using Expo and React Native, it is required to build out a custom sign-in screen for users to be able to sign in to your application. Below is an example:

1
import React from "react";
2
import { Text, TextInput, TouchableOpacity, View } from "react-native";
3
import { useSignIn } from "@clerk/clerk-expo";
4
import { log } from "../logger";
5
import { RootStackScreenProps } from "../types";
6
import { SignInWithOauth } from "../components/SignInWithOauth";
7
import { styles } from "../components/Styles";
8
9
10
11
export default function SignInScreen({
12
navigation,
13
}: RootStackScreenProps<"SignIn">) {
14
const { signIn, setSession, isLoaded } = useSignIn();
15
16
const [emailAddress, setEmailAddress] = React.useState("");
17
const [password, setPassword] = React.useState("");
18
19
const onSignInPress = async () => {
20
if (!isLoaded) {
21
return;
22
}
23
24
try {
25
const completeSignIn = await signIn.create({
26
identifier: emailAddress,
27
password,
28
});
29
30
await setSession(completeSignIn.createdSessionId);
31
} catch (err) {
32
// @ts-ignore
33
log("Error:> " + (err.errors ? err.errors[0].message : err));
34
}
35
};
36
37
const onSignUpPress = () => navigation.replace("SignUp");
38
39
return (
40
<View style={styles.container}>
41
42
<View style={styles.inputView}>
43
<TextInput
44
autoCapitalize="none"
45
value={emailAddress}
46
style={styles.textInput}
47
placeholder="Email..."
48
placeholderTextColor="#000"
49
onChangeText={(emailAddress) => setEmailAddress(emailAddress)}
50
/>
51
</View>
52
53
<View style={styles.inputView}>
54
<TextInput
55
value={password}
56
style={styles.textInput}
57
placeholder="Password..."
58
placeholderTextColor="#000"
59
secureTextEntry={true}
60
onChangeText={(password) => setPassword(password)}
61
/>
62
</View>
63
64
<TouchableOpacity style={styles.primaryButton} onPress={onSignInPress}>
65
<Text style={styles.primaryButtonText}>Sign in</Text>
66
</TouchableOpacity>
67
68
<View style={styles.footer}>
69
<Text>Have an account?</Text>
70
71
<TouchableOpacity
72
style={styles.secondaryButton}
73
onPress={onSignUpPress}
74
>
75
<Text style={styles.secondaryButtonText}>Sign up</Text>
76
</TouchableOpacity>
77
</View>
78
</View>
79
);
80
}

Token Cache

A token cache is required to work with Clerk and Expo. This is entirely up to you how you handle the token cache. For example, Expo provides a way to encrypt and securely store key–value pairs locally on the device via expo-secure-store. You can use it as your client JWT storage by setting the tokenCache prop in your <ClerkProvider/> as shown below.

1
import React from "react";
2
import { Text } from "react-native";
3
import { SafeAreaProvider } from "react-native-safe-area-context";
4
import { ClerkProvider } from "@clerk/clerk-expo";
5
import * as SecureStore from "expo-secure-store";
6
7
const tokenCache = {
8
getToken(key: string) {
9
try {
10
return SecureStore.getItemAsync(key);
11
}
12
catch (err) {
13
return null;
14
}
15
},
16
saveToken(key: string, value: string) {
17
try {
18
return SecureStore.setItemAsync(key, value);
19
}
20
catch (err) {
21
return null;
22
}
23
}
24
};
25
26
export default function App() {
27
return (
28
<ClerkProvider publishableKey="your_publishable_key" tokenCache={tokenCache}>
29
<SafeAreaProvider>
30
<Text>Hello world!</Text>
31
</SafeAreaProvider>
32
</ClerkProvider>
33
);
34
}

Was this helpful?

Clerk © 2023