---
title: "Référence d'API — @nodefony/security — contracts"
source: docs/api/security/contracts.md
url: https://nodefony.github.io/nodefony-core/docs/api/security/contracts/
---


[Documentation](../../../) › [Référence d'API](../../) › [`@nodefony/security`](../) › contracts

> Générée depuis les déclarations de types publiées de `@nodefony/security` **10.0.0-beta.5** : exactement ce que reçoit une application qui l'installe. Cette page n'existe dans aucun dépôt — pour la corriger, on corrige le TSDoc du code.

## `@nodefony/security`

`import { … } from "@nodefony/security"` — 47 symboles.

### Interfaces (39)

#### `IAccessTokenRecord`

```ts
interface IAccessTokenRecord
```

Enregistrement d'un jeton persistant — un PAT (clé API style GitHub) ou un refresh token. Le secret n'est JAMAIS stocké en clair : seul `secretHash` vit ici (le secret high-entropy est affiché une seule fois à la création).

- `id: string` — Identifiant unique : claim `jti` (refresh) / id public (PAT).
- `kind: "pat" | "refresh"` — Nature : clé API personnelle (`pat`) ou refresh token (`refresh`).
- `name: string` — Libellé humain (« CI deploy », « app mobile ») — affiché dans la console.
- `prefix: string | null` — Préfixe public affichable (« nf_a1b2c3… ») pour l'UI/lookup ; `null` pour un refresh opaque.
- `subjectId: string` — Identité du porteur (id d'un utilisateur OU d'un service account).
- `subjectType: "user" | "service"` — Discriminant du porteur (humain vs machine).
- `tenantId: string | null` — Organisation/tenant (multi-tenant, façon orgs GitHub) — axe distinct du porteur ; `null` = global.
- `scopes: string[]` — Capacités accordées à ce jeton (⊆ droits du porteur — downscoping).
- `audience: string[]` — Audiences liées (claim `aud`, RFC 8707/9700) ; `[]` = audience de l'app.
- `resources: IResourcePermission[] | null` — Permissions fine-grained (slot GitHub) ; `null` = portée par les seuls `scopes`.
- `secretHash: string` — Hash du secret présenté (jamais le secret) — clé de `ITokenStore.findByHash`.
- `hashAlg: string` — Algorithme de hachage du secret (agilité crypto, migration future).
- `clientId: string | null` — Client OAuth émetteur (slot OAuth2) ; `null` = non-OAuth.
- `cnf: string | null` — Confirmation sender-constrained : `jkt` (DPoP RFC 9449) / `x5t#S256` (mTLS RFC 8705) ; `null` = bearer simple.
- `family: string | null` — Famille de rotation : un refresh tourné conserve la famille (reuse detection) ; `null` pour un PAT.
- `replacedBy: string | null` — `id` du successeur après rotation (chaîne d'audit) ; `null` = feuille active.
- `createdAt: number` — Création (epoch ms).
- `expiresAt: number | null` — Expiration (epoch ms) ; `null` = sans expiration (PAT longue durée).
- `lastUsedAt: number | null` — Dernier usage (epoch ms) ou `null`.
- `lastUsedIp: string | null` — IP du dernier usage (audit « last used from ») ; slot.
- `lastUsedUserAgent: string | null` — User-Agent du dernier usage (audit) ; slot.
- `revokedAt: number | null` — Instant de révocation (epoch ms) ou `null` si actif.
- `revokedReason: TokenRevokeReason | null` — Raison de révocation (audit) ou `null`.
- `metadata: Record<string, unknown>` — Extras applicatifs libres (anti-migration), `{}` par défaut.

#### `IAccessVoter`

```ts
interface IAccessVoter
```

Voter contextuel (niveau C de l'autorisation, P6.8) — décide d'un accès en fonction du token ET du sujet (ex. « cet user édite-t-il SON projet ? »).

- `supports(attribute: string, subject?: unknown): boolean` — Ce voter sait-il décider de cet attribut/sujet ?
- `vote(token: IToken, attribute: string, subject?: unknown): Promise<VoterVote>` — Vote pour l'attribut donné sur le sujet donné.

#### `IApiKeyCapabilities`

```ts
interface IApiKeyCapabilities
```

Capacités/contraintes d'émission des clés API — exposées à la console (« Mes clés ») pour un formulaire de création **honnête** : plafond par porteur, catalogue de scopes, préfixe public, durée par défaut. **Aucune valeur sensible** (config publique : le préfixe figure déjà dans chaque clé).

- `enabled: boolean` — Émission de clés activée en config (`apiKeys.enabled`).
- `prefix: string` — Marqueur public des clés (`<prefix>_…`, ex.
- `defaultExpiryDays: number | null` — Expiration par défaut en jours (`null` = sans expiration).
- `maxPerSubject: number` — Plafond de clés ACTIVES par porteur (création au-delà → 409).
- `allowedScopes: string[] | null` — Catalogue de scopes autorisés (`null` = libre : tout scope non vide accepté).

#### `IApiKeyCreated`

```ts
interface IApiKeyCreated extends IApiKeyView
```

Résultat d'une **création** de clé — la vue publique **+ le token en clair**. Le `token` n'est disponible qu'ICI, une seule fois : il n'est jamais stocké (seul son `sha256` l'est) ni re-dérivable. La console l'affiche puis l'oublie.

- `token: string` — Secret EN CLAIR — affiché UNE seule fois (RFC : « shown once »).

#### `IApiKeyView`

```ts
interface IApiKeyView
```

Vue **publique** d'une clé API (PAT) — projection de `IAccessTokenRecord` **sans le secret ni son hash** (jamais exposés après création). C'est la forme renvoyée par la console (« mes clés ») et le data plane Studio.

- `id: string` — Identifiant public de la clé (révocation, affichage).
- `prefix: string | null` — Préfixe public affichable (`<prefix>_<pubid>`, ex.
- `name: string` — Libellé humain (« CI deploy », « app mobile »).
- `scopes: string[]` — Capacités accordées (axe distinct des rôles RBAC).
- `subjectId: string` — Porteur (id utilisateur ou service account).
- `subjectType: "user" | "service"` — Discriminant du porteur.
- `tenantId: string | null` — Organisation/tenant (`null` = global).
- `createdAt: number` — Création (epoch ms).
- `expiresAt: number | null` — Expiration (epoch ms) ou `null` (sans expiration).
- `lastUsedAt: number | null` — Dernier usage (epoch ms) ou `null` (jamais utilisée).
- `lastUsedIp: string | null` — Adresse du dernier usage, ou `null`.
- `lastUsedUserAgent: string | null` — Agent du dernier usage, ou `null` (même usage : reconnaître l'inattendu).
- `revokedAt: number | null` — Révocation (epoch ms) ou `null` (active).

#### `IAuditEvent`

```ts
interface IAuditEvent
```

Un événement de sécurité journalisé. `id`/`ts` sont posés par l'`AuditService` (l'émetteur ne fournit qu'un `IAuditEventDraft`) → un seul appel système d'horodatage, centralisé hors des points d'émission.

- `id: string` — Identifiant unique dans le process (corrélation + curseur de pagination).
- `ts: number` — Horodatage (epoch ms, `Date.now()`), posé par le service.
- `category: AuditCategory` — Sous-système concerné — axe de filtrage principal.
- `action: string` — Action conventionnée `<sujet>.<verbe>` (ex.
- `outcome: AuditOutcome` — Issue de l'action.
- `actor: string | null` — Acteur : identité (`token.getUserIdentifier()`) ou `null` si anonyme/non identifié (tentative pré-authentification).
- `resource?: string | null` — Ressource visée (zone firewall, route, canal WS, attribut d'autorisation) — descripteur léger ; jamais le corps ni les en-têtes de la requête.
- `reason?: string | null` — Raison **machine** stable et filtrable (ex.
- `ip?: string | null` — IP source si disponible (audit « from where »).
- `userAgent?: string | null` — User-Agent source si disponible.
- `requestId?: string | null` — Id de requête (corrélation log ↔ audit via l'ALS, P1.4) ; `null` hors requête.
- `flags?: IAuditEventFlags` — **Présence** (jamais la valeur) de matériel sensible au moment de l'événement — calque `AuditLogEntry.hasAuthorization`.
- `metadata?: Record<string, unknown>` — Extras applicatifs libres (anti-migration) ; absents par défaut.

#### `IAuditEventFlags`

```ts
interface IAuditEventFlags
```

Drapeaux de **présence** de matériel sensible (jamais la valeur).

- `hasAuthorization?: boolean` — Un en-tête `Authorization` était présent.
- `hasCookie?: boolean` — Un cookie était présent.

#### `IAuditListQuery`

```ts
interface IAuditListQuery extends IPageQuery
```

Filtre de lecture du journal d'audit (console Studio P6.15, data plane P6.14 Lot 3) — `IPageQuery` + les critères propres au journal. Tous les critères sont **AND** ; absents = non filtrant.

- `category?: AuditCategory` — Restreint à un sous-système.
- `outcome?: AuditOutcome` — Restreint à une issue (`success`/`failure`/`denied`).
- `actor?: string` — Restreint à un acteur (égalité exacte de l'identifiant).
- `action?: string` — Restreint à une action conventionnée (`"login.success"`…).
- `requestId?: string` — Restreint aux événements d'une **requête** (corrélation trace ↔ audit, P6.15).
- `since?: number` — Borne basse d'horodatage (epoch ms, inclus).
- `until?: number` — Borne haute d'horodatage (epoch ms, inclus).

#### `IAuditSink`

```ts
interface IAuditSink
```

Face **émission** du journal, vue par les points sensibles (firewall, authenticators, controllers OAuth/WebAuthn). `record` est **synchrone et fire-and-forget** : l'audit ne doit JAMAIS bloquer ni faire échouer le flux métier (un store en panne se solde par un log d'erreur, pas par un login KO). No-op à coût nul si l'audit est désactivé.

- `record(event: IAuditEventDraft): void` — Journalise un événement : pose `id`+`ts`, persiste (best-effort) et notifie les abonnés live.
- `subscribe(listener: (event: IAuditEvent) => void): () => void` — S'abonne au flux live des événements (bridge WS, P6.14 Lot 4).

#### `IAuditStore`

```ts
interface IAuditStore
```

Journal d'audit **append-only** (tamper-evident) — état serveur des événements de sécurité. **Pluggable** par backend (mémoire/fichier/ORM/Loki) comme `ITokenStore`. La référence mémoire borne le volume (anti-fuite) ; un backend partagé (ORM/Redis) sert le multi-pod et la rétention longue.

- `append(event: IAuditEvent): Promise<void>` — Ajoute un événement (immuable, jamais modifié ensuite).
- `listPage(query: IAuditListQuery): Promise<IPage<IAuditEvent>>` — Lit **une page** d'événements filtrés, du plus récent au plus ancien — l'implémentation ne matérialise jamais plus que `limit` événements.
- `gc(now?: number): Promise<number>` — Purge les événements au-delà de la fenêtre de rétention.

#### `IAuthenticator`

```ts
interface IAuthenticator
```

Stratégie d'authentification — pattern « authenticator » : une classe = une façon de prouver qui on est. Pas de Bridge/Factory (héritage Passport/YAML abandonné).

- `readonly name: string` — Nom logique (référencé dans `area.authenticators`).
- `supports(context: ContextType): boolean` — Peut-on extraire un credential de cette requête ?
- `createToken(context: ContextType): Promise<IToken>` — Construit un token NON authentifié depuis la requête (extraction credential).
- `authenticate(token: IToken): Promise<IToken>` — Valide le token (vérifie le credential) ou `throw` une AuthenticationError.
- `onSuccess(context: ContextType, token: IToken): Promise<void>` — Hook succès — pose le token (cookie JWT, log audit S1…).
- `onFailure(context: ContextType, error: Error): Promise<void>` — Hook échec — log audit, throttling (J2)… Le 401 + challenge sont posés par le firewall.
- `challenge?(area?: ISecuredArea): string` — Challenge `WWW-Authenticate` (RFC 9110 §11 : tout 401 DOIT en porter un).
- `validateArea?(area: ISecuredArea): void` — Vérifie AU BOOT que la zone qui référence cet authenticator lui donne ce dont il a besoin — sinon `throw`, et la configuration n'existe pas.

#### `IAuthorizationService`

```ts
interface IAuthorizationService
```

Service d'autorisation (niveau C de la sécurité, P6) — décide si un token a le droit d'effectuer une action (`attribute`) sur un sujet (`subject`).

- `decide(token: IToken, attribute: string, subject?: unknown): Promise<boolean>` — Le token a-t-il le droit demandé ?

#### `ICreateApiKeyOptions`

```ts
interface ICreateApiKeyOptions
```

Options de création d'une clé API.

- `name: string` — Libellé humain (obligatoire, non vide).
- `scopes?: string[]` — Capacités demandées (⊆ `apiKeys.allowedScopes` si un catalogue est défini).
- `expiresInDays?: number | null` — Durée de vie en jours ; `null` = sans expiration ; omis = défaut config.
- `tenantId?: string | null` — Tenant/organisation (multi-tenant) ; `null` = global.

#### `IFirewall`

```ts
interface IFirewall extends IFirewallGate
```

Orchestrateur de sécurité — branché dans le pipeline HTTP/WS de `@nodefony/http`.

- `isSecure(context: ContextType): boolean` — Match rapide de zone (pose `context.security`).
- `handleSecurity(context: ContextType): Promise<ContextType>` — Pipeline complet d'authentification de la zone.
- `enforceCsrf(context: ContextType): void` — Défense CSRF (Fetch Metadata + repli Origin) sur les méthodes state-changing.
- `handleCors(context: ContextType): number` — Politique CORS : pose les en-têtes `Access-Control-*`.
- `applySecurityHeaders(context: ContextType): void` — Pose les en-têtes de sécurité applicatifs (CSP, Referrer-Policy, COOP/COEP/ CORP, Permissions-Policy) sur la réponse.
- `registerCspOrigins(moduleName: string, fragment: CspFragment): void` — Déclare des directives CSP additionnelles pour un module (ex.
- `unregisterCspOrigins(moduleName: string): void` — Retire les directives CSP d'un module (ex.
- `registerAuthenticator(authenticator: IAuthenticator): void` — Enregistre un authenticator (appelé par chaque `*Authenticator` au boot).
- `getArea(name: string): ISecuredArea` — Zone par nom, ou `undefined`.
- `describe(): IFirewallDescription` — Projection LECTURE SEULE de l'état RUNTIME (zones/authenticators/défenses) pour le data plane Studio — **secrets exclus** (présence, jamais valeur).
- `describeRoleHierarchy(): IRoleHierarchyDescription` — Hiérarchie de rôles déclarée + résolution transitive (data plane Studio).
- `publishedProtectedResources(): readonly IProtectedResourceInput[]` — Ressources protégées à publier en RFC 9728 — une par `area.resource` déclarée, avec les émetteurs de confiance comme serveurs d'autorisation.

#### `IIssuerPolicy`

```ts
interface IIssuerPolicy
```

Ce qu'on exige du paramètre `iss` renvoyé par le serveur d'autorisation (RFC 9207).

- `readonly issuer: string` — Émetteur attendu, sous sa forme canonique.
- `readonly requireIssParameter: boolean` — `true` si le serveur ANNONCE émettre `iss` (`authorization_response_iss_parameter_supported`) : son absence est alors une promesse non tenue, donc un refus.

#### `IJwtKeystore`

```ts
interface IJwtKeystore
```

Source du matériel cryptographique de signature des JWT.

- `getSigningKey(): Promise<IJwtSigningKey>` — Clé active de signature.
- `getPublicJWKS(): Promise<JSONWebKeySet>` — JWKS **public** (toutes les clés du keyset, paramètres publics uniquement) — passé à `createLocalJWKSet` pour résoudre la clé de vérification par `kid`.

#### `IJwtSigningKey`

```ts
interface IJwtSigningKey
```

Clé active de signature résolue par le keystore — la clé privée Ed25519 plus son `kid` (à poser dans l'en-tête JWT) et l'algorithme JWA.

- `readonly key: CryptoKey` — Clé privée Ed25519 (WebCrypto `CryptoKey`) qui signe les jetons.
- `readonly kid: string` — Identifiant de clé = thumbprint RFC 7638 → en-tête JWT `kid` (sélection au verify).
- `readonly alg: "EdDSA"` — Algorithme JWA — toujours `"EdDSA"` pour une clé Ed25519 (RFC 8037).

#### `ILogoutRequest`

```ts
interface ILogoutRequest
```

Ce que porte une déconnexion initiée par l'application (OpenID Connect RP-Initiated Logout 1.0 §2).

- `readonly idTokenHint: string` — ID token reçu au login (`id_token_hint`) : il dit au fournisseur QUELLE session fermer, et lui évite de demander une confirmation à l'utilisateur.
- `readonly postLogoutRedirectUri: string` — Adresse de retour, enregistrée chez le fournisseur (`post_logout_redirect_uri`).

#### `ILogoutTokenClaims`

```ts
interface ILogoutTokenClaims
```

Ce qu'un jeton de déconnexion VÉRIFIÉ désigne (OpenID Connect Back-Channel Logout 1.0 §2.4) : au moins l'un de `subject` et `sid`.

- `readonly issuer: string` — Émetteur canonique — celui de la liste fermée qui a servi à vérifier.
- `readonly subject: string | null` — `sub` : l'utilisateur chez le fournisseur, ou `null`.
- `readonly sid: string | null` — `sid` : LA session du fournisseur à fermer, ou `null` (= toutes celles de `subject`).
- `readonly tokenId: string` — `jti` : identifiant unique du jeton, la clé de l'anti-rejeu.
- `readonly expiresAt: number` — `exp` : fin de validité, en secondes depuis l'époque.

#### `IOAuthProvider`

```ts
interface IOAuthProvider
```

Adaptateur d'**un fournisseur OAuth/OIDC**, façade UNIFORME au-dessus d'un client OAuth 2.0 — masque les divergences entre fournisseurs derrière un contrat stable consommé par `OAuth2Service` :

- `readonly usesPkce: boolean` — `true` si le fournisseur exige PKCE (RFC 7636) — le service génère alors un `code_verifier` et le transmet aux deux méthodes ci-dessous.
- `readonly issuerPolicy: IIssuerPolicy | null` — Politique de vérification du paramètre `iss` (anti-mix-up, RFC 9207), ou `null` pour un fournisseur qui ne relève pas de cette défense (GitHub, non-OIDC).
- `readonly defaultScopes: string[]` — Scopes appliqués quand la configuration n'en précise aucun.
- `createAuthorizationURL(request: IAuthorizationRequest): URL` — Construit l'URL d'autorisation (étape 1).
- `validateAuthorizationCode(request: ITokenRequest): Promise<OAuth2Tokens>` — Échange le `code` d'autorisation contre des jetons (étape 2, canal serveur).
- `fetchProfile(tokens: OAuth2Tokens): Promise<IOAuthProfile>` — Récupère et **normalise** le profil de l'utilisateur à partir des jetons.
- `createLogoutURL?(request: ILogoutRequest): URL` — Construit l'adresse de déconnexion chez le fournisseur (RP-Initiated Logout).
- `verifyLogoutToken?(logoutToken: string): Promise<ILogoutTokenClaims | null>` — Vérifie un jeton de déconnexion reçu sur le canal arrière (OpenID Connect Back-Channel Logout 1.0 §2.6) et rend ce qu'il désigne.

#### `IResourcePermission`

```ts
interface IResourcePermission
```

Permission **fine-grained** sur une ressource (modèle GitHub fine-grained PAT).

- `type: string` — Type de ressource (ex.
- `ids?: string[]` — Identifiants ciblés (omis = toutes les ressources de ce type).
- `perms: Array<"read" | "write">` — Permissions accordées sur ces ressources.

#### `ISecuredArea`

```ts
interface ISecuredArea extends ISecurityZone
```

Zone sécurisée — un pattern d'URL + la liste des authenticators à exécuter.

- `readonly name: string` — Nom de la zone (`"main_api"`, `"admin"`…).
- `readonly pattern: RegExp` — Pattern d'URL compilé.
- `readonly security: boolean` — Zone protégée (Zero Trust) ; `false` = zone publique explicite.
- `readonly stateless: boolean` — Stratégie d'identité AU-DESSUS du protocole.
- `readonly mode: "first" | "all"` — Sémantique de la chaîne : `"first"` = le premier authenticator qui reconnaît la requête authentifie ; `"all"` = tous doivent passer (MFA — le DERNIER porte l'identité).
- `readonly authenticators: readonly string[]` — Noms des authenticators à exécuter (sémantique selon `mode`).
- `readonly host?: string` — Domaine/vhost de la zone (ex.
- `readonly resource?: string` — URI canonique de la ressource protégée par cette zone — l'**audience** qu'un jeton doit porter pour y être accepté (RFC 8707 §2).
- `readonly subjectPolicy?: "require" | "ephemeral"` — Politique de rattachement du sujet d'un jeton TIERS propre à cette zone, ou `undefined` pour suivre `resourceServer.subjectPolicy`.
- `readonly ephemeralRoles?: readonly string[]` — Rôles accordés par cette zone à un appelant `ephemeral` — définis dès que la zone déclare `subjectPolicy: "ephemeral"` (vide si elle n'en écrit aucun : un pouvoir local ne s'hérite jamais de la politi …
- `readonly entryPoint?: string` — Page de connexion vers laquelle le pare-feu conduit un visiteur anonyme qui NAVIGUE (`302` vers `<entryPoint>?from=<chemin demandé>`), au lieu du `401`.
- `readonly realtime: boolean` — Zone valable AUSSI pour le WebSocket (frames `api.request` + `subscribe`), pas seulement HTTP.
- `readonly roles: readonly string[] | null` — Rôles exigés PAR DÉFAUT dans la zone — en OU, hiérarchie comprise —, ou `null` quand la zone n'exige qu'une identité.
- `match(context: ContextType): boolean` — La requête tombe-t-elle dans cette zone ?

#### `IToken`

```ts
interface IToken
```

Jeton de sécurité — porte l'identité (authentifiée ou non) d'une requête.

- `readonly type: string` — Type du token (`"anonymous"`, `"userpassword"`, `"jwt"`, `"oauth2"`, `"mtls"`).
- `getUser(): IUser` — Utilisateur porté — jamais `null` (AnonymousUser si non authentifié).
- `getUserIdentifier(): string` — Identifiant logique de l'utilisateur (`"anonymous"`, `"admin"`…) — partagé avec `IRealtimeToken` (le token WS, sous-ensemble transport-neutre, n'a PAS `getUser()`).
- `isAuthenticated(): boolean` — `true` si l'authentification a réussi (≠ anonyme).
- `getRoles(): string[]` — Rôles **plats** de l'utilisateur (sans hiérarchie résolue).
- `getCredentials(): unknown` — Credential brut avant validation (vidé au succès).
- `getScopes(): string[]` — Scopes accordés (clé API / OAuth) — axe **distinct** des rôles RBAC.
- `getAttribute<T = unknown>(key: string): T` — Lecture d'un attribut arbitraire posé par l'authenticator (claims JWT, scopes…).
- `setAttribute(key: string, value: unknown): void` — Pose un attribut arbitraire (claims, scopes, providerId…).

#### `ITokenListQuery`

```ts
interface ITokenListQuery extends IPageQuery
```

Requête de **listing paginé** de jetons (data plane admin) — le contrat de page standard du core (`IPageQuery`) enrichi des filtres propres aux jetons. Tous **portables** au `Criteria` (`subjectId` indexé, colonnes simples) → pas de SQL natif, le helper `paginate()` d'orm-core suffit côté ORM.

- `subjectId?: string` — Restreint à un porteur (indexé).
- `kind?: "pat" | "refresh"` — Restreint à une nature de jeton.
- `status?: TokenStatus` — Restreint à un **état de vie** du jeton.

#### `ITokenStore`

```ts
interface ITokenStore extends ISortableSource
```

Contrat du store de jetons — implémentations enregistrées via `registerTokenStore`, sélectionnées par config. Toutes les opérations sont **asynchrones** (un backend ORM/Redis fait des I/O ; la référence mémoire résout immédiatement).

- `put(record: IAccessTokenRecord): Promise<void>` — Enregistre (ou remplace) un jeton persistant.
- `findById(id: string): Promise<IAccessTokenRecord | null>` — Recherche par identifiant (`jti`/id public).
- `findByHash(secretHash: string): Promise<IAccessTokenRecord | null>` — Recherche par hash de secret présenté.
- `findBySubject(subjectId: string): Promise<IAccessTokenRecord[]>` — Tous les jetons d'un porteur (console « mes jetons », révocation ciblée).
- `listAll(): Promise<IAccessTokenRecord[]>` — **Tous** les jetons du store, tous porteurs confondus — vue d'ADMINISTRATION cross-porteur (gouvernance / réponse à incident).
- `listPage(query: ITokenListQuery): Promise<IPage<IAccessTokenRecord>>` — Liste **paginée** de jetons pour le data plane admin — ne matérialise **jamais** plus d'une page (contrairement à `ITokenStore.listAll`, réservé au dump d'incident).
- `countTokens(query: ITokenListQuery): Promise<number>` — Compte les jetons correspondant aux filtres — base du `total` de la page (SQL/Mongo `COUNT`, mémoire `length`).
- `markUsed(id: string, usage: ITokenUsage): Promise<void>` — Met à jour `lastUsedAt`/IP/UA (no-op si l'id est inconnu).
- `revoke(id: string, reason: TokenRevokeReason): Promise<void>` — Révoque un jeton (pose `revokedAt`+`revokedReason`) — idempotent.
- `revokeFamily(family: string, reason: TokenRevokeReason): Promise<void>` — Révoque TOUTE la famille de rotation (détection de rejeu, RFC 9700).
- `denyJti(jti: string, expiresAt: number): Promise<void>` — Inscrit un `jti` d'access sur la denylist jusqu'à `expiresAt` (epoch ms) — révocation immédiate avant l'`exp` du JWT.
- `isJtiDenied(jti: string): Promise<boolean>` — `true` si le `jti` est denylisté et non encore expiré.
- `revokeAllForSubject(subjectId: string, invalidBefore: number): Promise<void>` — Pose le seuil `invalidBefore` (epoch ms) d'un porteur : tout access auto-porté dont `iat < invalidBefore` est rejeté.
- `getInvalidBefore(subjectId: string): Promise<number | null>` — Seuil `invalidBefore` d'un porteur (epoch ms) ou `null` si aucun.
- `gc(now?: number): Promise<number>` — Purge les entrées devenues inutiles : denylist `jti` expirée, records arrivés à `exp`, PAT révoqués sans expiration au-delà de la fenêtre de rétention.

#### `ITokenUsage`

```ts
interface ITokenUsage
```

Contexte d'un usage de jeton (audit « last used »).

- `at: number` — Instant d'usage (epoch ms).
- `ip?: string | null` — IP source, si disponible.
- `userAgent?: string | null` — User-Agent source, si disponible.

#### `ITotpEnrollmentSummary`

```ts
interface ITotpEnrollmentSummary
```

Vue d'un enrôlement 2FA pour l'INTROSPECTION admin (« qui a activé le 2FA, qui est resté en attente de confirmation »).

- `readonly userId: string` — Utilisateur propriétaire.
- `readonly algorithm: string` — Fonction HMAC du code (RFC 6238 §1.2).
- `readonly digits: number` — Nombre de chiffres du code.
- `readonly period: number` — Période d'un code en secondes.
- `readonly confirmedAt: number | null` — Confirmation de l'enrôlement (epoch ms), ou `null` = en attente.
- `readonly createdAt: number` — Création de l'enrôlement (epoch ms).
- `readonly lastUsedAt: number | null` — Dernier usage réussi (epoch ms), ou `null` = jamais servi.
- `readonly recoveryCodesLeft: number` — Nombre de codes de récupération NON consommés (jamais les condensats).

#### `ITotpListQuery`

```ts
interface ITotpListQuery extends IPageQuery
```

Requête de listing des enrôlements 2FA — `IPageQuery` + les filtres qui ont un sens ici. `q` (hérité) = **préfixe** d'`userId` (retrouver un id partiel collé depuis la console).

- `confirmed?: boolean` — `true` = enrôlements confirmés seulement, `false` = en attente seulement (comptes à relancer : un secret jamais confirmé ne protège personne), omis = les deux.

#### `ITotpSecret`

```ts
interface ITotpSecret
```

Secret TOTP d'un utilisateur (2FA) — **un seul par utilisateur** (clé = `userId`).

- `readonly userId: string` — Propriétaire = `IUser.identifier` (clé naturelle), jamais `IUser.id` — cf `ITotpSecretStore`.
- `readonly secretEnc: string` — Secret partagé `K` **chiffré** (blob opaque : `iv.tag.ciphertext` base64url).
- `readonly algorithm: TotpAlgorithm` — Fonction HMAC du code (RFC 6238 §1.2).
- `readonly digits: number` — Nombre de chiffres du code.
- `readonly period: number` — Période d'un code en secondes.
- `recoveryCodes: string[]` — Condensats `sha256` des codes de récupération **non encore consommés**.
- `confirmedAt: number | null` — Horodatage de **confirmation** de l'enrôlement (epoch ms), ou `null` tant que l'utilisateur n'a pas prouvé qu'il lit bien les codes (anti-lock-out).
- `lastUsedStep: number | null` — Dernière tranche temporelle `T` ayant validé un code (RFC 6238 §5.2) — un code déjà consommé dans sa fenêtre **ne doit pas resservir** (anti-rejeu).
- `readonly createdAt: number` — Horodatage de création (epoch ms).
- `lastUsedAt: number | null` — Horodatage du dernier usage réussi (epoch ms), ou `null`.

#### `ITotpSecretStore`

```ts
interface ITotpSecretStore
```

Store **pluggable** du secret TOTP par utilisateur — découple le cœur du backend de persistance (mémoire / fichier / ORM / Redis). Convention-frère d'`IWebAuthnCredentialStore` / `ITokenStore` : le builtin `memory` est sans dépendance, les adapters lourds s'enregistrent depuis leur propre module.

- `findByUser(userId: string): Promise<ITotpSecret | null>` — Secret TOTP de l'utilisateur, ou `null` si non enrôlé.
- `save(secret: ITotpSecret): Promise<void>` — Crée ou remplace le secret de l'utilisateur (upsert — ré-enrôlement).
- `update(userId: string, patch: TotpSecretUpdate): Promise<void>` — Applique un patch partiel (confirmation, anti-rejeu, consommation de codes).
- `delete(userId: string): Promise<void>` — Supprime le secret de l'utilisateur (désactivation du 2FA).
- `listPage(query: ITotpListQuery): Promise<IPage<ITotpEnrollmentSummary>>` — Page d'enrôlements 2FA pour le data plane admin — ne matérialise jamais plus d'une page, filtres appliqués au store, **secrets exclus** (cf `ITotpEnrollmentSummary`).
- `countEnrollments(query: ITotpListQuery): Promise<number>` — Nombre d'enrôlements correspondant aux filtres (`COUNT` natif) — le KPI « couverture 2FA » sans énumérer.

#### `IWebAuthnCredential`

```ts
interface IWebAuthnCredential
```

Enregistrement d'un **credential WebAuthn / passkey** côté serveur — le `credentialRecord` de WebAuthn L3 §7.1 (produit par la cérémonie d'enregistrement, relu et mis à jour à chaque authentification §7.2).

- `readonly id: string` — Identifiant du credential (base64url) — unique, fourni par l'authenticator.
- `readonly userId: string` — Propriétaire = `IUser.identifier` (sub / userHandle applicatif), jamais `IUser.id` — cf `IWebAuthnCredentialStore`.
- `readonly publicKey: string` — Clé publique **COSE** encodée base64url — vérifie la signature des assertions.
- `signCount: number` — Compteur de signatures (WebAuthn §6.1.1) — anti-clone : SHOULD croître à chaque authentification.
- `readonly transports: readonly string[]` — Transports annoncés (`usb` | `nfc` | `ble` | `internal` | `hybrid`).
- `readonly backupEligible: boolean` — BE flag (Backup Eligibility, §6.1.3) — credential multi-appareils (synchronisable).
- `backupState: boolean` — BS flag (Backup State) — actuellement sauvegardé.
- `uvInitialized: boolean` — La cérémonie a-t-elle réalisé une **vérification d'utilisateur** (biométrie/ PIN) au moins une fois (`uvInitialized`, §7.2) — base du step-up MFA.
- `nickname?: string` — Surnom optionnel de la passkey (« MacBook de Chris »).
- `readonly createdAt: number` — Création (epoch ms).
- `lastUsedAt: number | null` — Dernière authentification réussie (epoch ms), ou `null` si jamais utilisé.

#### `IWebAuthnCredentialStore`

```ts
interface IWebAuthnCredentialStore
```

Store **pluggable** des credentials WebAuthn — découple le cœur du backend de persistance (mémoire / ORM / Redis). Convention-frère d'`ITokenStore` : le builtin `memory` est sans dépendance, les adapters lourds s'enregistrent depuis leur propre module (inversion de dépendance).

- `findById(credentialId: string): Promise<IWebAuthnCredential | null>` — Credential par son id (base64url), ou `null` — résolution à l'authentification.
- `findByUser(userId: string): Promise<IWebAuthnCredential[]>` — Tous les credentials d'un utilisateur — pour `allowCredentials` (authentification ciblée) et l'UX « mes appareils ».
- `countByUser(userId: string): Promise<number>` — Nombre de credentials d'un utilisateur — **natif** par backend (`COUNT`, `countDocuments`, `SCARD`), jamais un `findByUser().length`.
- `save(credential: IWebAuthnCredential): Promise<void>` — Persiste un nouveau credential (fin de la cérémonie d'enregistrement).
- `update(credentialId: string, patch: WebAuthnAuthUpdate): Promise<void>` — Met à jour l'état post-authentification (compteur, sauvegarde, UV, usage).
- `delete(credentialId: string): Promise<void>` — Révoque un credential (l'utilisateur retire un appareil).
- `listPage(query: IWebAuthnListQuery): Promise<IPage<IWebAuthnCredentialSummary>>` — Page de passkeys pour le data plane admin — ne matérialise jamais plus d'une page, filtres appliqués au store, `publicKey` exclue (cf `IWebAuthnCredentialSummary`).
- `countCredentials(query: IWebAuthnListQuery): Promise<number>` — Nombre de passkeys correspondant aux filtres (`COUNT` natif), ou **`-1`** si le backend ne sait pas compter à coût raisonnable (Redis : un total exigerait un `SCAN` complet O(N) sur un chemin froid — …

#### `IWebAuthnCredentialSummary`

```ts
interface IWebAuthnCredentialSummary
```

Vue d'une passkey pour l'INTROSPECTION admin (« quels appareils portent des passkeys, lesquelles meurent avec leur appareil »).

- `readonly id: string` — Identifiant du credential (base64url) — la clé naturelle.
- `readonly userId: string` — Utilisateur propriétaire.
- `readonly transports: readonly string[]` — Canaux de l'authenticator (`internal`, `hybrid`, `usb`…).
- `readonly backupEligible: boolean` — Le credential PEUT être sauvegardé/synchronisé (BE flag).
- `readonly backupState: boolean` — Le credential EST sauvegardé (BS flag) — sinon il meurt avec l'appareil.
- `readonly uvInitialized: boolean` — Une vérification utilisateur (biométrie/PIN) a déjà eu lieu.
- `readonly signCount: number` — Compteur de signatures (anti-clone WebAuthn §6.1.1).
- `readonly nickname?: string` — Nom donné à l'appareil par l'utilisateur, si renseigné.
- `readonly createdAt: number` — Enrôlement (epoch ms).
- `readonly lastUsedAt: number | null` — Dernière authentification réussie (epoch ms), ou `null` = jamais servie.

#### `IWebAuthnListQuery`

```ts
interface IWebAuthnListQuery extends IPageQuery
```

Requête de listing des passkeys — `IPageQuery` + les filtres qui ont un sens ici. `q` (hérité) = **préfixe** d'`userId`.

- `userId?: string` — Restreindre à un porteur (sa liste d'appareils).
- `backedUp?: boolean` — `true` = passkeys sauvegardées/synchronisées seulement, `false` = celles liées à un seul appareil (les porteurs à risque de verrouillage), omis = les deux.

#### `IWebhookEndpoint`

```ts
interface IWebhookEndpoint
```

Endpoint webhook sortant — une **destination** que Nodefony notifie quand un événement souscrit survient (modèle façon GitHub/Stripe).

- `readonly id: string` — Identifiant public stable (`wh_<random>`).
- `readonly url: string` — URL de destination (validée anti-SSRF à l'enregistrement).
- `readonly secretEnc: string` — Secret de signature **chiffré** au repos (blob `gcm1.…`).
- `readonly events: readonly string[]` — Actions d'audit souscrites (ex.
- `readonly enabled: boolean` — Endpoint actif ?
- `readonly description: string | null` — Libellé humain optionnel (console admin).
- `readonly tenantId: string | null` — Slot multi-tenant (réservé P17) — `null` = global.
- `readonly createdBy: string | null` — Identité de l'admin créateur (soft ref, traçabilité).
- `readonly createdAt: number` — Création (epoch ms).
- `readonly updatedAt: number` — Dernière modification (epoch ms).
- `readonly lastDeliveryAt: number | null` — Dernière tentative de livraison (epoch ms) ou `null`.
- `readonly lastDeliveryStatus: number | null` — Code HTTP de la dernière livraison, ou `null` (jamais livré / erreur réseau).
- `readonly lastDeliveryError: string | null` — Message d'erreur de la dernière livraison, ou `null`.
- `readonly failureCount: number` — Échecs consécutifs (auto-désactivation au-delà d'un seuil, façon GitHub).
- `readonly metadata: Record<string, unknown>` — Métadonnées extensibles (jamais de secret).

#### `IWebhookListQuery`

```ts
interface IWebhookListQuery extends IPageQuery
```

Requête de **listing paginé** d'endpoints webhook (data plane admin) — le contrat de page standard du core (`IPageQuery`) enrichi des filtres propres aux endpoints.

- `enabled?: boolean` — `true` = actifs seulement, `false` = désactivés seulement, omis = les deux.
- `event?: string` — Ne garder que les endpoints **abonnés à cet événement** (appartenance au tableau `events`).
- `failing?: boolean` — `true` = seulement les endpoints **en échec** (au moins un échec consécutif courant, `failureCount > 0`), `false` = seulement ceux qui vont bien, omis = les deux.

#### `IWebhookStore`

```ts
interface IWebhookStore extends ISortableSource
```

Persistance des **endpoints webhook** (configuration durable, pas un cache). Backend interchangeable (Memory dev/test · Drizzle SQL · Mongoose) via le registre `../src/webhook/webhookStoreRegistry`. **Redis n'est PAS un store d'endpoints** (config durable ≠ éphémère) — il servira la *queue de livraison* cross-pod (slice cluster), pas ce contrat.

- `save(endpoint: IWebhookEndpoint): Promise<void>` — Insère un nouvel endpoint.
- `findById(id: string): Promise<IWebhookEndpoint | null>` — Charge un endpoint par id, ou `null`.
- `update(id: string, patch: WebhookEndpointUpdate): Promise<void>` — Applique un patch partiel (champs mutables) ; no-op si id absent.
- `delete(id: string): Promise<void>` — Supprime un endpoint ; no-op si id absent.
- `listAll(): Promise<IWebhookEndpoint[]>` — **Tous** les endpoints — réservé au **snapshot du dispatcher** (le service garde en mémoire la table complète des abonnements pour router un événement sans I/O, et la recharge au boot puis après chaqu …
- `listPage(query: IWebhookListQuery): Promise<IPage<IWebhookEndpoint>>` — Liste **paginée** d'endpoints pour le data plane admin — ne matérialise jamais plus d'une page, filtres `IWebhookListQuery` appliqués **au store** (jamais après un chargement complet).
- `countEndpoints(query: IWebhookListQuery): Promise<number>` — Nombre d'endpoints correspondant aux filtres (`COUNT` natif) — base du `total` d'une page et des compteurs de la console.

#### `TotpSecretUpdate`

```ts
interface TotpSecretUpdate
```

Champs mutables d'un secret TOTP (patch partiel).

- `confirmedAt?: number | null` — Confirmation de l'enrôlement (epoch ms) — passe le secret en « actif ».
- `recoveryCodes?: string[]` — Stock résiduel de codes de récupération hachés (après consommation).
- `lastUsedStep?: number` — Dernière tranche `T` validée (anti-rejeu RFC 6238 §5.2).
- `lastUsedAt?: number` — Horodatage du dernier usage réussi (epoch ms).

#### `WebAuthnAuthUpdate`

```ts
interface WebAuthnAuthUpdate
```

État mis à jour après une authentification réussie (WebAuthn §7.2).

- `signCount: number` — Nouveau compteur de signatures (anti-clone).
- `backupState: boolean` — Nouvel état de sauvegarde (BS flag).
- `uvInitialized: boolean` — UV réalisée durant cette cérémonie.
- `lastUsedAt: number` — Horodatage de l'usage (epoch ms).

### Types (7)

#### `AuditCategory`

```ts
type AuditCategory = "auth" | "authz" | "token" | "session" | "oauth" | "webauthn" | "csrf" | "cors" | "ws" | "webhook" | "config"
```

Sous-système de sécurité concerné — axe de filtrage principal de la console d'audit (Studio P6.15). Fermé : la liste des sous-systèmes est stable.

#### `AuditOutcome`

```ts
type AuditOutcome = "success" | "failure" | "denied"
```

Issue d'une action de sécurité. La distinction `failure`/`denied` est utile à l'auditeur : `failure` = l'acteur a échoué une preuve (brute-force, signature invalide) ; `denied` = une **politique** a refusé un acteur même bien formé (rôle manquant, origine interdite, plancher WS) — signal d'accès non autorisé.

#### `IAuditEventDraft`

```ts
type IAuditEventDraft = Omit<IAuditEvent, "id" | "ts">
```

Champs fournis par l'**émetteur** d'un événement — l'`AuditService` y ajoute `id` + `ts`. Garde les points d'émission concis et sans appel système d'horloge.

#### `TokenRevokeReason`

```ts
type TokenRevokeReason = "logout" | "rotated" | "reuse_detected" | "manual" | "compromised" | "subject_disabled" | "expired_cleanup"
```

Raison de révocation d'un jeton — tracée pour l'audit de sécurité.

#### `TokenStatus`

```ts
type TokenStatus = "active" | "expired" | "revoked"
```

État de vie d'un jeton — partition exhaustive, évaluée révoqué → expiré → actif.

#### `WebhookEndpointSummary`

```ts
type WebhookEndpointSummary = Omit<IWebhookEndpoint, "secretEnc">
```

Vue **publique** d'un endpoint (DTO console admin) — **sans** le secret chiffré. Le secret en clair n'est renvoyé qu'une fois, à la création/rotation.

#### `WebhookEndpointUpdate`

```ts
type WebhookEndpointUpdate = Partial<Pick<IWebhookEndpoint, "url" | "secretEnc" | "events" | "enabled" | "description" | "updatedAt" | "lastDeliveryAt" | "lastDeliveryStatus" | "lastDeliveryError" | "failureCount" | "metadata">>
```

Champs mutables d'un endpoint (PATCH). `id`/`createdAt`/`createdBy`/`tenantId` sont immuables après création.

### Énumérations (1)

#### `VoterVote`

```ts
enum VoterVote { GRANT = "GRANT", DENY = "DENY", ABSTAIN = "ABSTAIN" }
```

Vote d'un `IAccessVoter`. Stratégie firewall = affirmative + DENY veto : un seul DENY bloque ; sinon un GRANT suffit ; tous ABSTAIN → DENY (Zero Trust).

---

[← Toutes les références d'API](../../)
