Skip to content

auth: collect verified primary email from GitHub - #37

Open
utsengar wants to merge 1 commit into
mainfrom
users-email-collection
Open

auth: collect verified primary email from GitHub#37
utsengar wants to merge 1 commit into
mainfrom
users-email-collection

Conversation

@utsengar

Copy link
Copy Markdown
Owner

Summary

  • Expands OAuth scope from read:user to read:user user:email.
  • Adds users.email (nullable, no UNIQUE) via migration 0003-add-user-email.sql and updates schema.sql for fresh installs.
  • Callback now hits /user/emails, picks the primary + verified entry, and stores it. Email is optional — sign-in never blocks on it (denied scope / no verified email / lookup failure → NULL).
  • Refreshed on every sign-in via updateUserEmail(), so pre-user:email users (including StressLessAgency) get their email backfilled the first time they sign in again.
  • Dashboard npm run dashboard user-detail page surfaces the email as a mailto: link, which is the whole point — one click to reach the owner.
  • CLAUDE.md hard rule docs: tighten README intro line (test preview deploy) #4 expanded to document the new exception. No marketing list, no transactional email, no unsubscribe surface, no user-facing email UI.
  • Dev-mock OAuth path synthesizes <mock_login>@example.test (reserved TLD, can't accidentally send mail) so the e2e script keeps working.

Caveats

  • No backfill for inactive users. Anyone who never signs in again will keep email IS NULL forever. There is no scheduled backfill job (would need server-side write access to all users' GitHub accounts, which we don't have).
  • Existing users will see the GitHub consent screen on next sign-in because the requested scope changed. That's how OAuth re-consent works; not a regression.
  • Database migration needed on prod. After merge: npm run db:migrate:remote to add the column.

Test plan

  • Preview URL boots, /verify flow works against a real GitHub account
  • First sign-in on a new account writes the verified primary email to users.email
  • Re-sign-in on an existing account refreshes users.email (verify via dashboard)
  • Sign in with a GitHub account that has no verified primary email → sign-in still succeeds, users.email IS NULL
  • npm run dashboard user-detail page shows the email as a mailto: link
  • ./scripts/agent-e2e.sh against the preview URL still passes (dev-mock synthesizes *@example.test)
  • After merge: npm run db:migrate:remote applied; verify users schema includes email TEXT

🤖 Generated with Claude Code

Adds users.email column + 0003 migration. Expands OAuth scope to
read:user user:email so the callback can hit /user/emails and persist
the primary+verified address. Email is optional — sign-in never blocks
on it (denied scope / no verified email / lookup failure → NULL).
Refreshed on every sign-in, so pre-user:email rows backfill the first
time their owner signs in again.

No UNIQUE constraint on email: two distinct GitHub accounts can
legitimately share an address. github_user_id remains the identity.

Dashboard user-detail page surfaces the email as a mailto: link so
operator outreach (e.g. "are you the StressLessAgency publishing X?")
is one click. No automated send, no marketing list, no unsubscribe
surface, no user-facing email UI — disclosure is the GitHub consent
screen only. CLAUDE.md rule #4 expanded to document the new exception.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🚀 Cloudflare preview

URL: https://ee4267d4-htmlbin.utkarsh2012.workers.dev

Built from commit 19de7a64ffd85913afc95cf7bc608fe6fd3a0989.

Note: bindings (D1, KV, AI) are shared with production.
Avoid destructive PR tests on real data.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant