Authentication in Expo and React Native apps

Edit this page

Learn about setting up authentication in your Expo project.


Authentication is a critical part of 90 to 95 percent of modern apps. This guide explains common methods, patterns, and solutions to help you implement authentication in your Expo app.

TL;DR: Auth is hard. If you want to skip the complexity, jump to the Auth solutions section for ready-made solutions. Otherwise, keep reading.

Implementing authentication involves more than writing client-side code. You'll need to manage server requests, password flows, third-party providers like Google or Apple, email handling, and OAuth standards. It can get complex quickly.

There are several types of authentication methods. Some are simple and effective, while others offer a better user experience but require more work. Let's look at the most common approaches and how you can implement them.

Navigation auth flow

Let's start with the basics: any authentication system needs to separate public screens (such as login or signup) from protected screens (such as home or profile). At the navigation level, it comes down to a simple check: is the user authenticated?

To begin, you can simulate this using a hardcoded boolean value, like isAuthenticated = true, and build your navigation logic around it. Once everything is working, you can plug in your real authentication flow.

Using Expo Router

Expo Router v5 introduced protected routes, which prevent users from accessing certain screens unless they are authenticated. This feature works well for client-side navigation and simplifies your setup.

If you're using an older version of Expo Router, you can use redirects instead. Redirects provide the same result but require a bit more manual configuration. They are still supported in Expo Router v5 for backward compatibility.

Expo Router Protected Routes
Expo Router Protected Routes

Learn how to implement an authentication flow with Expo Router

Using React Navigation

If you're using React Navigation, they offer a helpful authentication flow guide that explains how to structure your navigation logic. It includes examples for both static and dynamic approaches based on the user's authentication state.

Both Expo Router and React Navigation give you flexible tools to implement protected navigation based on whether the user is logged in.

Email and password

Email and password is a popular option when adding authentication to your app.

To make this flow user-friendly, you also need to implement forgot password and reset password functionality so users who lose access to their accounts can recover them.

If you want a quicker solution, several services offer built-in email and password authentication, including Clerk, Supabase, Cognito, Firebase, and Better Auth. Most of these have generous free tiers, but it is a good idea to evaluate pricing if your app grows quickly.

The biggest advantage of these services is their ease of integration. They usually offer clear documentation, starter kits, and prebuilt components that save you time.

Security checklist (OWASP) and store-review gotchas

If you're building this flow yourself, be sure to review the Authentication Cheat Sheet by OWASP. It outlines best practices for password length, encryption, recovery, secure storage, and more.

Adding email and password authentication is usually enough to pass App Store and Play Store review. You can submit your app with this method first. If you include "Sign in with Google," Apple may reject your app unless you also support "Sign in with Apple." The same rule applies in reverse on Google Play.

Passwordless login

Passwordless login removes the need for users to create or remember a password. Instead, they provide their email address or phone number during registration. Your app then sends a magic link or one-time passcode (OTP) to their inbox or device. This is a smoother experience for most users and reduces friction during onboarding.

One-Time Passcodes (OTP)

An alternative to magic links is sending a one-time passcode by email or SMS. Instead of clicking a link, the user copies the code and manually returns to the app to enter it. This must happen within a specific time window before the code expires.

There's no deep linking involved here. The user stays in control of the flow and must return to the app themselves.

Fortunately, newer versions of Android and iOS automatically detect passcodes in incoming messages. This enables autofill suggestions above the keyboard, allowing users to enter the code with a single tap. When this works, the experience is seamless.

Magic links and passcodes are both valid authentication methods for Google Play Store and Apple App Store reviews. You can submit your app with either of these methods as the only option and get approved, even before adding social or OAuth login options.

OAuth 2.0

To let your users log in using their existing accounts from services like Google, Apple, GitHub, and more, you can use OAuth 2.0.

OAuth 2.0 is a widely used, secure protocol that allows your app to access user information from another service, without needing to handle passwords. It allows your users to log in with a single tap, which saves time, builds trust, and removes the need to manage passwords.

OAuth flows can be complex. If you're looking for a simple integration, most providers offer SDKs and services that handle everything for you. You can learn more about these in the Auth solutions section.

If you are looking for full control or want to understand how OAuth works under the hood, the following sections show how to implement a complete OAuth flow yourself using Expo.

How OAuth works

OAuth works by introducing an authorization server that acts as a secure middleman. Instead of giving your app their password, users log in through this server and approve access to specific data (like their name or email). The server then issues a temporary code, which your app can exchange for a secure access token.

In this diagram, 'client' simply refers to the application and does not imply any specific implementation details, such as whether it runs on a server, desktop, mobile device, or other platform.

Once you understand this pattern, you can apply it to any provider. The setup for Google, Apple, or GitHub will follow the same general steps.

Custom OAuth with Expo API Routes

The previous diagram shows a high-level overview of the OAuth flow. However, the preferred method for a client to obtain an authorization grant from the user is to use an authorization server as an intermediary, which is exactly what you can build using Expo API Routes.

The following diagram illustrates this flow in more detail:

Expo lets you implement the entire OAuth flow directly in your app using:

Expo Router
Expo Router API Routes
Expo AuthSession

Some providers offer native APIs to handle the sign-in flow directly within the app. Google offers a native Sign in with Google experience on Android. If you're looking for a native implementation, see the Google authentication guide. Apple provides Sign in with Apple, which uses a native bottom sheet and Face ID on iOS. See expo-apple-authentication reference.

The following setup gives you full control over the login experience across Android, iOS, and web.

