Files
turf_saas/API_AUTH.md
DevOps Engineer 5a23692ad1 feat: Sprint 2-3 — Auth JWT + Multi-tenant (HRT-28)
- auth_db.py: create users, subscriptions, refresh_tokens tables in turf_saas.db
- auth.py: register/login/refresh/logout endpoints, JWT middleware, plan_required decorator, free daily-limit check
- middleware.py: in-memory rate limiter (100 req/min/IP), timestamped access logs
- saas_api.py: Flask app factory wiring JWT, CORS, blueprints, /api/v1/predictions plan-gating
- tests/test_auth.py: 27 pytest tests, 83% coverage (target >=80%)
- API_AUTH.md: full endpoint documentation

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-25 17:35:45 +02:00

3.0 KiB

API Auth JWT — Documentation

Sprint 2-3 (HRT-28)

Base URL: http://localhost:8792


Endpoints d'authentification

POST /api/v1/auth/register

Inscription d'un nouvel utilisateur (plan free par défaut).

Body JSON:

{ "email": "user@example.com", "password": "motdepasse123" }

Réponse 201:

{ "message": "Compte créé avec succès", "user_id": 1 }

Erreurs: 400 (email invalide / mot de passe < 8 car.), 409 (email déjà utilisé)


POST /api/v1/auth/login

Connexion — retourne access_token (15min) + refresh_token (30j).

Body JSON:

{ "email": "user@example.com", "password": "motdepasse123" }

Réponse 200:

{
  "access_token": "<JWT>",
  "refresh_token": "<refresh_JWT>",
  "token_type": "Bearer",
  "plan": "free"
}

POST /api/v1/auth/refresh

Rotation du refresh token — invalide l'ancien, émet un nouveau.

Body JSON:

{ "refresh_token": "<refresh_JWT>" }

Réponse 200: identique à /login


POST /api/v1/auth/logout

Révocation du refresh token.

Body JSON:

{ "refresh_token": "<refresh_JWT>" }

Réponse 200:

{ "message": "Déconnexion réussie" }

Routes protégées

Toutes les routes protégées nécessitent le header:

Authorization: Bearer <access_token>

GET /api/v1/predictions

Plan Accès
free Top 3 uniquement, 1 course/jour
premium Toutes les courses + alertes Telegram
pro API complète + lien export CSV

GET /api/v1/predictions/export

Export CSV — plan pro uniquement (403 pour free/premium).

GET /api/v1/subscription/upgrade

Infos sur les plans disponibles et plan courant de l'utilisateur.

GET /api/v1/health

Vérification d'état du service (pas d'auth requise).


Sécurité

  • Passwords: hashés avec bcrypt (saltRounds=12)
  • JWT access: expiration 15 minutes (HS256)
  • JWT refresh: expiration 30 jours, stocké hashé (SHA-256) en DB, rotation à chaque usage
  • Rate limiting: 100 requêtes/min par IP — header X-RateLimit-Remaining
  • CORS: configuré pour https://turf-ia.h3r7.tech + localhost dev
  • Logs d'accès: horodatés ISO 8601 dans logs/saas_api.log

Lancement

JWT_SECRET_KEY="votre_cle_secrete" \
CORS_ORIGINS="https://turf-ia.h3r7.tech" \
./venv/bin/python saas_api.py

Tests

./venv/bin/pytest tests/test_auth.py -v
# Avec couverture:
./venv/bin/pytest tests/test_auth.py --cov=auth --cov=auth_db --cov=middleware --cov=saas_api --cov-report=term-missing
# Résultat: 27 tests OK, couverture globale 83%

Structure des tables DB

-- users: id, email, password_hash, plan(free/premium/pro), created_at, is_active, daily_usage, last_usage_date
-- subscriptions: id, user_id, plan, start_date, end_date, stripe_customer_id
-- refresh_tokens: id, user_id, token_hash, created_at, expires_at, revoked