Skip to content

feat(auth): authentication, subscriptions, and critical security hardening#20

Merged
marinone94 merged 4 commits into
mainfrom
feat/auth-with-security-hardening
Mar 11, 2026
Merged

feat(auth): authentication, subscriptions, and critical security hardening#20
marinone94 merged 4 commits into
mainfrom
feat/auth-with-security-hardening

Conversation

@marinone94

Copy link
Copy Markdown
Owner

Summary

  • Supabase JWT auth with PyJWT library (validates signature, expiry, audience, not-before)
  • API key auth — SHA-256 hashed, prefix for display, ck_live_ format
  • Tier system — Free/Pro ($19/mo)/Ultra ($49/mo) with Polar.sh webhook integration
  • 7-day Ultra trial for new signups with effective_tier() helper
  • Rate limiting — in-memory per-minute burst + PostgreSQL daily quotas (semantic, LLM)
  • IDOR fix — ownership checks on all collection mutations (create, update, delete, add/remove examples)
  • Config validator — auth auto-disables with warning when JWT secret is missing
  • UNIQUE email — migration 006 adds constraint on users.email
  • GDPR endpointsDELETE /account/me (Art. 17 erasure), GET /account/export (Art. 20 portability)
  • Legal pages — Privacy Policy (GDPR-compliant), Terms of Service, Cookie Policy (ePrivacy)
  • Login consent — signup form links to Terms/Privacy
  • CORS — locked to explicit methods (GET, POST, PUT, DELETE, OPTIONS) and headers
  • Frontend — AuthContext, ProtectedRoute, Login/Account/Pricing pages

Test plan

  • 523 tests passing (excluding pre-existing qdrant mock failure)
  • Auth fixtures updated with supabase_jwt_secret for auth-enabled tests
  • test_auth.py — unauthenticated access (401), free tier restrictions (403), trial access, expired trial
  • test_rate_limits.py — rate limit enforcement tests
  • Manual: verify Supabase JWT flow end-to-end (requires Supabase project)
  • Manual: verify Polar.sh webhook tier changes

🤖 Generated with Claude Code

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Mar 10, 2026

Copy link
Copy Markdown

Deploying cherry-evals with  Cloudflare Pages  Cloudflare Pages

Latest commit: 501a242
Status: ✅  Deploy successful!
Preview URL: https://ebff30c7.cherry-evals.pages.dev
Branch Preview URL: https://feat-auth-with-security-hard.cherry-evals.pages.dev

View logs

@marinone94
marinone94 force-pushed the feat/auth-with-security-hardening branch from 878a8ce to f1ddd45 Compare March 11, 2026 05:31
marinone94 added a commit that referenced this pull request Mar 11, 2026
…#23, #25

Mark 17 findings as fixed/mitigated, update executive summary,
reorganize remediation roadmap into done/immediate/before-launch/after-launch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
marinone94 added a commit that referenced this pull request Mar 11, 2026
…#23, #25

Mark 17 findings as fixed/mitigated, update executive summary,
reorganize remediation roadmap into done/immediate/before-launch/after-launch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@marinone94
marinone94 force-pushed the feat/auth-with-security-hardening branch from f1ddd45 to 4bbc832 Compare March 11, 2026 05:50
marinone94 and others added 4 commits March 11, 2026 06:54
…hardening

- Supabase JWT auth with PyJWT (HS256, validates signature/expiry/audience)
- API key auth (SHA-256 hashed, prefix for display)
- Tier system: Free/Pro/Ultra with Polar.sh webhooks
- 7-day Ultra trial for new signups
- Rate limiting (in-memory burst + PostgreSQL daily quotas)
- IDOR fix: ownership checks on all collection mutations
- Config validator: auth auto-disables without JWT secret
- UNIQUE constraint on users.email (migration 006)
- GDPR endpoints: DELETE /account/me (erasure), GET /account/export (portability)
- Legal pages: Privacy Policy, Terms of Service, Cookie Policy
- Login consent notice linking to Terms/Privacy
- Landing page links to app.cherryevals.com legal pages
- Frontend: AuthContext, ProtectedRoute, Login/Account/Pricing pages
- CORS locked to explicit methods and headers
- Test fixtures with supabase_jwt_secret for auth-enabled tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…routes

- Add settings import and ownership check (IDOR fix) to export endpoint
- Wire require_paid + check_and_increment_llm_budget into /agents/discover,
  /agents/ingest, /agents/{id}/export-custom, and /search/intelligent
- Wire check_semantic_search_quota into /search/semantic
- Add ownership check to /agents/{id}/export-custom
- Patch api.routes.agents.settings in all auth test fixtures

All 27 auth tests now pass. Free-tier users are properly blocked from
LLM-powered features (403), and collection export endpoints enforce
ownership to prevent IDOR.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Blocking fixes:
- B1: Polar webhook signature — implement Svix format (v1,<base64>)
  with proper msg_id.timestamp.body signing
- B2: API key count — use SELECT COUNT(*) instead of fetching all rows
- B3: Race condition — atomic check-and-increment for daily quotas
  using SQL UPDATE...WHERE (eliminates concurrent burst abuse)
- B4: IDOR check — move to shared check_collection_ownership() in deps.py,
  used by collections, export, and agents routes
- B5: quota_reset_at — set explicitly in _provision_user to now+1day

Non-blocking fixes:
- NB1: Gate Langfuse export behind require_paid tier check
- NB2: Wire check_search_rate_limit to keyword search endpoint
- NB3: Add api.routes.agents.settings patch to authed_client fixtures
  (now removed since agents.py no longer imports settings)
- NB4: LoginPage navigate() → <Navigate to="/" replace />
- NB5: Eager-load api_key.user with joinedload to prevent DetachedInstanceError
- NB8: Only upgrade tier on active/trialing subscription status
- NB10: Add min_length=1 to CreateApiKeyRequest.name
- NB12: DRY authed_client fixtures with _make_authed_client factory
- Sanitize filenames in Content-Disposition with regex
- Sanitize error messages in search routes (no str(e) to client)
- Add re module to exec sandbox safe_globals (from closed PR #21)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
These files were being ignored by the top-level `lib/` gitignore
pattern but are required for the frontend auth flow.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@marinone94
marinone94 force-pushed the feat/auth-with-security-hardening branch from 8d7c1a1 to 501a242 Compare March 11, 2026 05:55
@marinone94
marinone94 merged commit 37f40f8 into main Mar 11, 2026
4 checks passed
@marinone94
marinone94 deleted the feat/auth-with-security-hardening branch March 11, 2026 05:56
marinone94 added a commit that referenced this pull request Mar 30, 2026
These were implemented in PR #20 but not tracked in the audit doc.
34/46 findings now fixed. Only 1 before-launch item remains (DPAs — owner action).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant