Aller au contenu

Clé API

Une clé d'api est une chaîne de caractères aléatoire unique qui est utilisée pour identifier et authentifier un utilisateur qui effectue une requête à l'api. Ce n'est pas de l'information encrypté ou hashé. Par exemple on pourrait utiliser un UUID comme clé api. L'importe est que la clé api doit être unique dans le système.

On ajoute la clé dans l'entête de chaque requête envoyée à l'API. Ensuite le serveur détermine si la clé est valide, identifie l'utilisateur associé à la clé (identification) et détermine si celui-ci peut effectuer la requête (authentification).

Fonctionnement

Voici le mode de fonctionnement que nous allons utiliser pour ajouter une protection par clé api à notre projet:

  • L'utilisateur doit se créer un compte à l'aide d'une route de l'api en fournissant un email et un mot de passe.
  • On va générer une clé d'api, enregistrer les informations dans la base de données (hashez le mot de passe) et ensuite retourner la clé à l'utilisateur
  • L'utilisateur devra ensuite ajouter la clé dans l'entête de chaque requête qui est envoyée au serveur.
  • Un Intergiciel se chargera de valider si la clé est bonne en faisant une recherche dans la base de données.
  • On va ajouter le Intergiciel aux routes qu'on veut protéger.

Ajouter la clé à l'entête de la requête

Dans la section entête de la requête il y a une clé qui est utilisée pour envoyer des données d'authorisation comme une clé api. Dans Postman vous pouvez ajouter l'information dans l'onglet Headers. Le nom de la clé est Authorization et comme valeur nous allons avoir cle_api suivi d'une espace et de la clé. (Vous pouvez utiliser autre chose comme nom que cle_api, souvent dans les documentation on va voir Bearer, l'idée est d'indiquer quelle genre d'autorisation on demande).

apikey_01.png

Intergiciel de confirmation de la clé

Dans votre projet, créez un répertoire middlewares dans le répertoire src. Le code suivant est un exemple d'intergiciel qui récupère la valeur de la clé api dans l'entête de la requête et vérifie à l'aide d'une fonction dans le modèle que la clé existe dans la base de données.

authentification.middleware.js
import { ValidationCle } from "../models/utilisateur.model";

const authentification = (req, res, next) => {

    // Vérifier si la clé API est présente dans l'entête
    if(!req.headers.authorization) {
        return res.status(401).json({ message: "Vous devez fournir une clé api" });
    }

    // Récupérer la clé API qui est dans l'entête au format "cle_api XXXXXXXX"
    const cleApi = req.headers.authorization.split(' ')[1];
    // Vérifier si la clé API est valide
    ValidationCle(cleApi)
    .then(resultat => {
        if(!resultat) {
            return res.status(401).json({ message: "Clé API invalide" });
        } else {
            // La clé API est valide, on continue le traitement avec la fonction next()
            next();
        }
    })
    .catch(erreur => {
        return res.status(500).json({ message: "Erreur lors de la validation de la clé api" })
    });    
}

export default authentification;

Note

Explication de la ligne 11 req.headers.authorization me retourne la valeur complète de la clé authorization, par exemple "cle_api 123456". En utilisant split avec un espace comme caractère de séparation je me retrouve avec un tableau avec "cle_api" à l'index 0 et "123456" à l'index 1. C'est ne récupérer que la valeur de la clé que j'utilise split et ensuite je demande l'index 1.

Protection des routes

On peut appliquer la protection à toutes les routes de l'API. Par contre si on a une route qui permet de créer un utilisateur sans clé d'api ou une route pour la documentation, elles seront bloquées. Ce n'est donc pas la meilleure méthode. Dans le fichier index.js on va simplement utiliser app.use() avec le nom de la fonction intergiciel qu'on aura importé.

index.js
import authentification from './src/middlewares/authentification.middleware';
// Toutes les requètes vont validées par l'intergiciel
app.use(authentification);

Étant donnée qu'on utilise le routage, on peut aussi ajouter la protection à un groupe de route.

index.js
import authentification from './src/middlewares/authentification.middleware';
import testRoute from './src/routes/test.route';
// ...
app.use('api/test', authentification, testRoute);

On peut aussi y aller route par route

pokemons.route.js
1
2
3
4
5
6
7
import authentification from "../middlewares/authentification.middleware";  
import testController from "../controllers/test.controller";

// Cette route n'est pas protégée
router.get("/liste", testController.afficherListe);
// Mais celle-ci l'est
router.post("/", authentification, testController.ajouterItem);

Mediagraphie