Skip to content

Accounts & favorites ​

  • Sign-in: Google Identity Services button (apps/web/src/components/GoogleSignIn.tsx) → ID token → POST /v1/account/auth/google. The API verifies issuer, audience (GOOGLE_CLIENT_ID), RS256 and email_verified against Google's public keys (workers/api/src/modules/account/auth.ts, tested with forged/expired/wrong-audience tokens).
  • Session: opaque random token in an HttpOnly; Secure; SameSite=Lax cookie al365_session scoped to COOKIE_DOMAIN (artlove365.com) so the site and api. share it. Only its SHA-256 is stored (sessions). 90 days.
  • CSRF: every non-GET /v1/account/* call must come from an artlove365.com origin (or localhost in dev).
  • Favorites: anonymous → localStorage["artlove365.favorites"]; signed in → favorites table. At sign-in the browser's list is merged into the account (POST /v1/account/favorites/merge), and the local copy is kept as a mirror for instant hearts.
  • No Client ID yet? GOOGLE_CLIENT_ID is empty → sign-in UI is hidden, favorites still work locally. Setup: roadmap OPS-01.

Setting up the Google Client ID (OPS-01) ​

  1. Google Cloud Console → APIs & Services → Credentials → Create credentials → OAuth client ID → Web application.
  2. Authorized JavaScript origins: https://artlove365.com, http://localhost:5173.
  3. Copy the Client ID (it is public) into GOOGLE_CLIENT_ID in workers/api/wrangler.jsonc, push to main.

Local dev: workers/api/.dev.vars must contain COOKIE_DOMAIN="" (http, host-only cookie).