Save France
Composables

useAuth

Composable pour la gestion de l'authentification et des tokens JWT

Description

Composable pour la gestion de l'authentification, des tokens JWT, de l'état administrateur et des identifiants de requête. Il gère la persistance via les cookies et le state Nuxt.

Vue d'ensemble

Le composable useAuth centralise toute la logique d'authentification de l'application. Il gère les tokens d'accès et de rafraîchissement, l'état administrateur, et les identifiants de requête avec persistance automatique.

flowchart LR
    A[useAuth] --> B[Tokens JWT]
    A --> C[État Admin]
    A --> D[Request ID]
    B --> E[Cookies]
    B --> F[useState]
    C --> F
    D --> E
    D --> F

API

Fonctions de token

getToken(): string | null

Récupère le token JWT d'authentification. Vérifie d'abord useState, puis les cookies.

const { getToken } = useAuth();
const token = getToken();
if (token) {
  // Utiliser le token pour les requêtes API
}

setToken(newToken: string, newRefreshToken?: string): void

Définit le token d'accès et optionnellement le token de rafraîchissement. Persiste dans les cookies et le state.

const { setToken } = useAuth();
setToken('jwt-token', 'refresh-token');

Paramètres :

  • newToken : Token JWT d'accès
  • newRefreshToken : Token de rafraîchissement (optionnel)

Configuration des cookies :

  • auth_token : MaxAge 24 heures, secure, sameSite strict
  • refresh_token : MaxAge 7 jours, secure, sameSite strict

removeToken(): void

Supprime les tokens d'authentification (accès et rafraîchissement) du state et des cookies.

const { removeToken } = useAuth();
removeToken(); // Déconnexion

isAuthenticated(): boolean

Vérifie si l'utilisateur est authentifié (token présent).

const { isAuthenticated } = useAuth();
if (isAuthenticated()) {
  // Utilisateur connecté
}

getRefreshToken(): string | null

Récupère le token de rafraîchissement.

const { getRefreshToken } = useAuth();
const refreshToken = getRefreshToken();

refreshAccessToken(): Promise<boolean>

Renouvelle le token d'accès en utilisant le token de rafraîchissement.

const { refreshAccessToken } = useAuth();
const success = await refreshAccessToken();
if (success) {
  // Token renouvelé avec succès
}

Retour : true si le renouvellement a réussi, false sinon.

Comportement :

  • Appelle /api/auth/refresh avec le refresh token
  • Met à jour automatiquement les tokens en cas de succès
  • Supprime les tokens en cas d'échec

Fonctions d'administration

getIsAdmin(): boolean

Récupère l'état administrateur.

const { getIsAdmin } = useAuth();
if (getIsAdmin()) {
  // Mode administrateur actif
}

setIsAdmin(newIsAdmin: boolean): void

Définit l'état administrateur.

const { setIsAdmin } = useAuth();
setIsAdmin(true);

Fonctions de request ID

getRequestId(): string | null

Récupère l'identifiant de requête actuel.

const { getRequestId } = useAuth();
const requestId = getRequestId();

setRequestId(id: string): void

Définit l'identifiant de requête. Persiste dans un cookie avec maxAge de 24 heures.

const { setRequestId } = useAuth();
setRequestId('request-123');

removeRequestId(): void

Supprime l'identifiant de requête.

const { removeRequestId } = useAuth();
removeRequestId();

Initialisation

initializeFromCookies(): void

Initialise le state depuis les cookies au montage de l'application.

const { initializeFromCookies } = useAuth();
onMounted(() => {
  initializeFromCookies();
});

Note : Cette fonction est généralement appelée automatiquement dans un plugin ou middleware.

Utilisation

Exemple de base

<script setup lang="ts">
const { getToken, isAuthenticated, setToken, removeToken } = useAuth();

// Vérifier l'authentification
if (isAuthenticated()) {
  const token = getToken();
  // Utiliser le token
}

// Connexion
async function login(email: string, password: string) {
  const response = await $fetch('/api/auth', {
    method: 'POST',
    body: { email, password },
  });
  
  setToken(response.token, response.refresh_token);
}

// Déconnexion
function logout() {
  removeToken();
  navigateTo('/');
}
</script>

Middleware d'authentification

// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
  const { isAuthenticated } = useAuth();
  
  if (!isAuthenticated()) {
    return navigateTo('/login');
  }
});

Utilisation dans les appels API

const { getToken } = useAuth();
const token = getToken();

