This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
Authentication in Expo Router
Edit page
How to implement authentication and protect routes with Expo Router.
For the previous version of this guide (SDK 52 and earlier), see Authentication (redirects).
With Expo Router, all routes are always defined and accessible. You can use runtime logic to redirect users away from specific screens depending on whether they are authenticated. There are two different techniques for authenticating users within routes. This guide provides an example that demonstrates the functionality of standard native apps.
Using Protected Routes
Protected routes allow you to prevent users from accessing certain routes using client-side navigation. If a user tries to navigate to a protected screen, or if a screen becomes protected while it is active, they will be redirected to the anchor route (usually the index screen) or the first available screen in the stack. Consider the following project structure that has a /sign-in route that is always accessible and a (app) group that requires authentication:
srcapp_layout.tsxControls what is protectedsign-in.tsxAlways accessible (app)_layout.tsxRequires authorization index.tsxShould be protected by the (app)/_layout1
To follow the above example, set up a React Context provider that can expose an authentication session to the entire app. You can implement your custom authentication session provider or use the one from the Example authentication context below.
Example authentication context
This provider uses a mock implementation. You can replace it with your own authentication provider.
The following code snippet is a basic hook that persists tokens securely on native with expo-secure-store and in local storage on web.
2
Create a SplashScreenController to manage the splash screen. Authentication loading is asynchronous, so keep the splash screen visible until authentication loads.
3
Add the SessionProvider to your root layout. This gives your entire app access to the authentication context. Ensure the SplashScreenController is inside the SessionProvider.
4
Create the /sign-in screen. This screen toggles authentication using signIn(). Since this screen is outside the (app) group, the group's layout and authentication check do not run when rendering this screen. This lets logged-out users access this screen.
5
Now modify the RootNavigator to protect routes based on your SessionProvider.
6
Implement an authenticated screen that lets users sign out.
7
Create the src/app/(app)/_layout.tsx:
You now have an app that will present the splash screen until the initial authentication state has loaded and will redirects to the sign-in screen if the user is not authenticated. If a user visits a deep link to any routes with the authentication check, they'll be redirected to the sign-in screen.
Modals and per-route authentication
Another common pattern is to render a sign-in modal over the top of the app. This enables you to dismiss and partially preserve deep links when the authentication is complete. However, this pattern requires routes to be rendered in the background as these routes require handling data loading without authentication.
srcapp_layout.tsxDeclares global session context(app)_layout.tsxsign-in.tsxModal presented over the root(root)_layout.tsxProtects child routesindex.tsxRequires authorization More information
For more information, read the Protected routes documentation to learn more about patterns.

Learn how to use Protected Routes in Expo Router version 5 and later to create an authentication flow.
Middleware
Traditionally, websites may leverage some form of server-side redirection to protect routes. Expo Router on the web currently only supports build-time static generation and has no support for custom middleware or serving. This can be added in the future to provide a more optimal web experience. In the meantime, authentication can be implemented by using client-side redirects and a loading state.