This guide covers authentication patterns for One apps, from simple session management to full OAuth flows. One’s unique combination of middleware, loaders, and cross-platform support gives you flexibility in how you protect routes.
Approaches
There are three main approaches to authentication:
Approach
Best For
Complexity
Self-hosted libraries
Most apps, full control, own database
Low-Medium
Hosted providers
Fastest setup, managed infrastructure
Low
Custom auth
Specific requirements, full control
High
Self-hosted libraries like Better Auth or Auth.js run on your own server with your own database. You get full control over user data while the library handles the complexity of OAuth flows, session management, and security best practices. This is our recommended approach.
Hosted providers like Clerk or Supabase Auth manage everything for you including infrastructure. Fastest to set up but user data lives on their servers.
Custom auth means implementing everything yourself - password hashing, session management, token validation, OAuth flows. Only recommended if you have very specific requirements.
Session Context
The foundation of any auth system is a session context that tracks auth state across your app.
For token storage, use a cross-platform storage library. Popular options:
react-native-mmkv - Fast key-value storage (~30x faster than AsyncStorage), works on web and native
Zustand with persist middleware - State management with built-in storage abstraction
expo-secure-store - Encrypted storage for sensitive tokens (native only)
Create a platform-specific abstraction using One’s file extensions:
Terminal
features/auth/
├── storage.ts # Shared interface
├── storage.web.ts # localStorage or MMKV for web
└── storage.native.ts # MMKV or expo-secure-store for native
This keeps your auth context clean while each platform uses appropriate secure storage.
Protected Routes
There are two approaches to protecting routes in One:
Approach
Best For
<Protected />
Routes that shouldn’t exist when unauthorized (hidden tabs, admin-only pages)
Redirect guard
Routes that redirect to login but support returning after auth
The <Protected /> component completely filters out routes when its guard prop is false. This is ideal when routes should be invisible to unauthorized users:
Protect routes using a layout guard that checks auth state and redirects unauthorized users. This approach allows deep linking to protected pages - users are redirected to login, then can return to their original destination.
Check auth in loaders for SSR pages. Loaders run on the server, so redirect() works for both direct page loads and client-side <Link> navigation — the protected page never renders and no sensitive data reaches the client.
Both throw redirect() and return redirect() work — throw is often cleaner since it stops execution and makes it obvious the remaining code won’t run.
Use +ssr routes for protected pages so loaders run on every request, including client-side navigation. This ensures auth is always checked server-side.
Note: Component JavaScript is always downloadable (same as every framework). Loaders protect data — use them to ensure sensitive data never reaches unauthorized clients.