const { data } = await $fetch('/api/protected', {
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

Renouvellement automatique du token

const { refreshAccessToken, isAuthenticated } = useAuth();

// Dans un plugin ou middleware
if (isAuthenticated()) {
  const refreshed = await refreshAccessToken();
  if (!refreshed) {
    // Token invalide, rediriger vers login
    navigateTo('/login');
  }
}

Gestion de l'état administrateur

<script setup lang="ts">
const { getIsAdmin, setIsAdmin } = useAuth();
const isAdmin = computed(() => getIsAdmin());

function toggleAdminMode() {
  setIsAdmin(!isAdmin.value);
}
</script>

<template>
  <div v-if="isAdmin">
    <UAlert
      icon="i-heroicons-shield-check"
      color="info"
      title="Mode administrateur"
    />
  </div>
</template>

Persistance

Cookies

Les données sont persistées dans des cookies avec les configurations suivantes :

CookieMaxAgeSecureSameSite
auth_token24hOuiStrict
refresh_token7jOuiStrict
request_id24hOuiStrict

State Nuxt

Les données sont également stockées dans le state Nuxt via useState pour un accès rapide côté client :

  • auth_token : Token JWT d'accès
  • refresh_token : Token de rafraîchissement
  • request_id : Identifiant de requête
  • admin : État administrateur (boolean)

Sécurité

Bonnes pratiques

  1. Tokens
    • Les tokens sont stockés dans des cookies sécurisés (secure: true)
    • sameSite: 'strict' pour prévenir les attaques CSRF
    • Les tokens sont supprimés automatiquement en cas d'erreur
  2. Refresh token
    • Durée de vie plus longue (7 jours)
    • Utilisé uniquement pour renouveler l'accès
    • Supprimé si le renouvellement échoue
  3. État administrateur
    • Stocké uniquement dans le state (non persisté)
    • Réinitialisé à chaque chargement de page
    • Doit être validé côté serveur

Dépannage

Le token n'est pas récupéré

  1. Vérifiez que initializeFromCookies() est appelé
  2. Vérifiez que les cookies sont bien définis dans le navigateur
  3. Vérifiez la console pour les erreurs

Le refresh token ne fonctionne pas

  1. Vérifiez que l'endpoint /api/auth/refresh est accessible
  2. Vérifiez que le refresh token est valide
  3. Vérifiez les erreurs dans la console

L'état administrateur ne persiste pas

  1. L'état admin n'est pas persisté intentionnellement
  2. Utilisez un cookie séparé si vous avez besoin de persistance
  3. Validez toujours côté serveur

Exemple complet

<template>
  <div>
    <div v-if="isAuthenticated()">
      <p>Connecté en tant que : {{ user.email }}</p>
      <UButton @click="handleLogout">Déconnexion</UButton>
    </div>
    
    <div v-else>
      <UForm @submit="handleLogin">
        <UFormGroup label="Email" name="email">
          <UInput v-model="loginForm.email" type="email" />
        </UFormGroup>
        
        <UFormGroup label="Mot de passe" name="password">
          <UInput v-model="loginForm.password" type="password" />
        </UFormGroup>
        
        <UButton type="submit" :loading="loading">
          Connexion
        </UButton>
      </UForm>
    </div>
  </div>
</template>

<script setup lang="ts">
const { 
  getToken, 
  setToken, 
  removeToken, 
  isAuthenticated,
  refreshAccessToken 
} = useAuth();

const loginForm = reactive({
  email: '',
  password: '',
});

const loading = ref(false);
const user = ref<any>(null);

// Vérifier et renouveler le token au montage
onMounted(async () => {
  if (isAuthenticated()) {
    const refreshed = await refreshAccessToken();
    if (refreshed) {
      await loadUser();
    } else {
      removeToken();
    }
  }
});

async function handleLogin() {
  loading.value = true;
  try {
    const response = await $fetch('/api/auth', {
      method: 'POST',
      body: loginForm,
    });
    
    setToken(response.token, response.refresh_token);
    await loadUser();
  } catch (error) {
    console.error('Erreur de connexion:', error);
  } finally {
    loading.value = false;
  }
}

async function loadUser() {
  const token = getToken();
  if (!token) return;
  
  try {
    const { data } = await $fetch('/api/user', {
      headers: {
        Authorization: `Bearer ${token}`,
      },
    });
    user.value = data;
  } catch (error) {
    console.error('Erreur de chargement utilisateur:', error);
  }
}

function handleLogout() {
  removeToken();
  user.value = null;
  navigateTo('/');
}
</script>

Résumé

  • Gestion centralisée de l'authentification
  • Persistance automatique via cookies et state
  • Renouvellement automatique des tokens
  • Gestion de l'état administrateur
  • Gestion des identifiants de requête
  • Sécurité renforcée avec cookies sécurisés
  • API simple et intuitive