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


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

> 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"` — 26 symboles.

### Classes (15)

#### `AccessTokenVerifierService`

```ts
class AccessTokenVerifierService extends Service
```

Pose (ou non) le vérificateur de jetons d'accès dans le conteneur — celui qu'une ressource protégée (porte MCP, zone `external-jwt`) interroge.

- `module: Module`
- `constructor(module: Module)`
- `get verifier(): IAccessTokenVerifier | null` — Le vérificateur posé, ou `null` si rien n'est vérifiable.

#### `ApiKeyService`

```ts
class ApiKeyService extends Service
```

Gestion des **clés API personnelles (PAT, P6.12)** — émission, listing et révocation, au-dessus du `ITokenStore` **partagé** (posé au container par le `TokenService`, qui en possède aussi le `gc`). Un PAT et un refresh token cohabitent dans la même table (`kind`) ; ce service ne traite que `kind:"pat"`.

- `module: Module`
- `constructor(module: Module)`
- `isEnabled(): boolean` — `true` si les clés API sont activées en config.
- `sortableFields(): readonly string[]` — Champs de tri que le backend **actuellement branché** sait honorer, en vocabulaire public.
- `createForSubject(subjectId: string, subjectType: "user" | "service", opts: ICreateApiKeyOptions, roles?: readonly string[]): Promise<IApiKeyCreated>` — Émet une nouvelle clé API pour un porteur — renvoie sa vue publique **+ le token en clair** (affiché une seule fois).
- `listForSubject(subjectId: string): Promise<IApiKeyView[]>` — Liste les clés (PAT) d'un porteur — vue publique, sans secret, récentes d'abord.
- `listPagePat(query: ITokenListQuery): Promise<IPage<IApiKeyView>>` — Liste **paginée** des clés (PAT) du système, tous porteurs confondus — vue d'ADMINISTRATION (gouvernance / réponse à incident), publique et sans secret.
- `countKeyFacets(query?: Partial<ITokenListQuery>): Promise<ITokenCounts>` — Les compteurs de tête de la console — posés sur la collection ENTIÈRE, pas sur la page affichée.
- `revokeAnyPat(id: string, actorId: string): Promise<IApiKeyView | null>` — Révoque **n'importe quelle** clé (PAT) — action d'ADMINISTRATION (réponse à incident : clé compromise), SANS contrainte de porteur (≠ `revokeForSubject`).
- `describeCapabilities(): IApiKeyCapabilities` — Capacités/contraintes d'émission (plafond, scopes, préfixe, durée par défaut) — pour un formulaire de création honnête côté console.
- `revokeForSubject(subjectId: string, id: string): Promise<boolean>` — Révoque une clé du porteur.

#### `AuditService`

```ts
class AuditService extends Service implements IAuditSink
```

Journal d'audit de sécurité (P6.14) — collecte les **événements** de sécurité (login, refus d'accès, jeton émis/révoqué, défense CSRF/CORS, verrou WS) émis EXPLICITEMENT par le firewall, les authenticators et les controllers. Distinct du log de trafic (`JsonAuditLogger`, P3.1, 1 PDU/requête) : ici on trace les **transitions d'état** de sécurité, jamais le hot-path par requête.

