go-htmx-gsd #1
2 changed files with 212 additions and 0 deletions
137
.planning/phases/08-social-sign-in/08-CONTEXT.md
Normal file
137
.planning/phases/08-social-sign-in/08-CONTEXT.md
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
# Phase 8: Social Sign-in - Context
|
||||
|
||||
**Gathered:** 2026-05-15
|
||||
**Status:** Ready for planning
|
||||
|
||||
<domain>
|
||||
## 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.
|
||||
|
||||
</domain>
|
||||
|
||||
<decisions>
|
||||
## 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.
|
||||
|
||||
</decisions>
|
||||
|
||||
<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`, `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>
|
||||
|
||||
<specifics>
|
||||
## 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.
|
||||
|
||||
</specifics>
|
||||
|
||||
<deferred>
|
||||
## 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.
|
||||
|
||||
</deferred>
|
||||
|
||||
---
|
||||
|
||||
*Phase: 8-Social Sign-in*
|
||||
*Context gathered: 2026-05-15*
|
||||
75
.planning/phases/08-social-sign-in/08-DISCUSSION-LOG.md
Normal file
75
.planning/phases/08-social-sign-in/08-DISCUSSION-LOG.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# Phase 8: Social Sign-in - Discussion Log
|
||||
|
||||
> **Audit trail only.** Do not use as input to planning, research, or execution agents.
|
||||
> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
|
||||
|
||||
**Date:** 2026-05-15
|
||||
**Phase:** 8-Social Sign-in
|
||||
**Areas discussed:** Account linking, Social-only accounts, Login/signup surface, Provider profile data
|
||||
|
||||
---
|
||||
|
||||
## Account Linking
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Auto-link verified email | If provider email is verified and matches an existing user, attach provider identity and sign them in. | ✓ |
|
||||
| Require current password first | Matching email lands on a confirm-password step before linking. | |
|
||||
| Only link while already signed in | Social login creates a separate account unless explicitly linked from account settings. | |
|
||||
|
||||
**User's choice:** Auto-link verified email.
|
||||
**Notes:** Missing or unverified provider email is rejected with a clear error. If a provider subject is already linked, provider identity wins over later email changes. Add a simple linked providers status view; unlinking is deferred.
|
||||
|
||||
---
|
||||
|
||||
## Social-Only Accounts
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Allow passwordless users | Make `users.password_hash` nullable; social users can exist without passwords. | ✓ |
|
||||
| Generate unusable password hash | Keep `password_hash NOT NULL` with a sentinel hash. | |
|
||||
| Require setting password after social signup | Social signup creates account, then immediately asks user to set password. | |
|
||||
|
||||
**User's choice:** Allow passwordless users.
|
||||
**Notes:** Adding a password later is deferred. Email/password signup is blocked if a social-only account already owns that email. Existing password users linked to Google/Apple keep password login.
|
||||
|
||||
---
|
||||
|
||||
## Login/Signup Surface
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Both login and signup pages | Same provider buttons on both pages; callback handles create/link/sign-in. | ✓ |
|
||||
| Login page only | Treat social auth as sign-in, with account creation implicit after callback. | |
|
||||
| Signup page only | Use social only for account creation. | |
|
||||
|
||||
**User's choice:** Both login and signup pages.
|
||||
**Notes:** Show disabled provider buttons when config is missing. Google and Apple get equal prominence. Successful social sign-in redirects to `/`.
|
||||
|
||||
---
|
||||
|
||||
## Provider Profile Data
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Minimal identity only | Store provider, subject, email, email_verified, and timestamps only. | |
|
||||
| Store display name too | Persist provider name where available. | |
|
||||
| Store name and avatar | Persist provider name and profile image URL where available. | ✓ |
|
||||
|
||||
**User's choice:** Store name and avatar.
|
||||
**Notes:** User first answered minimal identity, then explicitly returned to this question and changed the answer to store name and avatar. Apple private relay emails are accepted as verified if Apple verifies them. Provider identity email and local `users.email` should update when provider verified email changes.
|
||||
|
||||
---
|
||||
|
||||
## the agent's Discretion
|
||||
|
||||
- Exact database field names and route names.
|
||||
- Exact disabled-provider and provider-error copy.
|
||||
- Exact handling of local email update conflicts, provided it does not silently overwrite or relink another account.
|
||||
|
||||
## Deferred Ideas
|
||||
|
||||
- Provider unlink actions.
|
||||
- Add-password/password management for social-only users.
|
||||
- Password reset flow.
|
||||
- Redirect-after-login return URL through OAuth state.
|
||||
Loading…
Reference in a new issue