Stack logo
Sync up on the latest from Convex.
Hyo Jang's avatar
Hyo Jang
a month ago

User Authentication with Clerk and Convex

Welcome! This is the first article in 4-part series on building a full-stack application using Convex and Expo. Throughout this series, we’ll implement features such as authentication, profile management, and chat functionality, providing you with practical examples you can apply in your own projects.

  1. User Authentication with Clerk and Convex (You are here)
  2. Real-Time User Profiles with Convex and Clerk
  3. Implementing Real-Time AI Chat with Convex
  4. Automating Content with Convex Cron and ChatGPT

 

What This Article Covers

This article focuses on user authentication, showing you how to integrate Clerk with Convex for user account management and how to configure Expo Router to handle different screens based on the user’s login status.

  1. Setting up user authentication with Clerk and Convex
  2. Synchronizing Clerk with Convex to ensure seamless user data management
  3. Using Expo Router to manage authentication states and screen navigation

What You’ll Gain from This Article

  • A working understanding of how Clerk integrates with Convex to manage authentication
  • Hands-on experience with Expo Router's authentication flow
  • The foundation needed for implementing secure features in future articles

This article lays the foundation ****for our series by implementing user session handling and authentication-based navigation. These core concepts are essential for the more advanced features we'll build in upcoming articles, where we'll cover:

  • Using Convex's real-time database and file storage
  • Implementing AI chat in Convex
  • Using Convex Cron

Let’s dive in and set up our user authentication flow! 🚀

Project Setup

To get started, create the foundation for this project on GitHub. The repository can be found here:

https://github.com/hyochan/convex-expo-workshop

This project uses dooboo-cli, a command-line tool that streamlines the setup of Expo projects. It provides a boilerplate from expo-router-starter with pre-configured Expo Router settings. This helps developers quickly scaffold projects with routing built-in, reducing repetitive setup tasks.

Additionally, dooboo-cli installs the lightweight dooboo-ui React Native component library by default. Although still evolving and less mature than other UI frameworks, dooboo-ui follows a solid design philosophy, detailed in its documentation here. With a minimal set of components, it enables rapid app structuring without unnecessary overhead. The source code for dooboo-ui is available here.

To initialize the project with dooboo-cli, run the following command:

1npx dooboo init
2

Using dooboo-cli as the installation path for Expo projects is highly recommended for quickly starting with a well-configured environment.

Configuring Authentication with Clerk

This project demonstrates user authentication by integrating Clerk with Convex. With Clerk integrated, Expo Router manages routes based on the user’s session status, ensuring that the app displays the appropriate screens for logged-in and logged-out users. The complete implementation of this setup can be found in the following pull request:

https://github.com/hyochan/convex-expo-workshop/pull/1

By the end of this step, we'll have a working authentication flow and session-based routing, forming a solid foundation for building more advanced features in the following parts of the series.

For more details on Clerk configuration, visit the Clerk Expo Quickstart. To proceed smoothly with the workshop, sign up for Clerk, create a .env file in the project root, and add the following value as explained here:

1EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=<your-clerk-publishable-key>
2

This key can be found in the API Keys section within the Configure menu of the Clerk dashboard.

Getting Started

  1. With the initial setup complete, the next step is to clone the repository and check out the relevant commit(68a0429dbca5ee432f50dbb8c7f9c59f5fb82191) for this project. Use the following command:
1git clone https://github.com/hyochan/convex-expo-workshop.git && cd convex-expo-workshop && git checkout 68a0429dbca5ee432f50dbb8c7f9c59f5fb82191
2
  1. Once the repository is cloned, create a .env file by copying the .env.sample file. In the newly created .env file, focus only on setting the EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY as shown below, ignoring other keys:
1expoProjectId=
2EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_dW5pcXVlLW1hbW1vdGgtMzIuY2xlcmsuYWNjb3VudHMuZGV2JA
3
4
  1. After setting up the environment variables, install the required packages. This repository recommends using bun for faster package installation, but other package managers such as npm or yarn can also be used.
1bun install
2
  1. To start the project, use:
1bun start
2
  1. After starting the project, open the iOS simulator by pressing the i shortcut key. If everything is configured correctly, the following screen should appear, confirming the project is running successfully.

Once the simulator launches, you should see the Clerk login screen. Try signing in with email or a social provider to verify that authentication is working correctly. A successful login will redirect you to the main app screen, confirming that Clerk is properly integrated.

Convex actually offers its own SSO solution called Convex-Auth, which allows free user management, but since it is still in Beta, Clerk will be used for now.

Integrating Clerk with Convex

To integrate Clerk with Convex, start by following the instructions in the Convex & Clerk section on the Convex official website.

After reviewing the guide, open the Clerk dashboard and follow these steps:

  1. Navigate to ConfigureSession ManagementJWT Templates.

  1. Create a new JWT template to enable secure communication between Clerk and Convex by clicking on Convex.

In this screen, make sure to take note of the Issuer URL displayed above. This will be used later in the Convex configuration.

After creating the Convex template as shown above, proceed to configure Convex. Then, go back to the Convex project and add the Issuer URL to Environment Variables.

These environment variables establish the connection between Clerk and Convex, enabling secure user authentication.

Convex

https://docs.convex.dev/quickstart/react-native

The first step is install Convex in your project. While full documentation is available in the Convex React Native guide, here are the key steps. Run this command:

