Nodefony 10.0.0-beta.5
Framework Node.js fullstack — HTTP & WebSocket, même contexte

@nodefony/security — la sécurité de bout en bout

stable@nodefony/securitymis à jour 2026-07-19

Le pare-feu applicatif de Nodefony : un modèle par zones, des authenticators enfichables, des voters de droits, et les briques qui vont avec (jetons, passkeys, 2FA, OAuth2, CSRF, CORS, en-têtes, webhooks, audit). Principe directeur : Zero Trust — sur une zone protégée, pas de preuve d’identité valide, pas d’accès. Le même firewall protège HTTP et WebSocket.

📍 Documentation › Sécurité

🧭 Par où commencer#

Quatre parcours selon ce que tu viens faire. L’ordre compte : chaque étape suppose la précédente.

Je découvre la sécurité Nodefony — comprendre le modèle avant de configurer quoi que ce soit.

  1. Firewall — zones, Zero Trust, la chaîne de décision. Tout part d’ici.
  2. Authenticators — les sept façons de prouver qui appelle.
  3. Autorisation — rôles, scopes, voters : ce qu’il a le droit de faire.
  4. Jetons — ce qui matérialise une identité prouvée, et comment on la révoque.

Je protège une API pour des machines — scripts, CI, partenaires, agents.

  1. Firewall — déclarer la zone et ses authenticators.
  2. Clés d’API — émettre, faire tourner, révoquer une clé opaque.
  3. Jetons — le JWT quand la vérification doit rester sans état.
  4. Jetons d’un émetteur TIERS — accepter Keycloak, Auth0 ou Entra sans leur céder l’application.
  5. Autorisation — borner chaque clé par des scopes.

J’ouvre un login à des humains — navigateur, comptes, second facteur.

  1. Authenticators — la session BFF, et pourquoi le login est déjà fourni.
  2. Page de connexion — la page servie à /login, et comment l’habiller à ton nom.
  3. OAuth2 — « se connecter avec GitHub/Google » et le Shadow User.
  4. Keycloak — brancher l’annuaire de l’entreprise, du realm au premier login.
  5. WebAuthn / passkeys — se connecter sans mot de passe, résistant au phishing.
  6. TOTP — le second facteur classique, et l’élévation de privilège (step-up).

J’audite avant une mise en production — la passe qu’on regrette de ne pas avoir faite.

  1. En-têtes de sécurité — CSP, HSTS, COOP/COEP : ce que le navigateur applique pour toi.
  2. CSRF — empêcher un site tiers d’agir au nom de ton utilisateur.
  3. CORS — qui a le droit de lire tes réponses.
  4. Journal d’audit — prouver après coup qui a fait quoi.
  5. Webhooks — notifier un système tiers sans se faire piéger (SSRF).

🗂️ Les briques du module#

Le tableau pour choisir en cinq secondes ; les cards en dessous pour le détail.

