# Plan de Migration : Gestion des Tokens JWT via Cookies HttpOnly

## 1. Contexte et Objectif

Ce document décrit le plan d'action pour migrer le système d'authentification de l'application d'un stockage des tokens JWT dans le `localStorage` vers une stratégie plus sécurisée utilisant des cookies `HttpOnly`.

**Objectif :** Renforcer la sécurité de l'application en protégeant les tokens JWT contre les attaques de type XSS (Cross-Site Scripting). Les cookies `HttpOnly` ne sont pas accessibles par le code JavaScript côté client, ce qui empêche leur vol par des scripts malveillants.

## 2. Stratégie Générale

La migration se fera en deux phases principales, en commençant par le backend pour s'assurer que les cookies sont correctement émis, puis en adaptant le frontend pour les consommer.

1.  **Backend (Django)** :
    -   Modifier la configuration de `djangorestframework-simplejwt` pour qu'il envoie les `access_token` et `refresh_token` dans des cookies `HttpOnly` lors de la connexion et du rafraîchissement.
    -   Activer la rotation des refresh tokens pour une sécurité accrue.
    -   Configurer une vue de déconnexion qui supprime ces cookies.

2.  **Frontend (Next.js)** :
    -   Configurer le client HTTP (Axios/fetch) pour qu'il envoie les informations d'identification (cookies) avec chaque requête (`withCredentials: true`).
    -   Supprimer toute la logique de stockage et de manipulation des tokens du store Zustand et du `localStorage`.
    -   Adapter le store pour qu'il ne gère plus que l'état d'authentification (`isAuthenticated`, `user`) sans connaître les tokens.

## 3. Plan d'Action Détaillé

### Étape 1 : Modifications du Backend (Django)

Cette étape est cruciale et doit être réalisée en premier.

-   [ ] **Adapter les vues de login et logout** :
    -   **Action** : Modifier la vue `CustomTokenObtainPairView` pour qu'elle dépose les tokens `access` et `refresh` dans des cookies `HttpOnly` au lieu de les retourner dans le corps de la réponse.
    -   **Action** : Créer ou modifier une vue de `logout` qui envoie une instruction au navigateur pour supprimer ces cookies.

-   [ ] **Mettre à jour `settings.py`** :
    -   Configurer `SIMPLE_JWT` pour la rotation des tokens.

    ```python
    # settings.py

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': (
            # Permet au backend de lire le JWT depuis le cookie HttpOnly
            # Vous devrez peut-être ajouter une classe d'authentification personnalisée
            # ou utiliser une bibliothèque comme 'djangorestframework-simplejwt-cookie-bridge'
            'rest_framework_simplejwt.authentication.JWTAuthentication',
        ),
        # ...
    }

    SIMPLE_JWT = {
        # ...
        'ROTATE_REFRESH_TOKENS': True, # Recommandé pour la sécurité
        'BLACKLIST_AFTER_ROTATION': True, # Recommandé pour la sécurité
    }
    ```

-   [ ] **Adapter les URLs** :
    -   S'assurer que les endpoints de `login` et `logout` pointent vers vos vues personnalisées qui gèrent les cookies.

### Étape 2 : Modifications du Frontend (Next.js)

Une fois le backend prêt, nous adaptons le frontend.

-   [ ] **Configurer le client HTTP (`api-client.ts`)** :
    -   **Action** : Configurer l'instance Axios pour qu'elle envoie les cookies à chaque requête.
    ```typescript
    // src/lib/api-client.ts
    const apiClient = axios.create({
      baseURL: API_CONFIG.baseURL,
      withCredentials: true, // <-- Très important !
    });
    ```
    -   **Action** : Supprimer les intercepteurs qui ajoutaient manuellement le header `Authorization`. Le navigateur s'en chargera.

-   [ ] **Mettre à jour le Store Zustand (`auth-store.ts`)** :
    -   **Action** : Supprimer complètement la propriété `tokens` de l'état du store.
    -   **Action** : Supprimer la persistance des tokens dans le `localStorage` (`partialize`).
    -   **Action** : Simplifier la fonction `login`. Elle n'a plus besoin de stocker les tokens. La réponse de l'API ne contiendra plus les tokens dans le corps JSON.
        ```typescript
        // Dans la fonction login
        const data: { user: User } = await response.json(); // La réponse ne contient plus que l'utilisateur
        set({
          isAuthenticated: true,
          user: data.user,
          // tokens: null, // <-- Supprimer cette ligne
        });
        ```
    -   **Action** : Supprimer la fonction `refreshToken`. Le rafraîchissement sera géré de manière transparente par le backend et le navigateur via le `refresh-token` en cookie.
    -   **Action** : Simplifier la fonction `logout`. Elle appellera simplement l'endpoint `/logout/` du backend, qui se chargera de supprimer les cookies.
        ```typescript
        // Dans la fonction logout
        await fetch(`${API_BASE_URL}${apiEndpoints.auth.logout}`, { method: "POST", credentials: 'include' });
        // Le backend supprime les cookies. On réinitialise l'état local.
        set({ isAuthenticated: false, user: null, ... });
        ```
    -   **Action** : Adapter `checkTokenValidity`. Au lieu de vérifier un token en state, on peut faire un appel à un endpoint protégé (comme `/auth/user/`). Si l'appel réussit, l'utilisateur est connecté. S'il échoue (401), il est déconnecté.

-   [ ] **Mettre à jour le Middleware Next.js (`middleware.ts`)** :
    -   La logique de protection des routes doit être adaptée. Au lieu de lire un token du `localStorage`, le middleware doit vérifier la présence du cookie `amifond-access-token` dans la requête entrante.

### Étape 3 : Tests et Validation

-   [ ] **Test du flux de connexion** :
    -   Se connecter.
    -   Ouvrir les outils de développement du navigateur -> "Application" -> "Cookies".
    -   Vérifier la présence des cookies `amifond-access-token` et `amifond-refresh-token`.
    -   Vérifier que l'attribut `HttpOnly` est coché et que le `localStorage` est vide de tout token.

-   [ ] **Test de persistance** :
    -   Recharger la page. L'utilisateur doit rester connecté.
    -   Faire un appel à une API protégée et vérifier qu'il réussit.

-   [ ] **Test de déconnexion** :
    -   Se déconnecter.
    -   Vérifier que les cookies d'authentification ont été supprimés.
    -   Tenter d'accéder à une page protégée et vérifier la redirection.

-   [ ] **Test de rafraîchissement de token** :
    -   Attendre l'expiration de l'access token (configuré à 5 minutes dans l'exemple).
    -   Effectuer une action qui appelle l'API.
    -   Vérifier dans l'onglet "Network" qu'un appel à l'endpoint de refresh a été fait automatiquement et qu'un nouveau cookie `amifond-access-token` a été positionné.

## 4. Conclusion

Cette migration est une étape fondamentale pour sécuriser l'application. En suivant ce plan, la transition se fera de manière structurée, en éliminant une vulnérabilité majeure tout en simplifiant la gestion de l'état côté client.