fix(auth): unblock OAuth signups by supplying slug for auto-default team#4435
Conversation
Better Auth's organization plugin auto-creates a default team during
createOrganization when teams.enabled is true (crud-org.mjs:106-136),
hard-coding teamData = { organizationId, name, createdAt } with no slug.
Our auth.teams.slug is NOT NULL with no default, so every new-user OAuth
signup was aborting with unable_to_create_user.
Use customCreateDefaultTeam to own the auto-team insert and supply a
constant "DEFAULT" slug. Drop the duplicate db.insert(teams) from
afterCreateOrganization — better-auth already creates exactly one team
per new org, the manual insert was just shadowed by the failing
auto-insert running first.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughDefault team creation is refactored from inline hook logic to a dedicated configuration-driven function. The ChangesDefault Team Creation
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🚀 Preview Deployment🔗 Preview Links
Preview updates automatically with new commits |
Greptile SummaryThis PR fixes a regression introduced in #4403 where every new Google OAuth signup was failing because Better Auth's auto-default team insert omitted the
Confidence Score: 4/5Safe to merge; the change is narrow and directly addresses the broken signup flow. The change is focused and the schema confirms slug uniqueness is scoped per-org, so the hardcoded DEFAULT value is safe across all orgs. One thing worth watching: customCreateDefaultTeam commits the team row before afterCreateOrganization runs, so a Stripe failure in that hook would leave an org with a committed team but no stripeCustomerId set — though this ordering concern is an artifact of the pre-existing hook structure, not something this PR makes worse. Only packages/auth/src/server.ts changed; no other files need attention.
|
| Filename | Overview |
|---|---|
| packages/auth/src/server.ts | Adds customCreateDefaultTeam with hardcoded slug="DEFAULT" to satisfy the NOT NULL constraint on team slug during org creation; removes the now-redundant manual team insert from afterCreateOrganization. Logic is correct given the composite unique index on (organizationId, slug). |
Sequence Diagram
sequenceDiagram
participant User
participant BetterAuth
participant customCreateDefaultTeam
participant DB
participant afterCreateOrg
User->>BetterAuth: Google OAuth signup
BetterAuth->>DB: INSERT INTO auth.organizations
BetterAuth->>customCreateDefaultTeam: "organization {id, name, slug}"
customCreateDefaultTeam->>DB: "INSERT INTO auth.teams (name=Default Team, slug=DEFAULT, organizationId)"
DB-->>customCreateDefaultTeam: team row
customCreateDefaultTeam-->>BetterAuth: team
BetterAuth->>DB: INSERT INTO auth.team_members (teamId, userId)
BetterAuth->>afterCreateOrg: "{organization, user}"
afterCreateOrg->>DB: Stripe customer create + UPDATE organizations SET stripeCustomerId
afterCreateOrg->>DB: seedDefaultStatuses(organizationId)
afterCreateOrg-->>BetterAuth: done
BetterAuth-->>User: signup complete
Reviews (1): Last reviewed commit: "fix(auth): supply slug for better-auth's..." | Re-trigger Greptile
Summary
/api/auth/callback/googlewithunable_to_create_user.createOrganization(crud-org.mjs:106-136) and hard-codesteamData = { organizationId, name, createdAt }— noslug. Ourauth.teams.slugisNOT NULLwith no default, so the insert aborted with a constraint violation, rolling back the whole signup transaction.teams.defaultTeam.customCreateDefaultTeamto own the auto-team insert and supply a constant"DEFAULT"slug. Drop the now-duplicatedb.insert(teams)fromafterCreateOrganization.Why this hook (and not
beforeCreateTeam/afterCreateOrganization)beforeCreateTeamfires on both the auto-default path and user-initiatedcreateTeamcalls from the Settings → Teams UI (crud-team.mjs:107). Unconditionally returning{ slug: "DEFAULT" }would clobber user-chosen slugs.afterCreateOrganizationruns at line 137 — after the broken auto-team insert at line 126. The transaction already aborts before we'd get there.customCreateDefaultTeamis the dedicated callback consulted only on the auto-default path.Existing orgs
Untouched. They keep the team backfilled by migration
0049(slug = org slug). Only orgs created after this deploys getslug="DEFAULT".Test plan
allowedDomains. Confirm signup completes and lands in/.auth.teamswithname='Default Team',slug='DEFAULT', and exactly one matching row inauth.team_membersfor the new user.allowedDomainsand confirm the user lands in that org (no new org / default team created).Summary by cubic
Unblocks OAuth signups by ensuring the auto-created default team gets a slug. This removes the NOT NULL violation on
auth.teams.slugduring org creation.teams.defaultTeam.customCreateDefaultTeamwith name "Default Team" andslug="DEFAULT".afterCreateOrganization.Written for commit 8eb3055. Summary will update on new commits.
Summary by CodeRabbit