---
title: "@nodefony/security — la sécurité de bout en bout"
source: src/packages/@nodefony/security/docs/index.md
url: https://nodefony.github.io/nodefony-core/docs/modules/security/
---


> 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](firewall/) — zones, Zero Trust, la chaîne de décision. **Tout part d'ici.**
2. [Authenticators](authenticators/) — les sept façons de prouver **qui** appelle.
3. [Autorisation](authorization/) — rôles, scopes, voters : **ce qu'il a le droit** de faire.
4. [Jetons](tokens/) — 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](firewall/) — déclarer la zone et ses authenticators.
2. [Clés d'API](api-keys/) — émettre, faire tourner, révoquer une clé opaque.
3. [Jetons](tokens/) — le JWT quand la vérification doit rester sans état.
4. [Jetons d'un émetteur TIERS](external-jwt/) — accepter Keycloak, Auth0 ou Entra sans leur
   céder l'application.
5. [Autorisation](authorization/) — borner chaque clé par des scopes.

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

1. [Authenticators](authenticators/) — la session BFF, et pourquoi le login est **déjà fourni**.
2. [Page de connexion](login-page/) — la page servie à `/login`, et comment l'habiller à ton nom.
3. [OAuth2](oauth2/) — « se connecter avec GitHub/Google » et le Shadow User.
4. [Keycloak](keycloak/) — brancher l'annuaire de l'entreprise, du realm au premier login.
5. [WebAuthn / passkeys](webauthn/) — se connecter sans mot de passe, résistant au phishing.
6. [TOTP](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é](headers/) — CSP, HSTS, COOP/COEP : ce que le navigateur applique pour toi.
2. [CSRF](csrf/) — empêcher un site tiers d'agir au nom de ton utilisateur.
3. [CORS](cors/) — qui a le droit de **lire** tes réponses.
4. [Journal d'audit](audit/) — prouver après coup qui a fait quoi.
5. [Webhooks](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](firewall/)                 | qui passe, qui est bloqué, sur quelles routes | toujours — c'est la fondation                    |
| [Authenticators](authenticators/)     | prouver l'identité de l'appelant              | tu as autre chose que du public                  |
| [Autorisation](authorization/)        | rôles, scopes, voters métier                  | tous tes utilisateurs n'ont pas les mêmes droits |
| [Jetons](tokens/)                     | émission, keystore, rotation, révocation      | API sans état, ou révocation immédiate           |
| [Clés d'API](api-keys/)               | accès machine révocable (PAT opaque)          | un script/CI/partenaire appelle ton API          |
| [Obtenir un jeton](obtenir-un-jeton/) | émettre un porteur en ligne de commande       | un agent MCP ou un script doit appeler ton app   |
| [CSRF](csrf/)                         | requête authentifiée forgée par un site tiers | tu sers un front avec cookie de session          |
| [CORS](cors/)                         | lecture cross-origine de tes réponses         | ton front est sur un autre domaine               |
| [En-têtes](headers/)                  | CSP, HSTS, COOP/COEP, Referrer-Policy         | tu sers du HTML à un navigateur                  |
| [Page de connexion](login-page/)      | la page `/login` servie, habillable           | des humains se connectent à ton application      |
| [OAuth2](oauth2/)                     | login social + provisionnement d'identité     | « se connecter avec … »                          |
| [Keycloak](keycloak/)                 | connexion par l'annuaire auto-hébergé         | tes comptes vivent dans un realm Keycloak        |
| [WebAuthn](webauthn/)                 | passkeys, connexion résistante au phishing    | tu veux supprimer les mots de passe              |
| [TOTP](totp/)                         | second facteur temporel + step-up             | 2FA, ou re-preuve avant une action sensible      |
| [Webhooks](webhooks/)                 | notifier un tiers, signé et sans SSRF         | un système externe doit réagir à tes événements  |
| [Journal d'audit](audit/)             | tracer les événements de sécurité             | conformité, investigation, supervision           |

```nodefony-cards
[
  { "icon": "🛡️", "title": "firewall", "href": "firewall/", "featured": true,
    "desc": "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.",
    "meta": "à lire en premier — toutes les autres briques s'y branchent" },
  { "icon": "🪪", "title": "authenticators", "href": "authenticators/",
    "desc": "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.",
    "meta": "commence par « Ordre et modes » : les pièges de configuration sont là" },
  { "icon": "⚖️", "title": "authorization", "href": "authorization/",
    "desc": "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.",
    "meta": "juste après les authenticators — authentifier sans autoriser ne protège rien" },
  { "icon": "🚪", "title": "page de connexion", "href": "login-page/",
    "desc": "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.",
    "meta": "le piège : une couleur qui dépend du thème se redéfinit pour les DEUX thèmes" },
  { "icon": "🎫", "title": "tokens", "href": "tokens/",
    "desc": "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.",
    "meta": "et pourquoi ce n'est pas « full stateless »" },
  { "icon": "🔑", "title": "obtenir un jeton", "href": "obtenir-un-jeton/",
    "desc": "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.",
    "meta": "le refus le plus fréquent : l'audience n'est pas déclarée" },
  { "icon": "📓", "title": "audit", "href": "audit/",
    "desc": "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.",
    "meta": "alimente aussi les webhooks" }
]
```

## 🏛️ Place dans le framework

```mermaid
flowchart LR
  HTTP["@nodefony/http<br/>transport, contextes, sessions"] --> SEC["@nodefony/security<br/>firewall, authn, authz"]
  USER["@nodefony/user<br/>identité IUser"] --> SEC
  SEC --> FW["@nodefony/framework<br/>@IsGranted, @CurrentUser"]
  SEC -.->|stores| DB["drizzle · mongoose · redis"]
```

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](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

- ⬆️ **Remonter** : [Toute la documentation](../../)
- 🧭 **Modules voisins** : [`@nodefony/user`](../user/) (l'identité) ·
  [`@nodefony/http`](../http/) (transport et sessions) ·
  [`@nodefony/framework`](../framework/) (décorateurs `@IsGranted`, `@CurrentUser`)
- 🏛️ **Transverse** : [pipeline de requête](../../architecture/pipeline-requete/) —
  où le firewall s'insère exactement dans le trajet d'une requête.
- 📖 [Lexique général](../../lexique/) du framework.