What are Expo API Routes?

Expo Router API Routes allow you to write server-side logic directly inside your Expo app. You can define functions that handle requests just like an Express or Next.js backend, no need for an external server.

This makes it easy to securely handle sensitive parts of the auth flow, like the authorization code exchange, directly within your app. Since these routes run on the server, you can safely manage secrets, issue JWTs, and validate tokens.

You're essentially building a lightweight custom auth server scoped to your own application, all using your Expo project.
What is Expo AuthSession?

Expo AuthSession is a client-side package that helps you open a web browser or native modal to start the OAuth login flow. It handles redirection, parses the authorization response, and brings the user back into your app.

It's the tool that kicks off the flow and talks to your API Route after the user authorizes access. See Authentication with OAuth or OpenID providers for more information.

This setup lets you:

  • Start the login flow using AuthSession
  • Receive the auth code in your API Route
  • Exchange the code for a token securely
  • Generate a custom JWT with your own logic
  • Return that token to the client
  • Store sessions using cookies (Web) or JWTs (Native)
  • Deploy instantly using EAS Hosting (free to start)

The following tutorials cover implementing OAuth on Android, iOS, and web, including how to create and verify custom JWTs, manage sessions, and protect API routes. If you're new to this flow, we recommend starting with the Google tutorial.

Google Sign-In with Expo OAuth
Google Sign-In with Expo OAuth

Learn how to implement Google Sign-In with Expo Router API Routes


Sign in with Apple using Expo
Sign in with Apple using Expo

Learn how to implement Sign in with Apple


Managing sessions after OAuth

Handling the OAuth flow securely is just the beginning. Once the user is authenticated, you need to think about how to store, restore, and validate their session.

This includes:

  • Storing the session securely on the client
  • Restoring it when the app restarts
  • Protecting your API routes so only authenticated users can access them

Traditionally, cookies are used to store sessions on the web, while JSON Web Tokens (JWTs) are common in native applications.

The above tutorials demonstrate exactly how to handle this. After receiving the ID token from a provider like Google or Apple, you generate a custom JWT on the server using Expo API Routes.

This gives you full control over the session, including:

  • Structuring the payload using consistent fields across providers
  • Customizing expiration times
  • Signing the token with a secret key so your server can verify it later

Once the token is created:

  • For Android and iOS apps, you can store it securely using expo-secure-store
  • For web apps, you can set it as a secure cookie to maintain the session

On every request, the token is sent back to your server, where you verify the signature and check the expiration. If everything checks out, you continue processing the request.

This session model keeps your backend stateless, scalable, and secure, and works consistently across platforms.

All of this is covered in the video tutorials linked above, including:

  • Generating and verifying custom JWTs
  • Handling session storage with Secure Store and cookies
  • Protecting API routes with authentication logic

Auth solutions

If you prefer not to build a full authentication system from scratch, several services offer built-in solutions with first-class support for Expo. Here are some of the most popular options:

Better Auth

BetterAuth is a modern, open-source authentication provider built for developers. It integrates smoothly with Expo, and they offer a guide that shows how to use it with Expo API Routes for full control. It works well with any provider and deploys easily with EAS Hosting.

Clerk

Clerk is a powerful, full-featured authentication service with excellent Expo support. It includes email/password, passcodes, magic links, OAuth providers, and even passkeys. They also offer a native Expo module that handles much of the integration for you.

Supabase

Supabase provides a full backend platform, including a built-in authentication service that works with any OAuth provider. It integrates well with Expo apps and also includes support for email, magic links, and more.

Cognito

AWS Cognito is Amazon's solution for managing user pools and identity. It connects seamlessly with other AWS services and can be integrated into Expo apps using AWS Amplify. It does require more configuration, but it's robust and scalable.

Firebase Auth

Firebase Authentication is Google's auth platform and supports email, magic links, and OAuth providers. It works with React Native through react-native-firebase, which is compatible with Expo development builds.

Modern methods

Once you have a working authentication system in place, you can improve the user experience by adding optional but powerful enhancements like biometrics and passkeys. These features add convenience, trust, and speed to your login flows.

Biometrics

Biometrics like Face ID and Touch ID can be used to unlock the app or confirm identity after a valid session is established. These are not authentication methods on their own, but act as a local gate that makes re-authentication faster and more secure.

React Native provides access to biometric APIs through libraries like expo-local-authentication or react-native-biometrics.

Passkeys

Passkeys are a new, passwordless way to log in to apps and websites. Backed by Apple, Google, and Microsoft, they use platform-level cryptography and biometrics to authenticate users without passwords.

Passkeys offer a seamless and secure experience, but they require a user to already be authenticated before registering one. They also require extra configuration if you're not using a provider that handles them for you.

Recommendations

This guide covers a lot of ground, from basic email and password flows to fully custom OAuth implementations, session management, and modern methods like biometrics and passkeys. Not all of these need to be implemented at once.

In many cases, starting simple is the best approach. Shipping your app with something like email authentication using a magic link or one-time passcode is often more than enough to get through the App Store review process and start collecting feedback from real users.

That said, if you're building an app where you expect high traffic from day one or need to support sign-in across platforms with minimal friction, investing in a more complete authentication flow early on can make a big difference. It can help improve user onboarding, trust, and retention right from the start.

Modern solutions like OAuth, biometrics, and passkeys are not required, but they can be excellent additions once your core system is in place.

The key is to build authentication that fits your current needs, while staying flexible enough to grow with your product.