← Journal technique
EduQate·auth & sécurité·2026-07-18

Chaque client pouvait postuler, et chacun heurtait un mur

Testing as staff never hit it: as a customer, Apply Now threw a 403 from an admin-only route plus three 'no active form found' 404s at once.

Visible seulement en s'en servant

Invisible à la relecture du code. Trouvé en étant le vrai utilisateur, sur un vrai appareil, à une vraie largeur.

Je ne l'ai trouvé que parce que j'ai arrêté de tester en tant qu'admin et me suis connecté en tant que client. Cliquer sur Postuler lançait quatre toasts d'erreur empilés d'un coup : un 403 et trois 404 « aucun formulaire actif trouvé ». Le côté admin n'appelle jamais ce chemin, donc tester en tant que personnel ne le ferait jamais surgir.

Le 403 venait de la liste des cycles d'admission, que le flux de candidature appelle pour vérifier une admission ouverte. Cette route est réservée aux admins par conception, renvoie des champs internes, et est protégée par un cadrage de propriété d'organisation qui n'a aucun sens pour un client. Donc ce n'est pas une mauvaise liste de rôles, c'est un endpoint que ce flux n'était jamais censé appeler.

Rien ici ne loggue, ne renvoie 500 ni n'alerte personne. Ça transforme juste, discrètement, l'action la plus importante du produit en un bouton qui échoue toujours, pour chaque client, sur chaque organisation, jusqu'à ce que quelqu'un le clique avec la console ouverte. Ça aurait pu être livré exactement comme ça.

Corrigé avec un endpoint public et étroit qui ne liste que les admissions ouvertes, filtré côté serveur et ne renvoyant que ce dont un candidat a besoin, sans toucher aux protections de l'endpoint admin — l'ajouter à sa liste @Roles n'aurait de toute façon pas marché, puisque le guard de propriété rejetterait quand même un client sans périmètre d'organisation.

La version générale : l'autorisation d'un endpoint peut être entièrement correcte pour le rôle pour lequel il a été construit et être quand même la mauvaise porte pour un appelant différent. « Cet utilisateur a-t-il la permission » et « cet utilisateur devrait-il frapper ici tout court » sont des questions distinctes, et tester uniquement en tant que personnel n'en répond qu'à une.