- `module: Module`
- `constructor(module: Module)`
- `record(draft: 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).
- `listPage(query: IAuditListQuery): Promise<IPage<IAuditEvent>>` — Lit une page du journal (délègue au store) ; vide si l'audit est inactif.
- `isEnabled(): boolean` — `true` si l'audit est actif (config `audit.enabled`).

#### `AuthFlow`

```ts
class AuthFlow extends Service
```

Flux de session BFF — login/logout/me côté serveur (P6 J3).

- `module: Module`
- `constructor(module: Module)`
- `login(context: ContextType, identifier: unknown, password: unknown): Promise<ILoginOutcome>` — Authentifie le couple identifiant/mot de passe et OUVRE la session BFF.
- `establishSessionFor(context: ContextType, identifier: unknown, reason?: string): Promise<ISafeUser>` — Ouvre la session BFF pour un utilisateur **déjà authentifié par un autre facteur** (passkey/WebAuthn, OAuth, magic link…) — aucun mot de passe à vérifier ici, la preuve a été apportée en amont par l'a …
- `completeMfaLogin(context: ContextType, code: unknown): Promise<ISafeUser>` — Valide le **second facteur** (code TOTP ou code de récupération) après un `login` ayant renvoyé `mfa_required`, puis OUVRE la session BFF.
- `ensureSession(context: ContextType): Promise<ISession | null>` — Garantit une session pour la requête courante — la démarre (+ cookie) si elle n'existe pas encore.
- `logout(context: ContextType): Promise<boolean>` — Détruit la session courante (storage + cookie).
- `logoutWithProvider(context: ContextType): Promise<{ destroyed: boolean; logoutUrl: string | null; }>` — Déconnexion COMPLÈTE : détruit la session locale et rend, si la session vient d'un fournisseur qui publie un point de déconnexion (Keycloak…), l'adresse où envoyer le navigateur pour fermer AUSSI sa s …
- `me(context: ContextType): Promise<ISafeUser | null>` — Identité portée par la session courante, re-résolue auprès du provider (mêmes contrôles que le `SessionAuthenticator` — source unique).
- `describeLoginPage(): ILoginPageDescription | null` — Décrit la page de connexion par défaut : ce qu'elle propose et comment elle s'habille, depuis `security.loginPage` et les fournisseurs opérationnels.

#### `Authorization`

```ts
class Authorization extends Service implements IAuthorizationService
```

Service d'autorisation Nodefony (niveau C, P6 J6) — décide d'un accès via un jury de `IAccessVoter`.

- `module: Module`
- `constructor(module: Module)`
- `decide(token: IToken, attribute: string, subject?: unknown): Promise<boolean>` — Le token a-t-il le droit `attribute` sur `subject` ?
- `log(pci: unknown, severity?: Severity, msgid?: Msgid, msg?: Message): Pdu` — Émet une entrée de log structurée — point d'entrée central pour TOUT log Nodefony.

#### `Cors`

```ts
class Cors
```

Politique CORS de Nodefony — Same-Origin Policy assouplie côté serveur (Fetch Standard / W3C CORS protocol). Logique PURE et synchrone : décide les en-têtes `Access-Control-*` à poser pour une origine donnée. Instanciée une fois au boot par le firewall, testable sans serveur.

- `constructor(options: ICorsOptions)`
- `reflectsOrigin(allowOrigin: string): boolean` — `true` si la valeur Allow-Origin reflète l'origine (⇒ l'appelant doit poser `Vary: Origin`).
- `preflightHeaders(origin: string): CorsHeaders | null` — En-têtes d'une réponse au **preflight** `OPTIONS` (méthodes/headers autorisés + cache + credentials), ou `null` si l'origine n'est pas autorisée (réponse 204 nue → le navigateur bloque).
- `actualHeaders(origin: string): CorsHeaders | null` — En-têtes d'une réponse à une **requête réelle** cross-origin (Allow-Origin + credentials + headers exposés au JS), ou `null` si l'origine n'est pas autorisée.

#### `Csrf`

```ts
class Csrf
```

Défense CSRF par défaut de Nodefony — **Fetch Metadata d'abord** (modèle Go 1.25 `CrossOriginProtection` / OWASP 2025), repli `Origin`/`Referer` pour les vieux navigateurs. Logique PURE et synchrone (aucun I/O, aucune alloc sur le hot-path GET) → testable sans serveur, instanciée une seule fois au boot par le firewall.

- `static isStateChanging(method: string | null): boolean` — `true` si la méthode mute l'état (hors `SAFE_METHODS`).
- `constructor(options: ICsrfOptions, allowedOrigins?: readonly string[])`
- `enforce(req: ICsrfRequest): void` — Valide la provenance d'une requête.

#### `Firewall`

```ts
class Firewall extends Service implements IFirewall
```

Orchestrateur de sécurité Nodefony — refonte 2026 (P6).

- `module: Module`
- `constructor(module: Module)`
- `get roleHierarchy(): RoleHierarchyWalker` — Hiérarchie de rôles résolue (niveau A de l'autorisation, P6.8).
- `hasRole(userRoles: readonly string[], required: string): boolean` — `true` si l'un des rôles de l'utilisateur couvre `required` (hiérarchie comprise).
- `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[]` — Ce que l'application PROTÈGE, à publier en RFC 9728 — une entrée par ressource déclarée par une zone.
- `matchPath(pathname: string, host?: string): SecuredArea | null` — Match de zone par pathname (+ host) SANS contexte — source UNIQUE consultée par `isSecure` (HTTP) ET le verrou WebSocket (la frame `api.request` n'a qu'un path).
- `isSecure(context: ContextType): boolean` — Match rapide de zone — pose `context.security`.
- `handleSecurity(context: ContextType): Promise<ContextType>` — Pipeline complet de la zone : chaîne d'authenticators (selon `mode`) → ALS → Zero Trust.
- `enforceCsrf(context: ContextType): void` — Défense CSRF (P6 J5/étape 2) — branchée dans le pipeline HTTP de `@nodefony/http` pour TOUTE requête (zone ou non), APRÈS le resolve (les marqueurs `@CsrfProtect`/ `@CsrfExempt` de la route sont dispo …
- `handleCors(context: ContextType): number` — Politique CORS (P6 J5) — appelée par `HttpKernel.handleHttp()` (`http-kernel.ts:1169`), en TÊTE du pipeline : avant le routing, avant le parse du corps, donc bien avant `handleFrontController` et le f …
- `currentRevalidator(): (nowMs?: number) => Promise<boolean> | null` — Le revalidateur de l'identité de la requête courante, pour une connexion longue qui la gardera (flux SSE).
- `applySecurityHeaders(context: ContextType): void` — En-têtes de sécurité APPLICATIFS (P6 J5) — CSP, Referrer-Policy, isolation cross-origin (COOP/COEP/CORP), Origin-Agent-Cluster, Permissions-Policy.
- `registerCspOrigins(moduleName: string, fragment: CspFragment): void` — Déclare des directives CSP additionnelles pour `moduleName` (cf `IFirewall`).
- `unregisterCspOrigins(moduleName: string): void` — Retire les directives CSP de `moduleName` et recompose si nécessaire.
- `log(pci: unknown, severity?: Severity, msgid?: Msgid, msg?: Message): Pdu` — Émet une entrée de log structurée — point d'entrée central pour TOUT log Nodefony.

#### `KeycloakService`

```ts
class KeycloakService extends Service
```

Service `keycloak` — toutes les actions de Nodefony sur un serveur Keycloak, en un point du conteneur.

- `module: Module`
- `constructor(module: Module)`
- `config(): ISecurityConfig` — La configuration de sécurité VALIDÉE, relue à chaque appel (chemin froid).
- `realmPlan(request?: IKeycloakRealmRequest): IKeycloakRealmPlan` — Le realm que la configuration implique, fusionné avec le fichier d'import.
- `writeRealm(plan: IKeycloakRealmPlan): boolean` — Écrit le realm d'un plan — rien si le fichier est déjà à jour.
- `admin(providerName?: string): KeycloakAdminClient` — Le client de l'API d'administration d'un fournisseur Keycloak.
- `expectedLoginTheme(skin?: LoginPageSkin): string` — Le thème de connexion qu'un habillage demande à Keycloak.
- `applyLoginTheme(options?: { provider?: string; skin?: LoginPageSkin; }): Promise<IKeycloakLoginThemeResult>` — Pose sur le realm VIVANT le thème de connexion d'un habillage.

#### `OAuth2Service`

```ts
class OAuth2Service extends Service
```

**Social login OAuth 2.0** (P6 J9) — orchestrateur du flux *Authorization Code*.

- `module: Module`
- `constructor(module: Module)`
- `isEnabled(): boolean` — `true` si le social login est opérationnel (activé + boot OK).
- `listProviders(): string[]` — Noms des fournisseurs OPÉRATIONNELS — configurés ET connus du registre.
- `listDisplayProviders(): IOAuthDisplayProvider[]` — Fournisseurs à MONTRER sur l'écran de connexion, libellés compris.
- `getRedirects(provider?: string): { success: string; failure: string; }` — Redirections post-login (succès / échec) — lues par le controller.
- `createAuthorization(provider: string, options?: { theme?: "light" | "dark"; }): Promise<IOAuthAuthorization>` — Étape 1 — prépare l'URL d'autorisation + les éléments anti-replay à stocker en session (`state`, et `code_verifier` si PKCE).
- `exchangeAndProvision(provider: string, code: string, codeVerifier: string | null, returnedIss: string | null): Promise<{ identifier: string; logoutHint: IFederatedLogoutHint | null; }>` — Étape 2 — valide la réponse, échange le `code`, lit le profil et provisionne l'utilisateur local (Shadow User).
- `rememberLogout(session: IHintSession, hint: IFederatedLogoutHint | null): void` — Retient en session l'indice de déconnexion d'un login fédéré — à appeler APRÈS l'ouverture de la session authentifiée (l'ID de session est régénéré à l'ouverture).
- `logoutUrlFor(session: IHintSession | null): Promise<string | null>` — Adresse de déconnexion chez le fournisseur qui a ouvert la session, ou `null` : session locale, fournisseur sans point de déconnexion, ou fournisseur devenu indisponible.
- `backchannelLogout(provider: string, logoutToken: string): Promise<{ readonly outcome: "unsupported" | "refused"; } | { readonly outcome: "done"; readonly destroyed: number; }>` — Déconnexion demandée PAR le fournisseur sur le canal arrière (OpenID Connect Back-Channel Logout 1.0) : vérifie le jeton, refuse un rejeu, puis détruit les sessions locales qu'il désigne.
- `diagnose(name?: string): Promise<IOAuthDiagnosis[]>` — Diagnostique les fournisseurs CONFIGURÉS sans connexion humaine : découverte et émetteur, URL de retour acceptée, secret accepté (cf `diagnoseOAuthProvider`).

#### `SecurityHeaders`

```ts
class SecurityHeaders
```

En-têtes de sécurité **applicatifs** de Nodefony (couche `@nodefony/security`, complémentaire du socle transport de `@nodefony/http`). Pré-calcule une fois au boot la table d'en-têtes CONSTANTS (CSP statique, Referrer-Policy, isolation cross-origin COOP/COEP/CORP, Origin-Agent-Cluster, Permissions-Policy) → zéro alloc, zéro concat par requête (le firewall la pose telle quelle).

- `constructor(o: ISecurityHeadersOptions)`
- `get headers(): Readonly<Record<string, string>>` — Table d'en-têtes applicatifs CONSTANTS (figée), posée telle quelle par le firewall.
- `get hasNonce(): boolean` — `true` si le CSP est recomposé par requête avec un nonce (→ `cspFor`).
- `cspFor(nonce: string): string` — Recompose le CSP en injectant le `nonce` de la requête aux emplacements `{{nonce}}` : une concaténation s'il n'y en a qu'un, un `join` sinon (segments pré-split au boot).
- `cspForExtra(nonce: string, extra: CspFragment): string` — Recompose le CSP en fusionnant ADDITIVEMENT les directives `extra` d'une route (`@Csp`) dans le CSP de base, PUIS en substituant le `nonce`.

#### `TokenService`

```ts
class TokenService extends Service
```

Orchestrateur des jetons longue durée (P6 J4) — émission/refresh des JWT + **maintenance du store** (le seam `ITokenStore.gc()` n'a pas d'autre appelant).

- `module: Module`
- `constructor(module: Module)`
- `isEnabled(): boolean` — `true` si l'émission JWT (signature + refresh) est opérationnelle.
- `publishedIssuer(): string | null` — Émetteur sous lequel cette application accepte d'être DÉCOUVERTE, ou `null`.
- `getPublicJWKS(): Promise<Jose.JSONWebKeySet>` — Jeu de clés **publiques** de signature, tel qu'il doit être servi.
- `runGc(): Promise<number>` — Une passe de purge du store (`ITokenStore.gc()`) — point d'entrée public d'un ordonnanceur : le `GcScheduler` l'appelle, mais le futur worker cron (`security:token-gc` / k8s CronJob) peut l'appeler à …
- `issueForCredentials(identifier: unknown, password: unknown, requestedScopes?: string[], resource?: unknown, context?: ICredentialTransportContext): Promise<ITokenResponse>` — Émet un couple access/refresh après vérification d'un credential identifiant/mot de passe (grant M2M/CLI).
- `issueTokens(user: IUser, requestedScopes?: string[], resource?: unknown, accessTtlS?: number): Promise<ITokenResponse>`
- `refresh(rawRefresh: unknown, resource?: unknown): Promise<ITokenResponse>` — Rotation d'un refresh token (RFC 9700 §4.14) : valide le refresh présenté, émet un nouveau couple, révoque l'ancien.

#### `TotpService`

```ts
class TotpService extends Service
```

**2FA TOTP** (P6.17, RFC 6238) — service d'orchestration du second facteur.

- `module: Module`
- `constructor(module: Module)`
- `isEnabled(): boolean` — `true` si le 2FA est opérationnel (activé en config, boot OK).
- `beginEnrollment(userId: string, account: string): Promise<ITotpEnrollment>` — Démarre l'enrôlement (secret + QR affichés 1×).
- `confirmEnrollment(userId: string, code: string, context?: unknown): Promise<ITotpActivation>` — Confirme l'enrôlement par un 1ᵉʳ code → active + codes de récupération clairs.
- `verifyLogin(userId: string, code: string): Promise<ITotpLoginResult>` — Vérifie un second facteur au login (code TOTP ou code de récupération).
- `disable(userId: string, context?: unknown): Promise<void>` — Désactive le 2FA d'un utilisateur.
- `status(userId: string): Promise<ITotpStatus>` — État 2FA d'un utilisateur (absent / pending / activé + codes restants).
- `listPage(query: ITotpListQuery): Promise<IPage<ITotpEnrollmentSummary>>` — Page d'enrôlements 2FA — pagination **native au store** (jamais un parcours complet).
- `countEnrollments(query: ITotpListQuery): Promise<number>` — Nombre d'enrôlements correspondant aux filtres — le KPI « couverture 2FA » sans énumérer.
- `isEnabledFor(userId: string): Promise<boolean>` — 2FA activé pour cet utilisateur ?

#### `WebAuthnService`

```ts
class WebAuthnService extends Service
```

**WebAuthn / passkeys** (P6 J9) — orchestrateur des deux cérémonies FIDO2 (WebAuthn L3 §7.1 enregistrement, §7.2 authentification).

- `module: Module`
- `constructor(module: Module)`
- `isEnabled(): boolean` — `true` si les cérémonies sont opérationnelles (passkeys activés, boot OK).
- `generateRegistrationOptions(user: IWebAuthnUser): Promise<PublicKeyCredentialCreationOptionsJSON>` — Prépare les options de `navigator.credentials.create()` — le défi à signer + les contraintes (RP, type d'attestation, sélection d'authenticator).
- `verifyRegistration(response: RegistrationResponseJSON, expectedChallenge: string, userId: string, requestOrigin?: string): Promise<IWebAuthnCredential>` — Vérifie la réponse d'enregistrement (challenge, origine, rpIdHash, flags, format d'attestation) et **persiste** le nouveau credential.
- `generateAuthenticationOptions(userId?: string): Promise<PublicKeyCredentialRequestOptionsJSON>` — Prépare les options de `navigator.credentials.get()`.
- `verifyAuthentication(response: AuthenticationResponseJSON, expectedChallenge: string, requestOrigin?: string): Promise<IWebAuthnAssertionResult>` — Vérifie une assertion (signature sur `authData ‖ SHA-256(clientDataJSON)` avec la clé publique stockée, §7.2) + applique l'état (compteur anti-clone, sauvegarde, usage).
- `listUserCredentials(userId: string): Promise<IWebAuthnCredential[]>` — Liste les credentials d'un utilisateur (UX « mes appareils »).
- `listCredentialsPage(query: IWebAuthnListQuery): Promise<IPage<IWebAuthnCredentialSummary>>` — Page de passkeys pour le data plane admin (vue TRANSVERSE : « quels appareils portent des passkeys sur toute la plateforme »).
- `countCredentials(query: IWebAuthnListQuery): Promise<number>` — Nombre de passkeys correspondant aux filtres, ou `-1` si le backend ne sait pas compter à coût raisonnable (Redis).
- `removeCredential(credentialId: string): Promise<void>` — Révoque un credential (retrait d'un appareil).
- `removeUserCredential(userId: string, credentialId: string): Promise<boolean>` — Supprime un credential **du propriétaire** (self-service, anti-IDOR) : la suppression n'aboutit que si le credential appartient bien à `userId`, sinon `false` — 404 indiscernable côté client (on ne ré …

#### `WebhookService`

```ts
class WebhookService extends Service
```

**Webhooks sortants** (P6.13) — service d'orchestration du registre d'endpoints.

- `module: Module`
- `constructor(module: Module)`
- `isReady(): boolean` — Le service est-il opérationnel (activé + store + clé) ?
- `sortableFields(): readonly string[]` — Champs de tri que le backend **actuellement branché** sait honorer, en vocabulaire public.
- `register(input: IWebhookRegisterInput): Promise<IWebhookSecretReveal>` — Enregistre un endpoint : valide l'URL (anti-SSRF), génère un secret de signature, le chiffre au repos.
- `listPage(query: IWebhookListQuery): Promise<IPage<WebhookEndpointSummary>>` — Page d'endpoints (vue publique, sans secret) — pagination **native au store** : la console n'a jamais tout le registre en RAM.
- `countEndpoints(query: IWebhookListQuery): Promise<number>` — Nombre d'endpoints correspondant aux filtres (`COUNT` natif au store).
- `countWebhookFacets(query?: Partial<IWebhookListQuery>): Promise<IWebhookCounts>` — Les compteurs de tête de la console — posés sur la collection ENTIÈRE, pas sur la page affichée.
- `getEndpoint(id: string): Promise<WebhookEndpointSummary | null>` — Un endpoint par id (vue publique), ou `null`.
- `update(id: string, patch: Pick<WebhookEndpointUpdate, "url" | "events" | "enabled" | "description" | "metadata">): Promise<WebhookEndpointSummary | null>` — Met à jour les champs mutables (url/events/enabled/description/metadata).
- `setEnabled(id: string, enabled: boolean): Promise<WebhookEndpointSummary | null>` — Active/désactive un endpoint (révocation douce = `false`).
- `rotateSecret(id: string): Promise<IWebhookSecretReveal | null>` — Régénère le secret de signature (rotation) et retourne le nouveau en clair.
- `revealSecret(id: string): Promise<string | null>` — Révèle le secret en clair d'un endpoint (réversible — usage admin, à auditer par l'appelant).
- `delete(id: string): Promise<boolean>` — Supprime un endpoint.
- `listDeliveries(id: string): IWebhookDelivery[]` — Historique des dernières livraisons d'un endpoint (plus récentes d'abord) — ce que Nodefony a ENVOYÉ + la réponse observée.
- `getSnapshot(): IWebhookEndpoint[]` — Snapshot mémoire (sync) des endpoints — itération du dispatcher (si >0).
- `endpointCount(): number` — Nombre d'endpoints (0-alloc) — court-circuit hot-path du dispatcher.
- `decryptEndpointSecret(endpoint: IWebhookEndpoint): Buffer` — Déchiffre le secret de signature d'un endpoint (pour signer une livraison).
- `getDeliveryPolicy(): IWebhookDeliveryPolicy` — Politique de livraison (tolérance/retries/timeout…) issue de la config.
- `markDelivery(id: string, result: IDeliveryResult): Promise<void>` — Enregistre le résultat d'une livraison (appelé par le dispatcher) : lastDelivery*, compteur d'échecs consécutifs, et **auto-désactivation** de l'endpoint au-delà du seuil (façon GitHub).

### Interfaces (10)

#### `IKeycloakRealmPlan`

```ts
interface IKeycloakRealmPlan
```

Le realm que la configuration implique, confronté au fichier d'import.

- `readonly file: string` — Fichier d'import visé (chemin natif absolu).
- `readonly current: string | null` — Contenu actuel du fichier, `null` s'il n'existe pas.
- `readonly text: string` — Le realm fusionné, tel qu'il serait écrit.
- `readonly warnings: readonly string[]` — Constats à DIRE (le realm reste écrivable).
- `readonly upToDate: boolean` — `true` si le fichier porte déjà exactement `text`.

#### `IKeycloakRealmRequest`

```ts
interface IKeycloakRealmRequest
```

Ce qu'on demande au realm dérivé.

- `readonly provider?: string` — Nom dans `oauth2.providers` (défaut `keycloak`).
- `readonly file?: string` — Fichier d'import, relatif à la racine de l'application ou absolu.
- `readonly machine?: string` — Client machine dont l'audience suit la config.
- `readonly backchannelOrigin?: string` — Origine par laquelle Keycloak joint l'application (canal arrière).

#### `IOAuthAuthorization`

```ts
interface IOAuthAuthorization
```

Données à porter en session entre `authorize` et `callback` (anti-replay).

- `readonly url: string` — URL d'autorisation vers laquelle rediriger l'utilisateur.
- `readonly state: string` — `state` anti-CSRF à stocker en session (RFC 9700).
- `readonly codeVerifier: string | null` — `code_verifier` PKCE à stocker en session, ou `null` (fournisseur sans PKCE).

#### `ISafeUser`

```ts
interface ISafeUser
```

Projection PUBLIQUE de l'utilisateur — ce qui sort en JSON vers le client. Jamais l'entité brute : le hash (`IPasswordAuthenticatedUser.password`) ne doit traverser ni la sérialisation ni un log.

- `id: string`
- `identifier: string`
- `roles: string[]`

#### `ITokenResponse`

```ts
interface ITokenResponse
```

Réponse d'émission de jetons — nommage RFC 6749 §5.1 (snake_case, JSON). Le JWT part en `Authorization: Bearer`, JAMAIS en cookie ni en URL.

- `access_token: string`
- `refresh_token: string`
- `token_type: "Bearer"`
- `expires_in: number` — Durée de vie de l'access token (s).
- `scope: string` — Scopes accordés (séparés par des espaces).

#### `IWebAuthnAssertionResult`

```ts
interface IWebAuthnAssertionResult
```

Résultat d'une authentification WebAuthn vérifiée.

- `readonly credential: IWebAuthnCredential` — Le credential résolu (état déjà mis à jour : compteur, sauvegarde, usage).
- `readonly userId: string` — Identifiant de l'utilisateur propriétaire du credential.

#### `IWebAuthnUser`

```ts
interface IWebAuthnUser
```

Sujet d'une cérémonie d'enregistrement — l'utilisateur qui crée un passkey.

- `readonly id: string` — Clé de propriétaire = `IUser.identifier` — range les credentials (`findByUser`), cf `IWebAuthnCredentialStore`.
- `readonly handle?: string` — Source du `userHandle` WebAuthn : l'`IUser.id` (UUID) du compte.
- `readonly name: string` — Nom de compte affiché par l'OS (email, identifiant…).
- `readonly displayName?: string` — Nom complet optionnel (UX de l'invite système).

#### `IWebhookDeliveryPolicy`

```ts
interface IWebhookDeliveryPolicy
```

Politique de livraison lue par le dispatcher (Slice B).

- `readonly timestampToleranceS: number`
- `readonly maxRetries: number`
- `readonly autoDisableThreshold: number`
- `readonly deliveryTimeoutMs: number`
- `readonly maxConcurrent: number`
- `readonly maxQueue: number`
- `readonly allowHttp: boolean`
- `readonly denyPrivateIps: boolean`

#### `IWebhookRegisterInput`

```ts
interface IWebhookRegisterInput
```

Entrée de création d'un endpoint (les champs système sont dérivés).

- `readonly url: string` — URL de destination (validée anti-SSRF).
- `readonly events: readonly string[]` — Actions d'audit souscrites (`"*"` = toutes).
- `readonly description?: string | null` — Libellé humain optionnel.
- `readonly enabled?: boolean` — Actif dès la création ?
- `readonly createdBy?: string | null` — Identité de l'admin créateur (traçabilité).
- `readonly tenantId?: string | null` — Slot multi-tenant (réservé).
- `readonly metadata?: Record<string, unknown>` — Métadonnées extensibles.

#### `IWebhookSecretReveal`

```ts
interface IWebhookSecretReveal
```

Résultat de création/rotation : le secret en clair n'est exposé qu'ici, **une fois**.

- `readonly endpoint: WebhookEndpointSummary` — Endpoint (sans secret chiffré).
- `readonly secret: string` — Secret de signature en clair (`whsec_…`) — à communiquer au consommateur.

### Types (1)

#### `ILoginOutcome`

```ts
type ILoginOutcome = { status: "authenticated"; user: ISafeUser; } | { status: "mfa_required"; methods: readonly string[]; }
```

Issue d'un `login` : soit l'identité est établie (session ouverte), soit un **second facteur** est requis (2FA) — le mot de passe seul n'a PAS authentifié.

---

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