feat(auth): add invite-only signup mode for production deployments#28
Open
Matt Van Horn (mvanhorn) wants to merge 1 commit into
Open
feat(auth): add invite-only signup mode for production deployments#28Matt Van Horn (mvanhorn) wants to merge 1 commit into
Matt Van Horn (mvanhorn) wants to merge 1 commit into
Conversation
README's "Before deploying to production" block calls out three production gaps; this PR addresses the smallest of them (invite-only signup) without touching the broader rate-limiting / billing surface. Behavior change is opt-in: ALLOW_OPEN_SIGNUP defaults to true so existing deployments and the Vercel template keep working unchanged. Operators flip the flag and set ADMIN_USER_EMAIL to gate signups behind invite codes minted from a new /dashboard/admin/invites page. The Better Auth databaseHooks.user.create.before hook claims an invite code atomically (prisma updateMany with WHERE usedAt IS NULL ... + SET usedAt=now) so concurrent signups can't reuse the same code. APIError surfaces a clear 'Invite code required' / 'Invalid or expired invite code' message back to the signup form. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the smallest of the three production gaps the README's "Before deploying to production" block calls out:
Adds opt-in invite-only signup: a new
ALLOW_OPEN_SIGNUPenv flag (defaulttrue, so existing deploys are unaffected), anInviteCodePrisma model, a Better AuthdatabaseHooks.user.create.beforehook that claims a code atomically at signup, and a minimal/dashboard/admin/invitespage guarded byADMIN_USER_EMAILfor minting and revoking codes.Behavior change
ALLOW_OPEN_SIGNUP=true(default): identical to today's behavior. No migration-required redeploy.ALLOW_OPEN_SIGNUP=false+ADMIN_USER_EMAILset: signup rejected without a valid invite code. Login form surfaces an "Invite code" field with a clear error message on rejection.prisma.inviteCode.updateManywithWHERE usedAt IS NULL AND (expiresAt IS NULL OR expiresAt > now). Concurrent signups can't reuse the same code.What changed
prisma/schema.prisma+ new migration:InviteCodetable (code, createdAt, createdBy, expiresAt, usedAt, usedByUser, note).src/env.ts:ALLOW_OPEN_SIGNUP(boolean, default true) andADMIN_USER_EMAIL(optional email).src/server/auth.ts:databaseHooks.user.create.beforehook; throwsAPIErroron missing/invalid/expired code.src/server/api/trpc.ts: newadminProcedure(session.user.email must matchADMIN_USER_EMAIL).src/server/api/routers/trustclaw/admin/:createInviteCode,listInviteCodes,revokeInviteCodeprocedures + schemas.src/app/(authenticated)/dashboard/admin/invites/: page +invite-list+create-invite-formshadcn components.src/app/login/_components/login-page.tsx: invite-code field rendered whenNEXT_PUBLIC_ALLOW_OPEN_SIGNUP=false..env.example+ README updates documenting the new flag.Validation
pnpm typecheckpasses.pnpm lintshows the same Prisma "type could not be resolved" warnings that exist onmain(affectssrc/server/clients/db.ts,src/server/api/routers/trustclaw/updateSettings.ts, etc.) - pre-existing ESLint module-resolution issue, not introduced by this diff.updateMany+ WHERE clause that includesusedAt: null.AI was used for assistance.