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
101 changes: 101 additions & 0 deletions AUTH_ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Auth Architecture

This project currently uses two authentication paths that map into the same
Neon PostgreSQL `users` table.

## Current System

### Password Auth

- Frontend login and registration call `POST /api/login` and `POST /api/register`.
- The API verifies passwords with `bcrypt` and signs JWTs with `jsonwebtoken`.
- The frontend stores the JWT in `localStorage` and sends it as a bearer token.
- API routes use `requireAuth()` from `api/_lib/auth.js`; that middleware checks
the JWT path first.

### OAuth Auth

- OAuth is handled by Stack Auth through the Neon Auth integration.
- The React app initializes `StackClientApp` in `app/src/config/neonAuth.js`.
- `app/src/App.jsx` wraps the app in `StackProvider` and exposes Stack Auth's
callback handler at `/handler/*`.
- The backend verifies Stack Auth sessions in `api/_lib/neon-auth.js` by calling
Stack Auth's server API.
- OAuth users are linked to local database users by `neon_auth_id` first, then
by email.

### Data Persistence

Neon PostgreSQL remains the application database. User-owned data is keyed to
`users.id`:

- `calculations.user_id`
- `user_data.user_id`
- `contributors.user_id`

Any auth migration must preserve those relationships so saved calculations,
custom yield data, and contributor profiles continue to sync across devices.

## Required Properties For Any Future Auth System

- Support OAuth providers such as Google and GitHub.
- Support email or password login for users who do not use OAuth.
- Persist identity across devices, not only in browser storage.
- Map every authenticated identity to the existing local user record.
- Keep `req.user` compatible with protected API routes that expect `id`,
`username`, and `email`.
- Work with the selected hosting platform and Neon PostgreSQL.

## Operational Notes

Stack Auth OAuth redirects only work from domains registered in Stack Auth's
Trusted Domains settings. A deployed Vercel domain must be added there before
OAuth can complete. The callback route is `/handler/*`, but Stack Auth expects
the domain root to be trusted, not the full callback URL.

The Vercel integrations panel should only keep integrations that are actively
used. Clerk is not referenced in this codebase, and duplicate Neon integrations
make it harder to reason about which environment variables and auth project are
active.

## Migration Options

### Keep Stack Auth

This is the lowest-code option. It keeps the current OAuth flow and local JWT
password flow, but the team must maintain Trusted Domains and Vercel integration
settings carefully.

### Better Auth

Better Auth can consolidate email/password and OAuth into one self-hosted auth
system. The existing roadmap in `docs/AUTH_MIGRATION_ROADMAP.md` covers the
larger Stack Auth to Better Auth plus Cloudflare migration.

### Clerk

Clerk has strong React support and can run outside Vercel, but it is not wired
into this repository today. Connecting Clerk would require replacing the current
Stack Auth and JWT paths.

### Auth.js

Auth.js is open source and provider-agnostic. It would require more adapter and
session work than Stack Auth, but it avoids a hosted auth dependency.

### Supabase Auth

Supabase Auth works well when the database is also Supabase. Using it here would
introduce a second platform next to Neon unless the database is migrated too.

## Migration Checklist

