React Scaffold (Custom)
A full-stack React application with custom OAuth and email authentication built on Hono. This scaffold implements all auth flows from scratch — no SDK required.
Overview
This scaffold demonstrates how to integrate AuthGate using raw HTTP requests. It's ideal if you want complete control over your auth implementation or need to understand how the proxy flow works under the hood.
What's included:
- Hono server with full auth routes (OAuth + email)
- React 19 frontend with React Router 7
- HMAC-signed session cookies with timing-safe comparison
- Nonce-based OAuth state validation (10-minute TTL)
- Login, signup, forgot password, and reset password pages
- Protected dashboard route with session guard
Prerequisites
- Node.js 18+
- An AuthGate project with at least one provider enabled
- An API key from the AuthGate dashboard
- A registered callback URL pointing to
/api/auth/callback
Setup
Clone the scaffold from the monorepo and install dependencies:
cd apps/scaffolds/react/custom
cp .env.example .env
# Fill in your AuthGate credentials
pnpm install
pnpm dev
The dev server runs at http://localhost:3003 by default.
Directory structure
src/
├── server/
│ ├── index.ts # Hono server entry with Vite dev middleware
│ ├── env.ts # Server-side env validation
│ └── routes/auth.ts # All auth routes (~340 lines)
├── lib/
│ ├── auth.tsx # React auth context provider
│ └── authgate.ts # OAuth URL construction helpers
├── components/
│ ├── AuthGuard.tsx # Protected route wrapper
│ └── OAuthButtons.tsx # Provider login buttons
├── pages/
│ ├── Home.tsx
│ ├── Login.tsx
│ ├── Signup.tsx
│ ├── ForgotPassword.tsx
│ ├── ResetPassword.tsx
│ └── Dashboard.tsx
├── App.tsx # Route definitions
└── main.tsx # React entry point
Key files
src/server/routes/auth.ts
The core of this scaffold. Implements all auth endpoints:
| Route | Method | Description |
|---|---|---|
/:provider/login | GET | Redirects to AuthGate proxy with HMAC-signed state |
/callback | GET | Verifies state + JWT, sets session cookie |
/email/signup | POST | Proxies signup to AuthGate, verifies token, sets session |
/email/signin | POST | Proxies signin to AuthGate, verifies token, sets session |
/email/forgot-password | POST | Requests password reset email |
/email/reset-password | POST | Confirms reset with new password |
/me | GET | Returns current session user |
/logout | POST | Clears session cookie |
OAuth state flow: A random nonce is stored in an httpOnly cookie and combined with a timestamp and HMAC-SHA256 signature to form the state parameter. On callback, the state is verified using timing-safe comparison against the stored nonce.
Session cookies: User data is JSON-serialized, HMAC-signed, and stored as payload.signature in an httpOnly cookie with 7-day expiry.
src/lib/auth.tsx
React context provider that calls /api/auth/me on mount and exposes user, loading, refresh(), and logout() through a useAuth() hook.
src/components/AuthGuard.tsx
Wraps protected routes. Redirects to /login if no session exists, shows a loading state while checking.
Environment variables
| Variable | Server/Client | Description |
|---|---|---|
AUTHGATE_URL | Server | AuthGate API base URL (e.g. https://auth.authgate.dev) |
AUTHGATE_API_KEY | Server | API key for token verification |
STATE_SECRET | Server | Min 32 characters, used for HMAC signing |
VITE_AUTHGATE_URL | Client | Same as AUTHGATE_URL (Vite-prefixed for browser) |
VITE_APP_URL | Client | Your app's URL (e.g. http://localhost:3003) |