Microservice d'authentification et gestion d'identité construit avec FastAPI , PostgreSQL et Redis .
Mecanisme JWT asymetrique (RS256), refresh token rotation, rate limiting distribue, et blacklist temps reel.
Client --> API Gateway --> Auth Service (:8080) --> PostgreSQL (auth_identity_db)
|
v
Redis (rate limit + blacklist)
Chiffrement RS256 : seule l'Auth Service detient la cle privee. Les autres services recoivent la cle publique via /jwks.json.
Access Token (15 min) : transmis dans le body JSON, destine a la memoire volatile du client.
Refresh Token (7 jours) : cookie HttpOnly + Secure + SameSite=Strict. Le JavaScript n'y a pas acces.
Principe de fonctionnement
L'API Gateway valide l'Access Token avec la cle publique.
La Gateway injecte X-User-Id et X-User-Role dans les requetes aval.
Chaque microservice peut re-verifier via get_current_user() (FastAPI dependency).
Python 3.12+
PostgreSQL (ou base de donnees accessible)
Redis (optionnel : fallback automatique vers MockRedis en memoire)
pip install -r requirements.txt
# Generer les cles RSA (si absentes)
python generate_keys.py
Variables d'environnement (ou fichier .env) :
Variable
Defaut
Description
DATABASE_URL
postgresql+asyncpg://postgres:postgres@localhost:5432/auth_identity_db
Connexion PostgreSQL
REDIS_URL
redis://localhost:6379/0
Connexion Redis
RSA_PRIVATE_KEY_PATH
./keys/private_key.pem
Chemin de la cle privee
RSA_PUBLIC_KEY_PATH
./keys/public_key.pem
Chemin de la cle publique
INTERNAL_SERVICE_SECRET
super-secret-internal-token
Jeton pour les routes internes
PORT
8080
Port d'ecoute
COOKIE_SECURE
False
Secure flag sur le cookie (mettre True en prod HTTPS)
uvicorn main:app --port 8080 --reload
auth_service_fastAPI/
main.py # Point d'entree FastAPI
generate_keys.py # Utilitaire de generation RSA
keys/ # Cles PEM (generees)
app/
config.py # Pydantic Settings
database.py # Engine async SQLAlchemy + session
models.py # ORM : User, Profile, RefreshToken
schemas.py # Pydantic v2 validation
security.py # JWT, hash, JWKS
redis.py # Client Redis + MockRedis fallback
dependencies.py # Dependencies FastAPI (auth, roles, interne)
routers/
auth.py # /api/v1/auth/*
profiles.py # /api/v1/profiles/*
admin.py # /api/v1/admin/*
internal.py # /internal/v1/*
Methode
Chemin
Acces
Description
POST
/api/v1/auth/register
Public
Inscription (users + profiles, transaction atomique)
POST
/api/v1/auth/login
Public
Connexion (rate limite: 5 req/min/IP)
POST
/api/v1/auth/refresh
Cookie
Rotation du refresh token, nouveau access token
POST
/api/v1/auth/logout
Connecte
Revocation du refresh token + suppression cookie
GET
/api/v1/auth/.well-known/jwks.json
Public
Cle publique au format JWKS
Methode
Chemin
Acces
Description
GET
/api/v1/profiles/me
Connecte
Profil complet de l'utilisateur courant
PUT
/api/v1/profiles/me
Connecte
Mise a jour du profil courant
GET
/api/v1/profiles/{user_id}
Public
Profil public (donnees sensibles masquees)
Methode
Chemin
Acces
Description
PATCH
/api/v1/admin/users/{user_id}/ban
Admin
Bannissement (is_active=False + blacklist Redis)
Inter-services (protege par X-Internal-Service-Token)
Methode
Chemin
Description
GET
/internal/v1/users/{id}/access
Controle d'acces pour l'API Gateway
GET
/internal/v1/users/{id}/payout-identity
Donnees d'identite pour le service Paiement
users (1) ----- (1) profiles
|
| (N)
v
refresh_tokens
Champ
Type
Contrainte
id
UUID
PK, uuid4
email
VARCHAR(255)
Unique, indexe, normalise (lower + strip)
password_hash
VARCHAR(255)
Bcrypt
role
VARCHAR(50)
USER, STUDENT, ADMIN, MODERATOR
is_active
BOOLEAN
True defaut, False si banni
is_verified
BOOLEAN
False defaut
created_at / updated_at
TIMESTAMPTZ
Auto
Champ
Type
Contrainte
id
UUID
PK
user_id
UUID
FK -> users.id, CASCADE
first_name / last_name
VARCHAR(100)
Nullable
avatar_url
VARCHAR(500)
Nullable
bio
TEXT
Nullable
phone
VARCHAR(30)
Nullable, masque en public
Champ
Type
Contrainte
id
UUID
PK
user_id
UUID
FK -> users.id
token_hash
VARCHAR(255)
SHA-256 du token
expires_at
TIMESTAMPTZ
7 jours
is_revoked
BOOLEAN
False defaut
A chaque appel /refresh :
L'ancien refresh token est marque is_revoked = True.
Un nouveau token est emis (cookie + hash en base).
Si un token deja revoke est presente : tous les refresh tokens de l'utilisateur sont revoques (detection de vol de session).
Blacklist temps reel (Redis)
Lors d'un bannissement :
is_active = False en base.
Tous les refresh tokens revoques.
Cle blacklist:user:{id} inseree dans Redis (TTL = duree de vie de l'access token).
Les dependances FastAPI verifient cette blacklist avant chaque action.
/login : 5 tentatives par minute par IP (cle rate:login:{ip} dans Redis).
Au-dela : HTTP 429 avec message explicite.
Protection inter-services
Les routes /internal/* verifient l'en-tete X-Internal-Service-Token par comparaison stricte avec la variable INTERNAL_SERVICE_SECRET.
Format des reponses d'erreur
Toutes les erreurs suivent le format RFC 7807 :
{
"detail" : " Email ou mot de passe incorrect" ,
"code" : " AUTHENTICATION_FAILED"
}
Codes d'erreur courants :
INVALID_TOKEN : Token JWT invalide ou expire
AUTHENTICATION_REQUIRED : Aucun token fourni
ACCOUNT_SUSPENDED : Utilisateur blackliste
ACCOUNT_DISABLED : Compte desactive
FORBIDDEN : Role insuffisant
VALIDATION_ERROR : Donnees d'entree invalides
RATE_LIMIT_EXCEEDED : Trop de tentatives
SESSION_COMPROMISED : Vol de session detecte
Instructions pour les equipes
Ne pas extraire le refresh token du cookie. Le navigateur le transmet automatiquement.
Utiliser credentials: 'include' (fetch) ou withCredentials: true (axios).
Stocker l'access token en memoire (variable JS), pas dans localStorage.
Generer les cles RSA en production et les monter via /etc/secrets/.
Configurer COOKIE_SECURE=True en production (HTTPS obligatoire).
S'assurer que le secret INTERNAL_SERVICE_SECRET est partage de maniere securisee entre services.
psql -U postgres -c " CREATE DATABASE auth_identity_db;"
pytest scratch/run_tests.py -v