A starter boilerplate for authentication in React Native, built with Expo Router, NativeWind, Drizzle ORM, and SQLite. Includes sign up, sign in, sign out, forgot password, and reset password flows — designed as a solid foundation to build on, not a production-ready solution out of the box.
⚠️ This is a starting point. Before shipping to production, review the Security Considerations section below. Several intentional simplifications were made to keep this boilerplate approachable.
This project is intentionally simplified. Before using it as a base for a real-world app, you should address the following:
Currently, passwords are hashed using Crypto.CryptoDigestAlgorithm.SHA256 via expo-crypto. SHA-256 is not suitable for password hashing in production — it is fast by design, which makes brute-force attacks trivial.
The
argon2npm package is not compatible with React Native as it relies on Node.js native bindings (C++). Use one of the alternatives below instead.
Option 1 — react-native-argon2 (recommended, requires expo prebuild — exits Expo Go):
bun add react-native-argon2
bun run prebuildimport Argon2 from "react-native-argon2";
async function hashPassword(password: string, salt: string): Promise<string> {
const { rawHash } = await Argon2.hash(password, salt, { mode: "argon2id" });
return rawHash;
}Option 2 — expo-crypto with SHA-512 + salt (no eject required, stays in Expo Go):
import * as Crypto from "expo-crypto";
async function hashPassword(password: string, salt: string): Promise<string> {
return Crypto.digestStringAsync(
Crypto.CryptoDigestAlgorithm.SHA512,
salt + password,
);
}SHA-512 is still not ideal for password hashing, but significantly better than SHA-256 when combined with a unique per-user salt stored alongside the hash.
Option 3 — Backend authentication (most secure for production): Move auth entirely to a server (Node.js, Go, etc.) where Argon2id runs natively, and have the app communicate via HTTPS. Services like Supabase or Firebase Auth handle this out of the box.
Argon2id is the current recommendation from OWASP and RFC 9106.
- Password reset tokens — currently passed via route params (visible in navigation). Consider storing them only server-side or using a deeper link strategy.
- Session management — sessions are stored in SQLite with no expiry. Add a
expiresAtcolumn and invalidate stale sessions. - Input validation — add stricter password rules (min length, complexity) via Zod schemas.
- Rate limiting — no protection against brute-force login attempts exists in a local-first setup; consider adding attempt counters.
- Token expiry — reset tokens expire after 15 minutes by default; adjust as needed for your use case.
- No email verification — there is no email confirmation step on sign up.
- Local-only — this project uses SQLite with no backend. For multi-device or server-side auth, you will need to integrate a backend (e.g., Supabase, Firebase, or a custom API).
git clone https://github.com/Victor-Zarzar/react-native-basic-auth
cd react-native-basic-authbun ibun run db:generatebun run devOpen the app:
- Press
i→ iOS Simulator - Press
a→ Android Emulator - Press
w→ Web
| Script | Description |
|---|---|
bun run dev |
Start the development server (with cache clear) |
bun run android |
Start on Android Emulator |
bun run ios |
Start on iOS Simulator |
bun run web |
Start on Web |
bun run db:generate |
Generate Drizzle ORM migration files |
bun run upgrade-deps |
Fix and align dependencies with Expo SDK |
bun run prebuild |
Rebuild native directories with Expo Prebuild |
bun run ios:native |
Run native iOS build |
bun run android:native |
Run native Android build |
bun run lint |
Check code with Biome |
bun run lint:fix |
Auto-fix lint issues with Biome |
bun run format |
Format code with Biome |
bun run typecheck |
Run TypeScript type checking |
bun test |
Run tests with Bun |
- React Native – Cross-platform mobile framework
- Expo SDK 55 – Development platform and tooling
- Expo Router – File-based routing
- TypeScript – Type-safe development
- NativeWind – Tailwind CSS for React Native
- SQLite (Expo SQLite) – Local persistent storage
- Drizzle ORM – Type-safe ORM for SQLite with migration support
- Expo Crypto – Cryptographic utilities (SHA-256 for dev; replace with Argon2id for prod)
- React Native Reusables – Accessible UI component system
- Complete auth flow — Sign Up, Sign In, Sign Out, Forgot Password, Reset Password
- Local data persistence with SQLite via Expo SQLite
- Type-safe database queries with Drizzle ORM
- Drizzle Studio integration via
expo-drizzle-studio-pluginfor database inspection during development - Password hashing with Expo Crypto (SHA-256 — see Security Considerations for production upgrade path)
- Production-ready scalable structure
- File-based routing with Expo Router
- Dark mode support
- Reusable component system preconfigured
- Edge-to-edge support
- New Architecture enabled (Fabric + TurboModules)
- Cross-platform (iOS, Android, Web)
- Fully compatible with Expo Go
Before starting, ensure you have:
- Node.js (v24+)
- npm or Bun
- Expo CLI
- iOS Simulator (Mac) or Android Emulator
- Git
react-native-basic-auth/
├── .expo/ # Expo cache and config
├── .github/ # GitHub Actions & workflows
├── assets/ # Images and fonts
├── drizzle/ # Generated SQL migration files
├── i18n/ # Internationalization config
├── node_modules/ # Dependencies
├── src/
│ ├── app/ # Expo Router routes
│ │ ├── (auth)/ # Public auth routes (unauthenticated)
│ │ │ ├── _layout.tsx # Auth stack layout
│ │ │ ├── forgot-password.tsx # Forgot password screen
│ │ │ ├── reset-password.tsx # Reset password screen
│ │ │ ├── signin.tsx # Sign in screen
│ │ │ └── signup.tsx # Sign up screen
│ │ ├── (main)/ # Protected main routes (authenticated)
│ │ │ └── (tabs)/ # Bottom tab navigator
│ │ │ ├── about/ # About tab
│ │ │ │ ├── _layout.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── home/ # Home tab
│ │ │ │ ├── _layout.tsx
│ │ │ │ └── index.tsx
│ │ │ └── settings/ # Settings tab
│ │ │ ├── _layout.tsx
│ │ │ └── index.tsx
│ │ ├── +html.tsx # Custom HTML shell (web)
│ │ ├── +not-found.tsx # 404 screen
│ │ └── _layout.tsx # Root layout
│ └── shared/
│ ├── auth/ # Auth context & logic
│ │ ├── context.ts
│ │ ├── index.ts
│ │ └── provider.tsx
│ ├── components/
│ │ ├── language/ # i18n / language components
│ │ │ ├── flags/
│ │ │ └── index.tsx
│ │ └── ui/ # Reusable UI components
│ │ ├── forgot-password-form.tsx
│ │ ├── header-avatar.tsx
│ │ ├── reset-password-form.tsx
│ │ ├── sign-in-form.tsx
│ │ ├── sign-up-form.tsx
│ │ ├── social-connections.tsx
│ │ ├── user-menu.tsx
│ │ └── verify-email-form.tsx
│ ├── constants/
│ │ ├── Colors.ts
│ │ └── theme-icon.tsx
│ ├── db/ # Database layer
│ │ ├── client.ts # SQLite client setup
│ │ ├── db-migration.tsx # Migration runner
│ │ ├── index.ts
│ │ ├── provider.tsx # DB context provider
│ │ └── schema.ts # Drizzle schema definitions
│ ├── hooks/
│ │ ├── useAuth.ts
│ │ └── useColorScheme.ts
│ ├── lib/
│ │ ├── theme.ts
│ │ └── utils.ts
│ ├── services/
│ │ └── userService.ts
│ └── types/
│ ├── auth.ts
│ ├── icon.ts
│ └── locale.ts
├── tests/ # Test files
├── global.css # Global styles
├── app.json # Expo configuration
├── drizzle.config.ts # Drizzle Kit configuration
├── package.json # Dependencies
├── tailwind.config.js # NativeWind config
├── tsconfig.json # TypeScript config
└── babel.config.js # Babel config
This project uses Drizzle ORM on top of Expo SQLite for type-safe, local database operations.
After modifying the schema, run:
bun run db:generateThis will generate SQL migration files inside the drizzle/ folder using Drizzle Kit.
With the development server running (bun run dev), press Shift + M in the terminal to open the Dev Tools menu, then select expo-drizzle-studio-plugin from the list. Drizzle Studio will open in a new browser tab, allowing you to browse and manage your local SQLite database visually.
Note: This plugin is available during native development only (iOS/Android). It does not work on Web.
npx react-native-reusables/cli@latest add input textareaInstall all components:
npx react-native-reusables/cli@latest add --allnpm install -g eas-cli
eas login
eas buildDocumentation: https://docs.expo.dev/eas/
- Fork the project
- Create your feature branch
- Commit your changes
- Push to the branch
- Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Victor Zarzar - @Victor-Zarzar
Project Link: https://github.com/Victor-Zarzar/react-native-basic-auth
