==================================== Identity — Authentification JWT ==================================== Le système d'authentification étend SimpleJWT pour injecter les claims tenant dans les tokens JWT. Module : ``src.module.identity.infrastructure.authentication`` .. module:: src.module.identity.infrastructure.authentication :synopsis: Authentification JWT personnalisée avec claims tenant CustomTokenObtainPairSerializer ================================ .. class:: CustomTokenObtainPairSerializer(TokenObtainPairSerializer) Sérialiseur JWT qui injecte les claims tenant dans le token d'accès. Claims ajoutés : - ``tenant_id`` : UUID du tenant courant - ``roles`` : Liste des rôles de la membership - ``email`` : Email de l'utilisateur .. classmethod:: get_token(cls, user) -> Token Génère un token avec les claims tenant injectés. **Configuration dans settings.py :** .. code-block:: python SIMPLE_JWT = { 'TOKEN_OBTAIN_SERIALIZER': 'src.module.identity.infrastructure.authentication.CustomTokenObtainPairSerializer', } **Exemple de payload JWT décodé :** .. code-block:: json { "user_id": "550e8400-e29b-41d4-a716-446655440000", "email": "admin@acme.com", "tenant_id": "660e8400-e29b-41d4-a716-446655440001", "roles": ["admin", "billing"], "exp": 1711200000, "iat": 1711196400 } CustomJWTAuthentication ======================== .. class:: CustomJWTAuthentication(JWTAuthentication) Backend d'authentification JWT qui extrait le ``tenant_id`` depuis le token pour que le ``TenantMiddleware`` puisse l'utiliser. Étend ``JWTAuthentication`` de SimpleJWT. Endpoints d'authentification ============================= Module : ``src.module.identity.presentation.views`` .. class:: RegisterView(CreateAPIView) ``POST /api/v1/auth/register/`` Crée un nouvel utilisateur. :Body: ``{"email": "...", "password": "...", "first_name": "...", "last_name": "..."}`` :Response 201: ``{"id": "...", "email": "..."}`` .. class:: LoginView(TokenObtainPairView) ``POST /api/v1/auth/login/`` Authentifie un utilisateur et retourne les tokens JWT. :Body: ``{"email": "...", "password": "..."}`` :Response 200: ``{"access": "eyJ...", "refresh": "eyJ..."}`` Si ``OTP_REQUIRED_FOR_LOGIN`` est activé, retourne un token temporaire qui nécessite une vérification OTP avant utilisation. .. class:: SwitchTenantView(APIView) ``POST /api/v1/auth/switch-tenant/`` Génère un nouveau token JWT pour un autre tenant. :Body: ``{"tenant_id": "..."}`` :Response 200: ``{"access": "eyJ...", "refresh": "eyJ..."}`` Vérifie que l'utilisateur a une membership active dans le tenant cible. Flux d'authentification ======================== .. code-block:: text Client Serveur │ │ ├── POST /auth/login/ ──────────►│ │ {email, password} │ │ ├── Vérifie les credentials │ ├── Injecte tenant_id dans JWT │ │ │◄── {access, refresh} ──────────┤ │ │ ├── GET /api/v1/products/ ──────►│ │ Authorization: Bearer eyJ... │ │ ├── CustomJWTAuthentication │ │ extrait user + tenant_id │ ├── TenantMiddleware │ │ active le backend d'isolation │ ├── ABACPermission │ │ évalue les politiques │ │ │◄── [data scopée au tenant] ────┤