xtablo-source/.planning/phases/08-social-sign-in/08-CONTEXT.md
2026-05-15 20:35:41 +02:00

9 KiB

Phase 8: Social Sign-in - Context

Gathered: 2026-05-15 Status: Ready for planning

## Phase Boundary

Add Google and Apple sign-in to the existing Go + HTMX auth system. Provider login must create or link local Xtablo users, then issue the same server-managed session cookie used by email/password auth.

Delivers AUTH-08, AUTH-09, AUTH-10, AUTH-11, AUTH-12, AUTH-13. Not in scope: managed auth platforms, password reset/add-password flows, provider unlinking, MFA, passkeys, or broader account management.

## Implementation Decisions

Account Linking

  • D-01: If Google/Apple returns a verified email matching an existing Xtablo user, automatically link the provider identity to that user and sign them in.
  • D-02: If provider email is missing or not verified, reject the callback with a clear error. Do not create or link an account from unverified/missing provider email.
  • D-03: Once a provider subject is linked, provider identity wins on future callbacks. Sign in the already-linked Xtablo user even if the provider email later changes.
  • D-04: Phase 8 includes a simple linked providers account view showing Google/Apple connection status. Provider unlink actions are deferred unless planning finds they are trivial and low-risk.

Social-Only Accounts

  • D-05: Allow passwordless local users by making users.password_hash nullable. Email/password login only applies to users whose password_hash is present.
  • D-06: Social-only users can exist without a password. Adding a password later is deferred beyond Phase 8.
  • D-07: If email/password signup is attempted for an email that already belongs to a social-only user, block signup and show a clear message asking the user to sign in with the provider.
  • D-08: Existing email/password users who link Google/Apple become hybrid accounts and keep password login enabled.

Login and Signup Surface

  • D-09: Show Google and Apple sign-in buttons on both login and signup pages. The provider callback decides whether to create, link, or sign in.
  • D-10: If required provider config is missing, render the provider button disabled with a plain not-configured state. This keeps the intended UI visible in local/dev.
  • D-11: Google and Apple have equal prominence wherever provider buttons are shown.
  • D-12: Successful social sign-in redirects to /, matching existing email/password login and signup behavior.

Provider Profile Data

  • D-13: Store provider display name and avatar URL where providers supply them, in addition to provider, provider subject, verified email, and timestamps.
  • D-14: Apple may provide name only on first authorization. Persist Apple name immediately if present in the callback payload.
  • D-15: Accept Apple private relay emails as verified emails when Apple marks them verified.
  • D-16: If the same provider subject later returns a new verified email, update user_identities.email. Provider subject remains the durable external identity key.
  • D-17: When provider email changes, update local users.email too.

the agent's Discretion

  • Exact table/column names are planner discretion, but the data model must support provider, subject, verified email, display name, avatar URL, provider timestamps, and unique (provider, subject).
  • Exact copy for provider errors, disabled provider buttons, and duplicate/social-only signup messages is planner discretion, but messages must be clear and avoid leaking unnecessary security detail.
  • Planner must handle users.email update conflicts explicitly because users.email is unique. If a provider email update collides with another local user, do not silently relink or overwrite another account.
  • Exact route names for account/linked-provider status are planner discretion, but the view should be protected and minimal.

<canonical_refs>

Canonical References

Downstream agents MUST read these before planning or implementing.

Phase Scope

  • .planning/PROJECT.md — v2.0 constraints: Google/Apple are identity providers only; Xtablo owns users and sessions.
  • .planning/REQUIREMENTS.md — AUTH-08..AUTH-13 define Phase 8 requirements.
  • .planning/ROADMAP.md — Phase 8 goal, success criteria, and user-in-loop schema/account-linking gate.
  • .planning/research/SUMMARY.md — Research summary for Google/Apple OIDC and local session integration.
  • .planning/research/STACK.md — Provider config, OIDC/JWT verification notes, and recommended stack additions.
  • .planning/research/PITFALLS.md — OAuth state/nonce, provider subject, Apple first-login-only profile data, and email verification pitfalls.

