Multi-Provider Sign-In
GitHub, Google, Facebook, and X sign-in via NextAuth v4
Overview
Users sign in with GitHub, Google, Facebook, or X (Twitter OAuth 2.0) via NextAuth v4, backed by a Postgres adapter. Any linked provider identity resolves to the same User row in Postgres — session.user.id is that row's id, and is what everything else in the app (song ownership, uploads) keys off.
A signed-in user who didn't start with GitHub can later "Connect GitHub" to unlock self-hosted (GITHUB-backed) songs — see Storage Backends.
How it works
src/lib/auth.tsbuilds the NextAuthproviderslist dynamically: a provider only registers if its_CLIENT_ID/_CLIENT_SECRETenv vars are both set (enabledProviderIdsexports the resulting list). This keeps unconfigured providers (Facebook/X, until credentials exist) out of the sign-in UI entirely rather than rendering a button that errors on click.- Session strategy is JWT, not database sessions — the
jwt/sessioncallbacks copyuser.idand (for GitHub) the GitHubloginonto the token/session. allowDangerousEmailAccountLinking: falseon every provider — two providers never auto-merge into one account just because the email matches. Linking only happens through the explicit "Connect GitHub" flow (ConnectGithubButton.tsx), which relies on NextAuth v4 already decoding the active session cookie during an OAuth callback and linking the new identity to that user (rejecting withOAuthAccountNotLinkedif the GitHub identity belongs to someone else).- X/Twitter uses OAuth 2.0, which does not return an email — code must never assume
session.user.emailexists for X sign-ins.
Key files
| File | Role |
|---|---|
src/lib/auth.ts | Provider list, JWT/session callbacks, enabledProviderIds |
src/components/ConnectGithubButton.tsx | signIn('github') while already authenticated, to link GitHub |
prisma/schema.prisma | User/Account/Session/VerificationToken adapter tables |
Limitations / notes
- Apple sign-in is intentionally not implemented (needs a paid Apple Developer account + a JWT client secret rotated every 6 months).
- GitHub's OAuth App callback URL is a single field (classic OAuth Apps don't support multiple), so it's manually switched between local dev and production.