security: fix GoogleLoginView audience check + replace Clerk with direct GIS flow
- verify_oauth2_token now passes GOOGLE_CLIENT_ID as third arg (audience check)
- fail-closed: returns 503 if GOOGLE_CLIENT_ID env var is not set
- add GOOGLE_CLIENT_ID = os.environ.get('GOOGLE_CLIENT_ID', '') to settings
- replace ClerkLoginViewTests with GoogleLoginViewTests (4 cases)
- update requirements-docker.txt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
25
CHANGELOG.md
25
CHANGELOG.md
@@ -5,6 +5,31 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), version
|
||||
|
||||
---
|
||||
|
||||
## [1.10.0] — 2026-04-10
|
||||
|
||||
### Security
|
||||
- **`GoogleLoginView` audience-check fix** (`POST /api/user/google-login/`) — **CRITICAL security patch**
|
||||
- `verify_oauth2_token(token, google_requests.Request())` was called **without** the third `audience` argument, meaning any valid Google-signed ID token from *any* OAuth client was accepted — token spoofing from external apps was trivially possible
|
||||
- Fixed to `verify_oauth2_token(token, google_requests.Request(), settings.GOOGLE_CLIENT_ID)` — only tokens whose `aud` claim matches our registered Client ID are now accepted
|
||||
- Added fail-closed guard: if `settings.GOOGLE_CLIENT_ID` is empty the view returns HTTP 503 instead of silently accepting all tokens
|
||||
|
||||
### Changed
|
||||
- **Removed Clerk scaffolding** — the `@clerk/react` broker approach added in a prior iteration has been replaced with direct Google Identity Services (GIS) ID-token flow on the frontend. Simpler architecture: one trust boundary instead of three.
|
||||
- Removed `ClerkLoginView`, `_clerk_jwks_client`, `_get_clerk_jwks_client()` from `mobile_api/views/user.py`
|
||||
- Removed `path('user/clerk-login/', ...)` from `mobile_api/urls.py`
|
||||
- Removed `CLERK_JWKS_URL` / `CLERK_ISSUER` / `CLERK_SECRET_KEY` from `eventify/settings.py`; replaced with `GOOGLE_CLIENT_ID = os.environ.get('GOOGLE_CLIENT_ID', '')`
|
||||
- Removed `PyJWT[crypto]>=2.8.0` and `requests>=2.31.0` from `requirements.txt` + `requirements-docker.txt` (no longer needed; `google-auth>=2.0.0` handles verification)
|
||||
|
||||
### Added
|
||||
- **Settings**: `GOOGLE_CLIENT_ID = os.environ.get('GOOGLE_CLIENT_ID', '')` in `eventify/settings.py`
|
||||
- **Tests**: `mobile_api/tests.py::GoogleLoginViewTests` — 4 cases: valid token creates user (audience arg verified), missing `id_token` → 400, `ValueError` (wrong sig / wrong aud) → 401, existing user reuses DRF token
|
||||
|
||||
### Context
|
||||
- The consumer SPA (`app.eventifyplus.com`) now loads the Google Identity Services script dynamically and POSTs a Google ID token to the existing `/api/user/google-login/` endpoint. Django is the sole session authority. `localStorage.event_token` / `event_user` are unchanged.
|
||||
- Deploy requirement: set `GOOGLE_CLIENT_ID` in the Django container `.env` **before** deploying — without it the view returns 503 (fail-closed by design).
|
||||
|
||||
---
|
||||
|
||||
## [1.9.0] — 2026-04-07
|
||||
|
||||
### Added
|
||||
|
||||
Reference in New Issue
Block a user