Brique Ce qu’elle résout Tu en as besoin quand…
Firewall qui passe, qui est bloqué, sur quelles routes toujours — c’est la fondation
Authenticators prouver l’identité de l’appelant tu as autre chose que du public
Autorisation rôles, scopes, voters métier tous tes utilisateurs n’ont pas les mêmes droits
Jetons émission, keystore, rotation, révocation API sans état, ou révocation immédiate
Clés d’API accès machine révocable (PAT opaque) un script/CI/partenaire appelle ton API
Obtenir un jeton émettre un porteur en ligne de commande un agent MCP ou un script doit appeler ton app
CSRF requête authentifiée forgée par un site tiers tu sers un front avec cookie de session
CORS lecture cross-origine de tes réponses ton front est sur un autre domaine
En-têtes CSP, HSTS, COOP/COEP, Referrer-Policy tu sers du HTML à un navigateur
Page de connexion la page /login servie, habillable des humains se connectent à ton application
OAuth2 login social + provisionnement d’identité « se connecter avec … »
Keycloak connexion par l’annuaire auto-hébergé tes comptes vivent dans un realm Keycloak
WebAuthn passkeys, connexion résistante au phishing tu veux supprimer les mots de passe
TOTP second facteur temporel + step-up 2FA, ou re-preuve avant une action sensible
Webhooks notifier un tiers, signé et sans SSRF un système externe doit réagir à tes événements
Journal d’audit tracer les événements de sécurité conformité, investigation, supervision
firewall Le pare-feu applicatif : trois questions pour chaque requête — est-ce une zone protégée ? qui es-tu ? as-tu le droit ? Le chemin chaud (détecter) est séparé du chemin froid (décider), donc une route publique ne paie rien. à lire en premier — toutes les autres briques s'y branchent authenticators Prouver qui appelle : sept stratégies au même contrat — session, userpassword, jwt, external-jwt, apikey, anonymous, firewall-realtime — qui se composent dans l'ordre au sein d'une zone. commence par « Ordre et modes » : les pièges de configuration sont là authorization Décider des droits : rôles hiérarchisés, scopes, et voters métier qui portent le vrai pouvoir applicatif. Le jury vote, la stratégie tranche. juste après les authenticators — authentifier sans autoriser ne protège rien page de connexion La page servie à /login : identifiant, mot de passe, second facteur, boutons des fournisseurs, thèmes clair et sombre. Textes, panneau et couleurs se règlent par la configuration et une feuille de style — sans copier son balisage. le piège : une couleur qui dépend du thème se redéfinit pour les DEUX thèmes tokens L'identité matérialisée : émission, keystore, rotation, révocation — et le choix structurant du framework, session opaque côté serveur pour le web, JWT pour les API. et pourquoi ce n'est pas « full stateless » obtenir un jeton L'autre voie d'émission : l'application signe elle-même un porteur en ligne de commande, sans serveur en marche ni mot de passe — c'est ce dont un client MCP ou un script d'exploitation a besoin. le refus le plus fréquent : l'audience n'est pas déclarée audit La mémoire de ce qui s'est passé : qui s'est connecté, quel accès a été refusé, quelle clé a été révoquée. Conçu pour ne pas peser sur le chemin chaud de la requête. alimente aussi les webhooks

🏛️ Place dans le framework#

Le module consomme @nodefony/user (jamais l’inverse) et n’importe @nodefony/http / framework qu’en type-only, à une exception près : schemaMismatchOf (webhooks.ts), importé de @nodefony/http pour reconnaître une base au schéma en retard avec la même règle que le cœur HTTP, plutôt qu’avec une copie.

🧰 Surface publique#

Services Firewall, AuthFlow, TokenService, ApiKeyService, Authorization, WebAuthnService, OAuth2Service, AuditService, TotpService, WebhookService ; briques SecuredArea, Csrf/CsrfTokenManager, Cors, SecurityHeaders, RoleHierarchyWalker ; voters RoleVoter, ScopeVoter ; les *Authenticator ; stores mémoire et JwtKeystore.

Les signatures exactes vivent dans le graphe généré — jq '.symbols.Firewall' .ai/symbols.json — jamais recopiées ici (elles divergeraient).

🛠️ Gérer les comptes en exploitation#

Sur un serveur, la console d’administration suppose d’y être déjà entré — ce qui est précisément impossible quand on a perdu le mot de passe. Ces commandes sont l’autre porte, et elles s’exécutent sans ouvrir de port (profil console) :

Commande Ce qu’elle fait
nodefony security:user:add <id> [--admin] crée un compte, puis dit comment s’authentifier
nodefony security:user:list [-q <motif>] identifiant, rôles, état
nodefony security:user:password <id> change le mot de passe — et révoque sessions et jetons
nodefony security:user:delete <id> supprime, après confirmation ; refuse le dernier administrateur
nodefony security:secrets [--write] engendre les clés attendues et guide leur câblage
nodefony security:mcp:token émet un jeton d’accès pour la porte MCP
nodefony security:keycloak:realm [--write|--check] écrit le realm Keycloak déduit de la configuration (Keycloak)

