Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 28 additions & 157 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,45 +40,7 @@ This project is intentionally simplified. Before using it as a base for a real-w

### Password Hashing

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 `argon2` npm 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):

```bash
bun add react-native-argon2
bun run prebuild
```

```ts
import 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):

```ts
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](https://supabase.com) or [Firebase Auth](https://firebase.google.com/products/auth) handle this out of the box.

> Argon2id is the current recommendation from [OWASP](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) and [RFC 9106](https://www.rfc-editor.org/rfc/rfc9106).
Passwords are hashed using **`react-native-argon2`** with Argon2id, which is the current recommendation from [OWASP](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) and [RFC 9106](https://www.rfc-editor.org/rfc/rfc9106).

### Other Areas to Improve Before Production

Expand Down Expand Up @@ -115,42 +77,37 @@ bun i
bun run db:generate
```

### 4. Run the App (Start the development server):
### 4. Run the App

```bash
bun run dev
```

Open the app:
# iOS (native build)
bun run ios:native

- Press `i` → iOS Simulator
- Press `a` → Android Emulator
- Press `w` → Web

## Or scan the QR Code using Expo Go on your device.
# Android (native build)
bun run android:native
```

---

<h2 id="scripts">
Available Scripts
</h2>

| 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 |
| Script | Description |
| ------------------------ | --------------------------------------------- |
| `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 |

---

Expand All @@ -165,7 +122,7 @@ Open the app:
- **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 Argon2** – Argon2id password hashing
- **React Native Reusables** – Accessible UI component system

---
Expand All @@ -178,15 +135,14 @@ Open the app:
- Local data persistence with SQLite via Expo SQLite
- Type-safe database queries with Drizzle ORM
- Drizzle Studio integration via `expo-drizzle-studio-plugin` for database inspection during development
- Password hashing with Expo Crypto (SHA-256 — see [Security Considerations](#security-considerations) for production upgrade path)
- Password hashing with Argon2id via `react-native-argon2`
- 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

---

Expand All @@ -204,91 +160,6 @@ Before starting, ensure you have:

---

<h2 id="project-structure">
Project Structure
</h2>

```
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
```

---

<h2 id="database">
Database & Migrations
</h2>
Expand All @@ -307,14 +178,14 @@ This will generate SQL migration files inside the `drizzle/` folder using Drizzl

### Inspecting the Database with Drizzle Studio

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.
With the development server running, 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.

</br>

<p align="center">
<img src="https://github.com/user-attachments/assets/05dce4c2-72cd-46c9-afb9-d04146848ea2" width="1000" height="600" alt="SQL Drizzle Studio">
<img width="1919" height="962" alt="Screenshot 2026-04-13 at 18 48 48" src="https://github.com/user-attachments/assets/4843ee09-3889-4b36-a015-ee4fc485b221" width="1000" height="600" alt="SQL Drizzle Studio" />
</p>

</br>
Expand All @@ -326,13 +197,13 @@ With the development server running (`bun run dev`), press `Shift + M` in the te
</h2>

```bash
npx react-native-reusables/cli@latest add input textarea
bunx react-native-reusables/cli@latest add input textarea
```

Install all components:

```bash
npx react-native-reusables/cli@latest add --all
bunx react-native-reusables/cli@latest add --all
```

---
Expand Down
16 changes: 16 additions & 0 deletions android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# OSX
#
.DS_Store

# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
*.hprof
.cxx/

# Bundle artifacts
*.jsbundle
Loading
Loading