9 KiB
9 KiB
Phase 8: Social Sign-in - Context
Gathered: 2026-05-15 Status: Ready for planning
## Phase BoundaryAdd 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 DecisionsAccount 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_hashnullable. Email/password login only applies to users whosepassword_hashis 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.emailtoo.
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.emailupdate conflicts explicitly becauseusers.emailis 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.go—ResolveSession,RequireAuth,RedirectIfAuthedmiddleware 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— Currentusers.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.LoginPageandtemplates.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.PostFormValuebecause 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.envvalues 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 anduser_identities.backend/internal/db/queries/: add identity insert/get/update/linking queries, and adjust user queries for nullable password hash.backend/templates/auth_login.templandbackend/templates/auth_signup.templ: add equal-prominence Google/Apple buttons and disabled config states.backend/templates/layout.templor 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.emailshould follow provider email changes, but planner must guard the unique-email conflict path.
- 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