En terminal, le mot de passe est demandé masqué et confirmé ; pour un script, --password <pwd> l’accepte en argument — au prix de l’historique du shell, que la commande rappelle.

Deux garde-fous qui se constatent plutôt qu’ils ne se supposent : le dernier administrateur actif ne se supprime pas (security-user-delete.ts#SecurityUserDelete.generate), et un changement de mot de passe éjecte les accès en cours par la même cascade que la suppression (userRevocationCascade.ts#KernelListenerLike) — on change un mot de passe parce qu’il est perdu ou compromis.

⚙️ Configuration#

Un seul point d’entrée : use("@nodefony/security", { … }) dans nodefony.config.ts, validé par Zod au boot. Blocs : areas (zones + authenticators), cors, csrf, headers, rateLimit (backoff NIST), puis un bloc par brique (jwt, apiKeys, totp, webhooks, audit, passkeys, oauth2). Chaque page de brique détaille son bloc, avec une table dérivée du schéma.

📜 Normes appliquées#

Domaine Normes
Auth / challenge (401) RFC 9110 §11
JWT RFC 7519, 8725 (BCP)
OAuth 2 RFC 9700 (BCP), 8707, 8693, 9449 (DPoP)
Passkeys W3C WebAuthn L3, CTAP2
TOTP / HOTP RFC 6238, 4226
Mots de passe / 2FA NIST SP 800-63B (throttling, timeouts)
Cookies RFC 6265bis (SameSite, __Host-)
CSRF Fetch Metadata (Sec-Fetch-Site) + Origin/Referer
En-têtes CSP (W3C), HSTS (RFC 6797), COOP/COEP/CORP
Rate limit RFC 6585 (429)
Général OWASP Top 10, OWASP ASVS

📖 Lexique#

Sigle Sens
WAF Web Application Firewall : filtre applicatif des requêtes selon des règles.
Zero Trust « ne rien accorder sans preuve » : aucune requête n’est de confiance par défaut.
JWT JSON Web Token : jeton signé porté par le client (RFC 7519).
OAuth 2 Protocole de délégation d’autorisation (RFC 9700 BCP).
WebAuthn Authentification par passkey/clé (W3C WebAuthn L3).
TOTP/HOTP Codes à usage unique temporels/à compteur — 2FA (RFC 6238 / 4226).
MFA / 2FA Authentification à plusieurs / deux facteurs.
CSRF Cross-Site Request Forgery : requête authentifiée forgée par un site tiers.
CORS Cross-Origin Resource Sharing : règles d’appel cross-origine.
CSP Content-Security-Policy : restreint les sources de scripts (anti-XSS).
HSTS HTTP Strict Transport Security : force le TLS (RFC 6797).
RBAC Role-Based Access Control : droits selon le rôle.
Voter Composant qui vote « accès accordé/refusé » sur un critère (rôle, scope).
BFF Backend-For-Frontend : le serveur gère la session/les jetons pour le front.
PAT Personal Access Token : une clé d’API opaque, révocable côté serveur.

📡 Observabilité — Studio#

Quatre écrans dédiés (@nodefony/studio/frontend/src/routes/) : Firewall (zones et décisions, état runtime), ApiKeys, Audit (journal), Webhooks — plus les pages Roles, Sessions, Login, Users. Data plane admin : SecurityAdminApi / WebhookAdminApi sous /nodefony/security/api/*.

🧪 Tests & couverture#

Le module est le plus testé du framework. Chaque page de brique porte l’inventaire de ses tests (unitaires, intégration, E2E sur base réelle, bancs de contrat, tests d’attaque) et dit ce qui manque — un trou de couverture nommé vaut mieux qu’un chiffre flatteur. Les compteurs sont recomptés à chaque génération, jamais figés dans le texte.

🔗 Pour aller plus loin#