184 lines
7 KiB
Markdown
184 lines
7 KiB
Markdown
|
|
# BetterAuth Migration Checklist
|
|||
|
|
|
|||
|
|
This document covers the manual steps required to complete the Clerk → BetterAuth migration in both development and production.
|
|||
|
|
|
|||
|
|
**What's automated** (runs via `scripts/migrate.mjs` on every deploy, idempotent):
|
|||
|
|
- Schema migrations (sessions, accounts, verifications tables; nullable clerk_id; email_verified column)
|
|||
|
|
- Convert `teams.owner_id` and `commissioners.user_id` from Clerk IDs → `users.id` UUIDs
|
|||
|
|
- Mark all Clerk users as `email_verified = true`
|
|||
|
|
- Create `accounts` records for Google and Discord OAuth users (via Clerk API)
|
|||
|
|
|
|||
|
|
**What's manual** (one-time steps you do by hand):
|
|||
|
|
- Export user CSV from Clerk (for password hash migration)
|
|||
|
|
- Run the password migration script
|
|||
|
|
- Update OAuth redirect URIs in Google/Discord consoles
|
|||
|
|
- Set env vars in production
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Development
|
|||
|
|
|
|||
|
|
### Step 1 — Add environment variables
|
|||
|
|
|
|||
|
|
Add these to your `.env` file:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
BETTER_AUTH_SECRET="<random string — run: openssl rand -base64 32>"
|
|||
|
|
BETTER_AUTH_URL="http://localhost:5173"
|
|||
|
|
GOOGLE_CLIENT_ID="<from Clerk dashboard → Social Connections → Google>"
|
|||
|
|
GOOGLE_CLIENT_SECRET="<from Clerk dashboard → Social Connections → Google>"
|
|||
|
|
DISCORD_CLIENT_ID="<from Clerk dashboard → Social Connections → Discord>"
|
|||
|
|
DISCORD_CLIENT_SECRET="<from Clerk dashboard → Social Connections → Discord>"
|
|||
|
|
|
|||
|
|
# Keep temporarily for the automated OAuth migration (remove after confirmed working)
|
|||
|
|
CLERK_SECRET_KEY="<your existing value>"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Remove once confirmed working: `VITE_CLERK_PUBLISHABLE_KEY`, `CLERK_WEBHOOK_SECRET`, `DEV_ADMIN_CLERK_ID`
|
|||
|
|
|
|||
|
|
### Step 2 — Apply the database schema migration
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
npm run db:migrate
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Adds the `sessions`, `accounts`, and `verifications` tables; makes `clerk_id` nullable; adds `email_verified`.
|
|||
|
|
|
|||
|
|
### Step 3 — Add OAuth redirect URIs for localhost
|
|||
|
|
|
|||
|
|
In **Google Cloud Console** (APIs & Services → Credentials → your OAuth client):
|
|||
|
|
- Add `http://localhost:5173/api/auth/callback/google` to Authorized redirect URIs
|
|||
|
|
|
|||
|
|
In **Discord Developer Portal** (your app → OAuth2):
|
|||
|
|
- Add `http://localhost:5173/api/auth/callback/discord` to Redirects
|
|||
|
|
|
|||
|
|
### Step 4 — Run the automated data migration
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
node scripts/migrate.mjs
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
This converts owner IDs, creates Google/Discord OAuth accounts, and marks users as email-verified. It reads from the Clerk API using your `CLERK_SECRET_KEY`.
|
|||
|
|
|
|||
|
|
### Step 5 — Migrate email/password users
|
|||
|
|
|
|||
|
|
This requires exporting password hashes from Clerk (they're only in the CSV export, not the API).
|
|||
|
|
|
|||
|
|
1. Go to **Clerk dashboard → Users → Export** and download the CSV
|
|||
|
|
2. Save it as `exported_users.csv` in the project root (it's gitignored)
|
|||
|
|
3. Run:
|
|||
|
|
```bash
|
|||
|
|
node scripts/migrate-clerk-passwords.mjs
|
|||
|
|
```
|
|||
|
|
4. **Delete `exported_users.csv` immediately after** — it contains bcrypt password hashes
|
|||
|
|
|
|||
|
|
### Step 6 — Set yourself as admin
|
|||
|
|
|
|||
|
|
`DEV_ADMIN_CLERK_ID` no longer works. Set admin access directly in the database:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
UPDATE users SET is_admin = true WHERE email = 'your@email.com';
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Step 7 — Verify sign-in works
|
|||
|
|
|
|||
|
|
- **Google / Discord**: sign in immediately — OAuth accounts were migrated automatically
|
|||
|
|
- **Email/password**: sign in with the same password as before — bcrypt hashes were migrated
|
|||
|
|
- Check that league ownership and commissioner access still works
|
|||
|
|
|
|||
|
|
After verifying, remove `CLERK_SECRET_KEY` from `.env`.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Production
|
|||
|
|
|
|||
|
|
> Do Steps 1–3 before merging to main. The data migration (Step 4) and OAuth account creation run automatically on deploy.
|
|||
|
|
|
|||
|
|
### Step 1 — Add production environment variables
|
|||
|
|
|
|||
|
|
Add to your production environment (server docker-compose / secrets manager):
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
BETTER_AUTH_SECRET="<strong random string — openssl rand -base64 32>"
|
|||
|
|
BETTER_AUTH_URL="https://brackt.com"
|
|||
|
|
GOOGLE_CLIENT_ID="<same as Clerk dashboard>"
|
|||
|
|
GOOGLE_CLIENT_SECRET="<same as Clerk dashboard>"
|
|||
|
|
DISCORD_CLIENT_ID="<same as Clerk dashboard>"
|
|||
|
|
DISCORD_CLIENT_SECRET="<same as Clerk dashboard>"
|
|||
|
|
|
|||
|
|
# Keep temporarily — needed for the automated OAuth migration on first deploy
|
|||
|
|
CLERK_SECRET_KEY="<your existing production value>"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Step 2 — Add OAuth redirect URIs for production
|
|||
|
|
|
|||
|
|
In **Google Cloud Console**:
|
|||
|
|
- Add `https://brackt.com/api/auth/callback/google` to Authorized redirect URIs
|
|||
|
|
|
|||
|
|
In **Discord Developer Portal**:
|
|||
|
|
- Add `https://brackt.com/api/auth/callback/discord` to Redirects
|
|||
|
|
|
|||
|
|
### Step 3 — Migrate email/password users (before deploying)
|
|||
|
|
|
|||
|
|
The password migration runs against the production database directly — it does NOT go through Docker.
|
|||
|
|
|
|||
|
|
1. Go to **Clerk dashboard → Users → Export** and download the CSV for production users
|
|||
|
|
2. Save as `exported_users.csv` in the project root (gitignored)
|
|||
|
|
3. Run against the production database:
|
|||
|
|
```bash
|
|||
|
|
DATABASE_DIRECT_URL="<prod connection string>" CLERK_SECRET_KEY="<prod key>" node scripts/migrate-clerk-passwords.mjs
|
|||
|
|
```
|
|||
|
|
4. **Delete `exported_users.csv` immediately**
|
|||
|
|
|
|||
|
|
### Step 4 — Deploy
|
|||
|
|
|
|||
|
|
Merge to `main`. The GitHub Actions deploy will:
|
|||
|
|
1. Build and push the Docker image
|
|||
|
|
2. SSH to the server and run `docker compose up --no-deps migrate`
|
|||
|
|
3. `scripts/migrate.mjs` runs — applies schema migrations, then (because `CLERK_SECRET_KEY` is set):
|
|||
|
|
- Converts `teams.owner_id` and `commissioners.user_id` to `users.id` UUIDs
|
|||
|
|
- Marks users as `email_verified`
|
|||
|
|
- Creates `accounts` records for Google and Discord OAuth users
|
|||
|
|
4. The app container starts with the new BetterAuth code
|
|||
|
|
|
|||
|
|
### Step 5 — Verify production sign-in
|
|||
|
|
|
|||
|
|
- Google and Discord users: sign in immediately
|
|||
|
|
- Email/password users: sign in with the same password as before
|
|||
|
|
- Spot-check that league ownership and commissioner access are intact
|
|||
|
|
|
|||
|
|
### Step 6 — Remove Clerk credentials
|
|||
|
|
|
|||
|
|
Once everything is confirmed, remove from the production environment:
|
|||
|
|
```
|
|||
|
|
CLERK_SECRET_KEY
|
|||
|
|
VITE_CLERK_PUBLISHABLE_KEY
|
|||
|
|
CLERK_WEBHOOK_SECRET
|
|||
|
|
DEV_ADMIN_CLERK_ID
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Delete the Clerk webhook endpoint from the Clerk dashboard (it no longer exists in the codebase).
|
|||
|
|
|
|||
|
|
On the next deploy, `scripts/migrate.mjs` will log `"CLERK_SECRET_KEY not set — skipping Clerk account migration"` and skip gracefully.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Notes
|
|||
|
|
|
|||
|
|
### Why email/password migration is a separate manual step
|
|||
|
|
|
|||
|
|
Clerk's REST API does not expose password hashes — they're only available in the CSV dashboard export. The automated deploy script (`scripts/migrate.mjs`) handles OAuth accounts via the API, but password hashes must be exported manually and migrated with `scripts/migrate-clerk-passwords.mjs`.
|
|||
|
|
|
|||
|
|
The bcrypt hashes from Clerk are directly compatible with BetterAuth — no re-hashing is needed. Users sign in with the same password as before.
|
|||
|
|
|
|||
|
|
### What if a user signed up with both Google and email/password?
|
|||
|
|
|
|||
|
|
Both an OAuth account and a credential account will be created for them. BetterAuth handles this correctly — the user can sign in with either method.
|
|||
|
|
|
|||
|
|
### Future cleanup
|
|||
|
|
|
|||
|
|
After the migration is stable (a week or two after production deploy), open a follow-up PR to:
|
|||
|
|
1. Remove the `clerk_id` column from `database/schema.ts` and run `npm run db:generate`
|
|||
|
|
2. Remove `CLERK_SECRET_KEY` handling from `scripts/migrate.mjs`
|
|||
|
|
3. Delete `scripts/migrate-clerk-passwords.mjs`
|