feat: Google OAuth sign-in + per-user Gemini API key

Users with Google accounts can now sign in without a password.

Auth flow:
- GET /auth/google → Google consent page (CSRF state cookie)
- GET /auth/google/callback → exchange code, lookup user, set JWT
- auth.json gains google_sub + google_email fields
- set_password() no longer overwrites unrelated auth.json fields

Admin setup:
  python manage_passwords.py google-add <username> <email>
  # add GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET to .env

Per-user Gemini key:
- get_user_gemini_key() reads gemini_api_key from auth.json
- orchestrator_engine.run() accepts gemini_api_key param
- orchestrator router passes user's key, falls back to server key

login.html: "Sign in with Google" button above the password form.
manage_passwords.py list: now shows auth method columns (pw / google).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-03-27 21:01:52 -04:00
parent 62fde62653
commit 8aec6aafcc
10 changed files with 376 additions and 21 deletions

View File

@@ -5,6 +5,12 @@ from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
anthropic_api_key: str | None = None # not used — claude CLI handles auth
# Google OAuth — "Sign in with Google" for all users
# Create credentials at console.cloud.google.com → APIs & Services → Credentials
# Add https://<your-domain>/auth/google/callback as an authorised redirect URI
google_client_id: str | None = None
google_client_secret: str | None = None
# Orchestrator (Gemini API — separate from Gemini CLI)
# Get a key at: https://aistudio.google.com/apikey (free tier is sufficient)
gemini_api_key: str | None = None