1bun install convex && npx convex dev
2

When prompted, enter a name for your project:

Once the project name is entered as shown above, the installation will be completed, and you can immediately see it on the Convex dashboard.

Now, it's time to configure your installation.

Convex: Configuration Setup

  1. Create the configuration file convex/auth.config.ts and add the following values. Ensure the domain is set to the Issuer URL obtained from the JWT Templates created earlier in the Clerk dashboard:

    1export default {
    2  providers: [
    3    {
    4      domain: "https://unique-mammoth-32.clerk.accounts.dev",
    5      applicationID: "convex",
    6    },
    7  ],
    8};
    9
  2. Retrieve the Deployment URL from the URL & Deploy Key section in the Convex dashboard:

  1. Add the following environment variables to the .env file in the project root. The EXPO_PUBLIC_CONVEX_URL value should match the deployment URL copied from the Convex dashboard:

    1EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_dW5pcXVlLW1hbW1vdGgtMzIuY2xlcmsuYWNjb3VudHMuZGV2JA
    2expoProjectId=
    3
    4CONVEX_DEPLOYMENT=dev:combative-peacock-373
    5EXPO_PUBLIC_CONVEX_URL=https://combative-peacock-373.convex.cloud
    6
  2. Synchronize the provider with the backend by running:

    1npx convex dev
    2

    If deploying to production, use:

    1npx convex deploy
    2

Integrating Convex into Your App

Now let's add Convex to your React Native app. Here are the steps:

  1. In the root layout file (app/_layout.tsx), initialize the Convex client as shown below. This connects the app to the Convex backend using the deployment URL from the .env file:

    1const convex = new ConvexReactClient(process.env.EXPO_PUBLIC_CONVEX_URL!, {
    2  unsavedChangesWarning: false,
    3});
    4
  2. Wrap the app components with the ConvexProviderWithClerk provider to handle both Clerk and Convex functionalities:

    1<GestureHandlerRootView
    2  style={css`
    3    flex: 1;
    4  `}
    5>
    6  <ClerkProvider
    7    tokenCache={tokenCache}
    8    publishableKey={clerkPublishableKey}
    9  >
    10    <ClerkLoaded>
    11      <ConvexProviderWithClerk client={convex} useAuth={useAuth}>
    12        <RootProvider initialThemeType={localThemeType as ColorSchemeName}>
    13          <>
    14            <StatusBarBrightness />
    15            <Layout />
    16          </>
    17        </RootProvider>
    18      </ConvexProviderWithClerk>
    19    </ClerkLoaded>
    20  </ClerkProvider>
    21</GestureHandlerRootView>
    22
    23

    Convex offers a default ConvexProvider, but when integrating with Clerk, the ConvexProviderWithClerk from the convex/react-clerk package ensures smooth authentication management.

  3. Run the app:

    If the npx convex dev terminal is still running, the server will already be active. Otherwise, restart the server with:

    1npx convex dev
    2
  4. Start the project by running:

    1bun start
    2

    Your app should now be running with Convex and Clerk properly integrated. The authentication flow will handle the communication between these services automatically.

Key points:

  • ConvexProviderWithClerk connects Clerk's authentication with Convex
  • Provider order matters: Clerk must wrap Convex
  • Keep the Convex development server running while working on your app
  • The client initialization uses your deployment URL from .env

Convex: Verifying Clerk Integration

Now let's use the useConvexAuth hook to confirm that Clerk and Convex are working together properly. In the My Tab screen, call that hook and console.log the results as shown below.

1// app/(home)/(tabs)/index.tsx
2export default function My(): JSX.Element {
3  const [isSigningOut, setIsSigningOut] = useState(false);
4  const {signOut} = useAuth();
5  const auth = useConvexAuth();
6  console.log('auth', auth);
7  ...
8

Then, run the app and log in. You should see a console output like the one below. If you don't see these values, double-check your Clerk and Convex configuration steps above.

Congratulations! You've completed the first part of the workshop. Your app now has working authentication with Clerk and Convex integration. For the complete code, see https://github.com/hyochan/convex-expo-workshop/pull/2.

Bonus: Testing

The workshop primarily focused on app implementation, but we’ll also explore how to facilitate testing by merging the Clerk and Convex providers into the RootProvider and mocking the necessary functions using Jest.

Setup jest

  1. Create these mock files in your __mocks__ directory.

  1. Add the following lines to moduleNameMapper in jest.config.ts.

    1'^@clerk/clerk-expo$': '<rootDir>/__mocks__/@clerk/clerk-expo.ts',
    2'^convex/react-clerk$': '<rootDir>/__mocks__/convex/react-clerk.ts',
    3'^convex/react$': '<rootDir>/__mocks__/convex/react.ts',
    4
  2. Add react-clerk|@clerk to transformIgnorePatterns in jest.config.ts

Once again, check commit https://github.com/hyochan/convex-expo-workshop/pull/2/commits/ca75b337a14097f00ba865c24d8b5a0396117443 for more details. Hope this helps you write test code.


Up Next

Coming up, we’ll walk through the steps to implement real-time updates and manage user data. This will bring your app one step closer to a polished, professional user experience.

--> How to build real-time user profiles with Convex and Clerk

Build in minutes, scale forever.

Convex is the sync platform with everything you need to build your full-stack project. Cloud functions, a database, file storage, scheduling, search, and realtime updates fit together seamlessly.

Get started