Authentification et contrôle d’accès : sécuriser une API multi-clients
Crédit : Photo de Towfiqu barbhuiyasur Unsplash
Cet article fait partie d’une série consacrée à l’API REST de Rezo Pouce. Après avoir présenté l’architecture générale de l’API, ce volet aborde la sécurité : comment authentifier des utilisateurs issus de systèmes différents, protéger les routes et vérifier les droits à chaque requête. Les articles suivants détailleront le service Rezo Séniors et le géocodage, les documents et l’import de données.
Le problème
L’API sert quatre clients de natures différentes. Le site public a besoin d’un accès simple et rapide à des données en lecture. Les espaces d’administration ont besoin d’un accès sécurisé, différencié par rôle et par territoire. Et les utilisateurs du back-office ne sont pas gérés dans la base Rezo Pouce — ils sont gérés par Mobicoop, la coopérative qui porte le service. Il faut donc authentifier des utilisateurs qui n’existent pas localement, tout en leur attribuant des droits fins sur des ressources spécifiques.
Deux mécanismes d’authentification
Token opaque pour le site public
Le site public, construit en Symfony, utilise un mécanisme simple : le client envoie ses identifiants via POST /auth-tokens, l’API vérifie le mot de passe et retourne un token aléatoire (base64) stocké en base dans une table dédiée. Les requêtes suivantes transmettent ce token via le header X-Auth-Token. Le token a une durée de validité de 12 heures.
C’est un mécanisme volontairement classique, adapté à une application serveur qui gère ses propres sessions — pas besoin de la complexité d’un JWT pour un client qui ne fait pas de requêtes cross-origin.
JWT avec délégation Mobicoop pour l’administration
Les espaces d’administration, construits en Angular, utilisent des JSON Web Tokens via Lexik JWT Authentication Bundle.
Le flux est plus élaboré qu’un JWT classique. Quand un utilisateur se connecte au back-office, l’API Rezo Pouce ne vérifie pas elle-même le mot de passe — elle le transmet à l’API Mobicoop. Le processus se déroule en trois étapes :
- Authentification déléguée — L’API Rezo Pouce transmet les identifiants à Mobicoop, qui retourne un token JWT Mobicoop et un refresh token.
- Vérification territoriale — L’API décode le token Mobicoop pour en extraire l’identité, puis vérifie que l’utilisateur est rattaché à au moins un territoire autorisé.
- Émission du JWT Rezo Pouce — L’API génère son propre JWT encapsulant l’identifiant de l’utilisateur, le token Mobicoop et le mot de passe chiffré.
Pourquoi encapsuler le mot de passe chiffré dans le JWT ? Parce que le token Mobicoop expire. Quand cela se produit en cours de session, l’API utilise le mot de passe encapsulé pour effectuer une ré-authentification transparente auprès de Mobicoop — l’utilisateur ne voit rien, sa session continue sans interruption.
Un mécanisme d’accès dérogatoire existe pour certains comptes listés explicitement en configuration : ceux-ci sont authentifiés directement contre la base locale, sans passer par Mobicoop.
Conversion de l’identité
Une fois le token Mobicoop obtenu, l’API récupère le profil utilisateur via Mobicoop et le convertit en utilisateur Rezo Pouce. Le UserConverter transforme les données Mobicoop — nom, prénom, email — et surtout parcourt les assignations de rôles Mobicoop (userAuthAssignments) pour rattacher l’utilisateur aux territoires Rezo Pouce correspondants et lui attribuer les rôles associés.
C’est ce mécanisme qui permet à un gestionnaire ajouté dans Mobicoop d’accéder immédiatement au back-office Rezo Pouce, sans création de compte manuelle. L’identité est fédérée, les droits sont synchronisés.
Sécurisation par route
Chaque famille de routes est protégée par un mécanisme d’authentification et un niveau d’accès minimum :
| Routes | Authentification | Accès |
|---|---|---|
/api/frontend/ | Aucune | Public (lecture seule) |
/api/ | Token opaque | Utilisateur connecté |
/api/backend/ | JWT | Authentification complète |
/api/seniors/backend/ | JWT | Authentification complète |
/web_services/ | Token opaque | Authentification complète |
/crontasks/ | Aucune | Filtrage par adresse IP |
Les routes frontend sont ouvertes — elles servent les données publiques du site. Les routes backend exigent un JWT valide. Les tâches planifiées (cron) n’ont pas d’authentification utilisateur mais sont protégées par un filtrage IP au niveau serveur.
Une hiérarchie de droits à trois niveaux
Au-delà de l’authentification, chaque requête est vérifiée selon trois dimensions :
Le rôle global définit le périmètre d’action général : ROLE_SUPER_ADMIN a accès à tout, ROLE_TERRITORY_MANAGER gère un territoire, ROLE_TERRITORY_CONSULTANT consulte sans modifier.
Le rôle par domaine affine les droits sur un module fonctionnel : ROLE_NATIONAL_SENIORS_MANAGER pilote le service Séniors sur l’ensemble du territoire national, ROLE_TERRITORY_SENIORS_MANAGER le pilote sur un territoire spécifique, ROLE_TERRITORY_SENIORS_CONSULTANT ne fait que consulter.
Le rôle contextuel vérifie le rattachement à une ressource précise : un gestionnaire de territoire ne peut accéder qu’aux données des territoires dont il a explicitement la charge. Même avec le bon rôle, une requête ciblant un territoire non rattaché est rejetée.
Cette vérification en cascade est appliquée à chaque endpoint. Elle garantit qu’un gestionnaire ne peut pas, en forgeant manuellement une requête, accéder aux données d’un territoire dont il n’est pas responsable.
Ce que cette approche illustre
La double authentification — token opaque pour le site public, JWT avec délégation pour l’administration — est un héritage de l’histoire du projet. Le site public existait avant les back-offices Angular. Plutôt que de migrer un système qui fonctionnait, le JWT a été ajouté pour les nouveaux clients, avec un mécanisme de délégation adapté à la réalité organisationnelle : les utilisateurs sont gérés par Mobicoop, pas par Rezo Pouce.
Ce pragmatisme — deux mécanismes qui cohabitent plutôt qu’une refonte unificatrice — est caractéristique d’un projet qui évolue sur cinq ans en production. L’enjeu n’est pas l’élégance théorique mais la fiabilité pratique : chaque mécanisme est simple dans son périmètre, testé et stable.
L’article suivant détaille le domaine fonctionnel le plus riche de l’API : le service Rezo Séniors — mise en relation, notifications et tâches planifiées.
Une question ou un projet ?
Je suis disponible pour en discuter.