Skip to content

ADR-022: Expand Authentication Beyond Magic Links

Status: Accepted Date: 2026-04-10

Context

Sync uses Supabase magic link (OTP) as its only authentication method. On the Supabase free tier, email sending is rate-limited to ~2 emails per hour, which blocks onboarding when multiple people try to sign up or log in during the same session. With Sync opening to a broader public audience (many arriving from Telegram), the single magic-link path is a bottleneck.

Decision

Add two additional authentication methods alongside magic link:

1. Email + Password

  • Signup: email, password, confirm password. Supabase sends a confirmation email (one-time), then the user logs in with their password — no further emails required.
  • Login: email + password, with a toggle to switch to magic link mode.
  • Password minimum: 6 characters (Supabase default).

2. Google OAuth

  • "Continue with Google" button on both login and signup pages.
  • Uses Supabase's built-in Google provider via signInWithOAuth({ provider: 'google' }).
  • Requires one-time setup in Google Cloud Console + Supabase dashboard (client ID and secret).

UI Design

  • Google button appears first (most frictionless path).
  • "or" divider separates OAuth from email-based options.
  • Login page: toggle between Password and Magic Link modes.
  • Signup page: password fields shown by default, with "Use a magic link" toggle at the bottom.

Rationale

  • Password auth has no rate limit — users can sign up and log in immediately without waiting for an email. This is the primary bottleneck fix.
  • Google OAuth is zero-friction — no password to remember, one click. Most people have a Google account.
  • Magic link stays available — some users prefer passwordless auth, and existing users who signed up via magic link can continue using it.
  • All three methods share the same Supabase auth system — the callback route, middleware session refresh, and profile auto-creation all work regardless of auth method.

Alternatives Considered

  • Upgrade Supabase plan for higher email limits: Solves the rate limit but costs money and doesn't address the UX friction of waiting for emails. Password auth is strictly better for users who prefer it.
  • Telegram Login (OIDC): Telegram recently added OpenID Connect support, which could work as a custom OIDC provider in Supabase. Deferred because the setup is more involved (BotFather registration, custom OIDC configuration) and less battle-tested. Worth revisiting once the core auth expansion is stable and if Telegram users report friction.
  • GitHub OAuth: Easy to add (same pattern as Google) but less useful for the non-developer audience arriving from Telegram. Can be added later with a single button + dashboard config.

Discussion

The key trade-off is simplicity vs. coverage. Magic link was elegant — one field, no password to forget. But the rate limit makes it a hard blocker for public launch. Password auth solves the blocker, Google OAuth reduces friction further, and keeping magic link preserves the original experience for those who prefer it.

The callback route required minimal changes — OAuth uses PKCE (already handled via exchangeCodeForSession), and password signup confirmation uses verifyOtp with type='signup' (same token_hash path as magic links). The onboarding redirect logic applies uniformly regardless of auth method.

Telegram login was considered but deferred. Many users will arrive from Telegram, but they can use email/password or Google to sign up. If we see significant drop-off from Telegram users specifically, we'll revisit with a custom OIDC integration.

Consequences

  • Users now have three ways to authenticate: password, magic link, or Google OAuth
  • The login page has a Password/Magic Link toggle (defaulting to password)
  • The signup page defaults to password with an option to switch to magic link
  • Google OAuth requires one-time dashboard configuration (Google Cloud + Supabase)
  • The post_discussion_actions and profile system are unaffected — auth method is transparent to the game
  • Existing magic-link-only users can continue using magic links or set a password via Supabase's password reset flow

Key files: - src/app/auth/login/page.tsx — Multi-method login with password/magic-link toggle and Google OAuth - src/app/auth/signup/page.tsx — Password signup with magic link fallback and Google OAuth - src/app/auth/callback/route.ts — Handles PKCE (OAuth), token_hash (magic link + email confirmation)