Prior Auth Decisions

  • .planning/phases/02-authentication/02-CONTEXT.md — Existing session, cookie, CSRF, middleware order, rate-limit, and password-auth decisions.
  • .planning/phases/07-deploy-v1/07-CONTEXT.md — Production env-file secret management and deploy constraints relevant to provider secrets.

Codebase Entry Points

  • backend/internal/web/handlers_auth.go — Existing signup/login/logout handlers; social callback should reuse local session creation behavior.
  • backend/internal/auth/session.go — Existing session store; social sign-in must issue sessions through this path.
  • backend/internal/auth/cookie.go — Session cookie behavior.
  • backend/internal/auth/middleware.goResolveSession, RequireAuth, RedirectIfAuthed middleware behavior.
  • backend/internal/db/queries/users.sql — Existing user insert/lookup query shape; Phase 8 changes nullable password handling and identity lookup/linking.
  • backend/internal/db/queries/sessions.sql — Existing session query shape.
  • backend/migrations/0002_auth.sql — Current users.password_hash NOT NULL; Phase 8 migration must change this.
  • backend/templates/auth_login.templ — Login page provider button insertion point.
  • backend/templates/auth_signup.templ — Signup page provider button insertion point.
  • backend/.env.example — Add Google and Apple provider config without secrets.

</canonical_refs>

<code_context>

Existing Code Insights

Reusable Assets

  • auth.Store.Create / auth.Store.Rotate: issue local session cookies after provider verification.
  • auth.SetSessionCookie: keep cookie behavior identical across email/password and social sign-in.
  • auth.RedirectIfAuthed: existing auth-page redirect behavior should still apply to login/signup pages.
  • templates.LoginPage and templates.SignupPage: wrap auth forms in a Card; provider buttons can be added consistently on both pages.
  • ui.Button: reusable button component for provider buttons and disabled provider states.

Established Patterns

  • Form handlers read values through r.PostFormValue because gorilla/csrf may consume request bodies; OAuth callback handlers should keep callback parsing simple and avoid body-read surprises.
  • Existing successful auth paths redirect to /; social sign-in should match this.
  • Password hashing is argon2id and remains only for email/password users.
  • Sessions are DB-backed and store a SHA-256 hash of the raw cookie token; provider tokens must never become Xtablo sessions.
  • Route ordering in chi uses static routes before parametric routes; provider start/callback routes should follow this pattern.
  • Config lives in env vars and .env.example; production secrets are host .env values per deploy context.

Integration Points

  • backend/internal/web/router.go: add provider start/callback routes around existing auth page and POST routes.
  • backend/cmd/web/main.go: parse provider config and pass it through auth/web dependencies.
  • backend/migrations/: add Phase 8 migration for nullable password hashes and user_identities.
  • backend/internal/db/queries/: add identity insert/get/update/linking queries, and adjust user queries for nullable password hash.
  • backend/templates/auth_login.templ and backend/templates/auth_signup.templ: add equal-prominence Google/Apple buttons and disabled config states.
  • backend/templates/layout.templ or a new account template: expose a minimal linked providers view for authenticated users.

</code_context>

## Specific Ideas
  • Account linking is intentionally optimistic for verified provider emails to keep the early product flow smooth.
  • Provider subject is the stable identity key; email can change and should not drive relinking once a subject is linked.
  • Apple private relay is accepted as a normal verified email when Apple verifies it.
  • Store display name and avatar URL when supplied, but do not make them required for account creation.
  • Local users.email should follow provider email changes, but planner must guard the unique-email conflict path.
## Deferred Ideas
  • Provider unlink actions.
  • Add-password/password management for social-only users.
  • Password reset flow.
  • MFA.
  • Passkeys/WebAuthn.
  • Redirecting back to the originally requested protected URL after OAuth.
  • Provider-specific welcome/onboarding page.

Phase: 8-Social Sign-in Context gathered: 2026-05-15