- [ ] Inventory current Vercel and Stack Auth environment variables.
- [ ] Register production and preview domains in Stack Auth Trusted Domains.
- [ ] Remove unused Clerk integration from Vercel.
- [ ] Remove stale duplicate Neon integrations after confirming env ownership.
- [ ] Choose whether to keep dual auth or consolidate into one provider.
- [ ] Preserve the `users.id` mapping for calculations, custom data, and
contributor profiles.
- [ ] Test password login, OAuth login, logout, saved calculations, custom data,
and contributor profile updates after any auth change.
61 changes: 56 additions & 5 deletions DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ Before deploying, add these environment variables in Vercel:
|----------|-------|-------|
| `DATABASE_URL` | Your Neon connection string | From Step 1.1 |
| `JWT_SECRET` | Your generated secret | From Step 2 (required; API fails fast if missing) |
| `VITE_STACK_PROJECT_ID` | Stack Auth project ID | Required for frontend OAuth |
| `VITE_STACK_PUBLISHABLE_CLIENT_KEY` | Stack Auth publishable client key | Required for frontend OAuth |
| `STACK_SECRET_SERVER_KEY` | Stack Auth server secret key | Required for backend OAuth session verification |
| `ALLOWED_ORIGINS` | Comma-separated allowlist (e.g. `https://your-app.vercel.app,http://localhost:5173`) | Required for CORS |
| `CORS_ALLOW_CREDENTIALS` | `true` or `false` | Only enable when you need cookies across origins |
| `JWT_EXPIRES_IN_SECONDS` | Optional, default `86400` | JWT lifetime (same value should be used locally) |
Expand All @@ -116,17 +119,51 @@ Click "Deploy" and Vercel will:

---

## Step 5: Verify Deployment
## Step 5: Configure Stack Auth Trusted Domains

### 5.1 Test Public Endpoints
After deploying to Vercel, register the deployed domain in Stack Auth so OAuth
redirects can complete.

### 5.1 Add Domains to Stack Auth

1. Log in to https://app.stack-auth.com
2. Select the project matching `VITE_STACK_PROJECT_ID`.
3. Open Project Settings -> Domains or Trusted Domains.
4. Add each domain where users will sign in:
- Production Vercel URL, for example `https://your-app.vercel.app`
- Custom production domain, if configured
- Preview deployment URLs, or a preview wildcard if your Stack Auth project supports it
5. Save the domain settings.

The callback route in this app is `/handler/*`, but Stack Auth needs the domain
root in Trusted Domains, not the full callback path.

### 5.2 Clean Up Vercel Integrations

1. Open the Vercel project settings.
2. Remove the Clerk integration if it is present and unused. This repository
does not import Clerk.
3. Remove stale duplicate Neon integrations after confirming the active Neon
integration owns the current database and Stack Auth configuration.
4. Confirm the remaining integration and environment variables match the
intended Stack Auth and Neon projects.

See `AUTH_ARCHITECTURE.md` for the current auth architecture and migration
options.

---

## Step 6: Verify Deployment

### 6.1 Test Public Endpoints

1. Visit your Vercel URL: `https://your-app.vercel.app`
2. Test public pages:
- Home (calculator) - works without login
- Data Sources page - should load contributors
- About page

### 5.2 Test Authentication
### 6.2 Test Authentication

1. Register a new account
2. Login
Expand All @@ -136,13 +173,13 @@ Click "Deploy" and Vercel will:
- Uploading Excel file (under 4MB for Hobby plan)
- Exporting data

### 5.3 Check API Logs
### 6.3 Check API Logs

In Vercel Dashboard → Functions → View logs for any errors

---

## Step 6: Post-Deployment
## Step 7: Post-Deployment

### Update Frontend URL (Optional)

Expand Down Expand Up @@ -212,6 +249,20 @@ This will:
- Verify `ALLOWED_ORIGINS` includes your current origin
- Test with public endpoints first (`/api/contributors`)

### "REDIRECT_URL_NOT_WHITELISTED" error on deployed domain

- The deployed domain has not been added to Stack Auth's Trusted Domains list
- Go to https://app.stack-auth.com -> Project Settings -> Domains or Trusted Domains
- Add the Vercel URL or custom domain where users are signing in
- Save the setting and test OAuth again

### OAuth login fails but password login works

- Confirm Stack Auth Trusted Domains includes the deployed domain
- Verify `VITE_STACK_PROJECT_ID` and `VITE_STACK_PUBLISHABLE_CLIENT_KEY` are set in Vercel
- Verify `STACK_SECRET_SERVER_KEY` is set for backend session verification
- Check Vercel integrations and remove unused Clerk or stale duplicate Neon integrations

### Cold starts are slow

- Normal for serverless on first request
Expand Down
Loading