2 Commits

Author SHA1 Message Date
thejayman77 15728c3bcb User avatar (Google picture), avatar in mobile You tab, /account page
- Capture the Google profile picture (picture claim) into users.avatar_url; an
  Avatar component shows it, falling back to the initial. Used in the desktop
  header and the mobile "You" tab (which now shows the user when signed in).
- Move account/settings to its own route /account (robust + scrolls to top),
  reached by the desktop avatar and the mobile You tab; drop the inline "You"
  sheet. AccountPanel gains a Sign out action; the page links to Saved/History/
  Boundaries via home intent params (?view= / ?open=).
- db: users.avatar_url (schema + idempotent migration). 118 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 14:41:43 +00:00
thejayman77 b635d8f574 Accounts Phase 2: Google sign-in (OAuth 2.0 / OIDC)
- oauth_google.py (stdlib): PKCE, auth URL, code exchange, ID-token claim
  validation (iss/aud/exp/email_verified — token comes straight from Google's
  token endpoint over TLS, so no signature re-verify / JWKS needed).
- API: GET /api/auth/google/start (302 to Google, PKCE + signed state cookie
  binding the flow to the browser) and /callback (CSRF-checked state, exchange,
  find-or-create by verified email → links to an existing magic-link account,
  session cookie, redirect home). Errors land on /auth/verify?error=google.
- SignIn modal: "Continue with Google" + an "or email link" divider.
- 112 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 01:31:52 +00:00