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


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

> Générée depuis les déclarations de types publiées de `@nodefony/user` **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/user`

`import { … } from "@nodefony/user"` — 73 symboles.

### Classes (12)

#### `AnonymousUser`

```ts
class AnonymousUser implements IUser
```

Utilisateur **non authentifié** — implémente `IUser` sans credential.

- `readonly id = "anonymous"` — Identifiant interne — UUID (jamais `string | number`).
- `readonly identifier = "anon."` — Identifiant fonctionnel d'authentification (email, login...).
- `readonly roles: string[]` — Rôles **plats** accordés (sans hiérarchie résolue).
- `hasRole(role: string): boolean` — Indique si l'utilisateur possède le rôle exact donné (sans hiérarchie).
- `isActive(): boolean` — Un anonyme est utilisable (non désactivé).
- `isLocked(): boolean` — Un anonyme n'est jamais verrouillé.

#### `Argon2idEncoder`

```ts
class Argon2idEncoder implements IPasswordEncoder
```

Encodeur de mot de passe **Argon2id** (RFC 9106) — recommandation NIST/OWASP 2026.

- `readonly memoryKiB: number` — Mémoire par hash (KiB) utilisée pour produire les nouveaux hashs.
- `readonly timeCost: number` — Passes sur la mémoire utilisées pour produire les nouveaux hashs.
- `readonly parallelism: number` — Lanes parallèles utilisées pour produire les nouveaux hashs.
- `constructor(options?: Argon2idOptions)`
- `supports(hash: string): boolean` — Reconnaît un hash argon2 (tous variants `$argon2d|i|id$`) — parsing pur, sync.
- `hash(plain: string): Promise<string>` — Hache un mot de passe en clair (sel généré, paramètres inclus dans la sortie PHC).
- `verify(plain: string, hash: string): Promise<boolean>` — Vérifie un mot de passe en clair contre un hash stocké (temps constant interne).
- `needsRehash(hash: string): boolean` — Indique si un hash doit être recalculé : format non argon2, variant non `id`, version antérieure à 0x13, ou coûts stockés INFÉRIEURS aux coûts courants (politique affaiblie).

#### `BaseUser`

```ts
class BaseUser implements IPasswordAuthenticatedUser
```

Implémentation POJO de référence d'un utilisateur — base partagée par tous les ORM.

- `readonly id: string` — Identifiant interne — UUID (jamais `string | number`).
- `readonly identifier: string` — Identifiant fonctionnel d'authentification (email, login...).
- `roles: string[]` — Rôles **plats** accordés (sans hiérarchie résolue).
- `password: string | null` — Hash du mot de passe stocké, ou `null` pour un compte sans mot de passe local.
- `currentRole: string | null` — Profil de rôle actif en session (P5.11) — distinct des rôles plats.
- `socialProviders: ISocialProvider[]`
- `metadata: Record<string, unknown>`
- `credentialsVersion: number | null` — Version des identifiants — cf `IUser.credentialsVersion`.
- `protected enabled: boolean`
- `protected locked: boolean`
- `constructor(options: IBaseUserOptions)`
- `hasRole(role: string): boolean` — Indique si l'utilisateur possède le rôle exact donné (sans hiérarchie).
- `isActive(): boolean` — Indique si le compte est actif (activé et non expiré).
- `isLocked(): boolean` — Indique si le compte est verrouillé (ex.
- `toJSON(): Omit<IBaseUserOptions, "password" | "credentialsVersion">` — Forme sérialisée de l'utilisateur, SANS le hash du mot de passe ni la version des identifiants (état interne de révocation, utile à personne hors du pare-feu).
- `addRole(role: string): this` — Ajoute un rôle s'il n'est pas déjà présent (idempotent).
- `removeRole(role: string): this` — Retire un rôle s'il est présent (idempotent).
- `addSocialProvider(link: ISocialProvider): this` — Lie un compte externe (OAuth/OIDC) — pattern Shadow User.
- `enable(): this` — Active le compte.
- `disable(): this` — Désactive le compte.
- `lock(): this` — Verrouille le compte.
- `unlock(): this` — Déverrouille le compte.
- `setCurrentRole(role: string | null): this` — Définit le profil de rôle actif (session).
- `setPassword(hash: string | null): this` — Remplace le hash de mot de passe stocké.

#### `BcryptEncoder`

```ts
class BcryptEncoder implements IPasswordEncoder
```

Encodeur de mot de passe **bcrypt** — implémentation de référence d'`IPasswordEncoder`.

- `readonly rounds: number` — Coût bcrypt utilisé pour produire les nouveaux hashs.
- `constructor(rounds?: number)`
- `supports(hash: string): boolean` — Reconnaît un hash bcrypt (`$2a$`/`$2b$`/`$2y$` + coût) — parsing pur, sync.
- `hash(plain: string): Promise<string>` — Hache un mot de passe en clair (sel généré et inclus dans la sortie).
- `verify(plain: string, hash: string): Promise<boolean>` — Vérifie un mot de passe en clair contre un hash stocké (temps constant interne).
- `needsRehash(hash: string): boolean` — Indique si un hash doit être recalculé (coût stocké inférieur au coût courant, ou format non bcrypt).

#### `IdentifierImmutableError`

```ts
class IdentifierImmutableError extends nodefonyError
```

Une mise à jour tente de RENOMMER un compte — l'identifiant est immuable.

- `constructor(current: string)`

#### `IdentifierTakenError`

```ts
class IdentifierTakenError extends nodefonyError
```

Un compte local porte déjà cet identifiant — l'identifiant est UNIQUE dans l'annuaire, quel que soit le dépôt (index unique en SQL et en document, refus explicite en mémoire).

- `constructor(detail: string)`

#### `InMemoryUserRepository`

```ts
class InMemoryUserRepository implements IUserRepository
```

Annuaire d'utilisateurs **en mémoire** — implémentation de référence du contrat `IUserRepository` sur une `Map` (aucun ORM).

- `readonly sortableFields: readonly [ "identifier", "enabled", "id" ]` — Capacité RÉELLE de cet annuaire : `BaseUser` ne porte ni `createdAt` ni `updatedAt`, donc ils ne sont pas annoncés.
- `constructor(seed?: IBaseUserOptions[])`
- `find(criteria?: Criteria<IPasswordAuthenticatedUser>): Promise<IPasswordAuthenticatedUser[]>` — Retourne toutes les entités correspondant au critère (toutes si omis).
- `findOne(criteria: Criteria<IPasswordAuthenticatedUser>): Promise<IPasswordAuthenticatedUser | null>` — Retourne la première entité correspondant au critère, ou `null`.
- `create(data: Partial<IPasswordAuthenticatedUser>): Promise<IPasswordAuthenticatedUser>` — Persiste une nouvelle entité et retourne sa version persistée (id généré, valeurs par défaut).
- `updateOne(criteria: Criteria<IPasswordAuthenticatedUser>, data: Partial<IPasswordAuthenticatedUser>): Promise<IPasswordAuthenticatedUser | null>` — Met à jour **au plus une** entité correspondant au critère, de façon **atomique**, et retourne sa version persistée (ou `null` si aucune ne correspond).
- `upsert(criteria: Criteria<IPasswordAuthenticatedUser>, update: Partial<IPasswordAuthenticatedUser>, insertOnly?: Partial<IPasswordAuthenticatedUser>): Promise<IPasswordAuthenticatedUser>` — Insère **ou** met à jour atomiquement l'entité identifiée par `criteria` (clé unique), en **une seule** requête (`INSERT … ON CONFLICT DO UPDATE … RETURNING` SQL / `findOneAndUpdate({ upsert })` Mongo …
- `createMany(data: Partial<IPasswordAuthenticatedUser>[]): Promise<IPasswordAuthenticatedUser[]>` — Insère **plusieurs** entités en **une seule** requête (`INSERT … VALUES (…),(…)` SQL / `insertMany` Mongo) et retourne leurs versions persistées (ids générés, défauts appliqués), dans l'ordre.
- `exists(criteria: Criteria<IPasswordAuthenticatedUser>): Promise<boolean>` — Indique si **au moins une** entité correspond au critère, sans rapatrier la ligne (`SELECT 1 … LIMIT 1` SQL / `exists` Mongo).
- `deleteOne(criteria: Criteria<IPasswordAuthenticatedUser>): Promise<boolean>` — Supprime **au plus une** entité de façon **atomique** (symétrique d'`IRepository.updateOne` ; `DELETE … LIMIT 1` SQL / `deleteOne` Mongo).
- `findOneAndDelete(criteria: Criteria<IPasswordAuthenticatedUser>): Promise<IPasswordAuthenticatedUser | null>` — Supprime **au plus une** entité et **retourne** sa valeur supprimée (ou `null`), de façon atomique (`DELETE … RETURNING` SQL / `findOneAndDelete` Mongo) — claim-and-remove (file de jobs, outbox, pop a …
- `increment(criteria: Criteria<IPasswordAuthenticatedUser>, changes: Partial<Record<keyof IPasswordAuthenticatedUser, number>>): Promise<IPasswordAuthenticatedUser | null>` — Incrémente **atomiquement** des champs numériques d'**au plus une** entité (`SET f = f + ?` SQL / `$inc` Mongo), sans read-modify-write (donc sans race) — pour les compteurs (stats, usage/tokens, rate …
- `updateMany(criteria: Criteria<IPasswordAuthenticatedUser>, data: Partial<IPasswordAuthenticatedUser>): Promise<number>` — Met à jour **toutes** les entités correspondant au critère et retourne le **nombre** de lignes modifiées (parité de signature avec `IRepository.delete`).
- `delete(criteria: Criteria<IPasswordAuthenticatedUser>): Promise<number>` — Supprime les entités correspondant au critère.
- `count(criteria?: Criteria<IPasswordAuthenticatedUser>): Promise<number>` — Compte les entités correspondant au critère (toutes si omis).
- `countDistinct(field: keyof IPasswordAuthenticatedUser, criteria?: Criteria<IPasswordAuthenticatedUser>): Promise<number>` — Déduplication en mémoire — l'annuaire est déjà entièrement chargé, il n'y a donc pas de parcours à éviter comme en SQL.
- `withTransaction(_tx: ITransaction): IUserRepository` — In-memory : pas de transaction — le repository est sa propre unité.
- `findByIdentifier(identifier: string): Promise<IPasswordAuthenticatedUser | null>` — Retrouve un utilisateur par son identifiant fonctionnel (email, login...).
- `findBySocialProvider(provider: string, providerId: string): Promise<IPasswordAuthenticatedUser | null>` — Retrouve un utilisateur lié à un compte d'un fournisseur OAuth/OIDC.
- `listPage(query: IUserListQuery): Promise<IPage<IPasswordAuthenticatedUser>>` — {@inheritDoc IUserRepository.listPage}
- `countUsers(query: IUserListQuery): Promise<number>` — {@inheritDoc IUserRepository.countUsers}
- `countActiveAdmins(adminRole: string): Promise<number>` — Compte les administrateurs **actifs** (`isActive()` **et** porteurs de `adminRole`) — garde-fou anti-lockout, calculé **au store** (SQL `COUNT` avec containment de rôle), jamais en chargeant tous les …

#### `MigratingEncoder`

```ts
class MigratingEncoder implements IPasswordEncoder
```

Encodeur composite de **migration d'algorithme** — accepte les hashs legacy à la vérification, ne produit que des hashs au format courant.

- `readonly primary: IPasswordEncoder` — Encodeur cible — produit tous les nouveaux hashs.
- `readonly legacy: readonly IPasswordEncoder[]` — Encodeurs acceptés en lecture seule pendant la migration.
- `constructor(primary: IPasswordEncoder, legacy: readonly IPasswordEncoder[])`
- `supports(hash: string): boolean` — Reconnaît un hash si l'UN des encodeurs (principal ou legacy) le reconnaît.
- `hash(plain: string): Promise<string>` — Hache avec l'encodeur PRINCIPAL uniquement (jamais un format legacy).
- `verify(plain: string, hash: string): Promise<boolean>` — Vérifie en routant vers l'encodeur dont le format correspond au hash stocké.
- `needsRehash(hash: string): boolean` — Recommande un re-hash si le hash n'est pas au format principal (migration), ou si le principal lui-même le juge obsolète (coûts augmentés).

#### `PasswordPolicy`

```ts
class PasswordPolicy implements IPasswordBlocklist
```

Politique par défaut : six règles, de la moins chère à la plus chère.

- `readonly options: Required<IPasswordPolicyOptions>`
- `constructor(options?: IPasswordPolicyOptions)`
- `violation(plain: string, subject?: IPasswordSubjectHint): Promise<string | null>` — La règle enfreinte, ou `null` si le mot de passe est accepté.
- `isBlocked(plain: string, subject?: IPasswordSubjectHint): Promise<boolean>` — Le mot de passe doit-il être refusé ?

#### `UserNotFoundError`

```ts
class UserNotFoundError extends nodefonyError
```

Utilisateur introuvable dans la source d'identité — levée par les méthodes `IUserProvider` (contrat : jamais `null`, l'absence d'identité est un échec explicite).

- `constructor(detail: string)`

#### `UserService`

```ts
class UserService extends AbstractCrudService<IPasswordAuthenticatedUser, IUserRepository> implements IUserProvider, IPasswordVerifier, IOAuthUserProvisioner
```

- `protected readonly encoder: IPasswordEncoder`
- `passwordBlocklist: IPasswordBlocklist | null` — Politique de mot de passe (NIST SP 800-63B §5.1.1.2) — consultée à la création et au changement, jamais au login.
- `constructor(repository: IUserRepository, encoder: IPasswordEncoder, ...wiring: ServiceWiring)`
- `create(data: PartialInput<IPasswordAuthenticatedUser>): Promise<IPasswordAuthenticatedUser>` — Crée un compte (CRUD hérité), puis émet `USER_CREATED_EVENT` et en ATTEND les abonnés.
- `updateOne(criteria: Criteria<IPasswordAuthenticatedUser>, data: PartialInput<IPasswordAuthenticatedUser>): Promise<IPasswordAuthenticatedUser | null>` — Met à jour un compte (CRUD hérité).
- `protected beforeUpdate(criteria: Criteria<IPasswordAuthenticatedUser>, data: PartialInput<IPasswordAuthenticatedUser>): Promise<PartialInput<IPasswordAuthenticatedUser>>` — Refuse de RENOMMER un compte : sessions, jetons et facteurs sont rangés sous `identifier`, le changer les orphelinerait.
- `delete(criteria: Criteria<IPasswordAuthenticatedUser>): Promise<number>` — Supprime des comptes (CRUD hérité), un par un, et émet `USER_REVOKED_EVENT` (`deleted`) pour CHAQUE compte effectivement supprimé, en attendant la cascade : sessions, jetons et facteurs (TOTP, passkey …
- `createUser(input: ICreateUserInput): Promise<IPasswordAuthenticatedUser>` — Crée un utilisateur — hache le mot de passe en clair s'il est fourni, puis délègue au `create` générique (hooks + event `onCreated`).
- `findByIdentifier(identifier: string): Promise<IPasswordAuthenticatedUser | null>` — Charge un utilisateur par son identifiant fonctionnel (email, login...).
- `listPage(query: IUserListQuery): Promise<IPage<IPasswordAuthenticatedUser>>` — Liste **paginée nativement** d'utilisateurs (filtres role/enabled/q) — délègue au repository, qui ne matérialise jamais plus d'une page.
- `sortableFields(): readonly string[]` — Champs de tri que le repository **actuellement branché** sait honorer.
- `countActiveAdmins(adminRole: string): Promise<number>` — Compte les administrateurs actifs porteurs de `adminRole` — garde-fou anti-lockout calculé au store (jamais en chargeant tous les utilisateurs).
- `countUserFacets(adminRole: string, query?: Partial<IUserListQuery>): Promise<IUserCounts>` — Les compteurs de tête de la console — posés sur l'annuaire ENTIER, pas sur la page affichée.
- `changePassword(id: string, plainPassword: string): Promise<IPasswordAuthenticatedUser | null>` — Change le mot de passe d'un utilisateur — hache le clair avant persistance.
- `authenticate(identifier: string, plain: string): Promise<IPasswordAuthenticatedUser | null>` — Authentifie par identifiant + mot de passe.
- `loadUserByIdentifier(identifier: string): Promise<IUser>` — {@inheritDoc IUserProvider.loadUserByIdentifier}
- `loadUserByOAuth(provider: string, providerId: string): Promise<IUser>` — {@inheritDoc IUserProvider.loadUserByOAuth}
- `refreshUser(user: IUser): Promise<IUser>` — {@inheritDoc IUserProvider.refreshUser}
- `provisionOAuthUser(profile: IOAuthProfile, policy: IOAuthProvisionPolicy): Promise<IUser>` — {@inheritDoc IOAuthUserProvisioner.provisionOAuthUser}
- `syncOAuthRoles(provider: string, providerId: string, roles: readonly string[]): Promise<IUser>` — {@inheritDoc IOAuthUserProvisioner.syncOAuthRoles}

#### `WeakPasswordError`

```ts
class WeakPasswordError extends nodefonyError
```

Mot de passe refusé par la politique (connu-compromis / interdit) — `code = 400`.

- `readonly violation: string | null` — La règle enfreinte, telle que la politique l'a nommée (`null` si muette).
- `constructor(violation?: string | null)`

### Fonctions (20)

#### `assertUserContract`

```ts
function assertUserContract(present: Iterable<string>, origin: string, expected?: readonly IUserColumn[]): void
```

Refuse une entité utilisateur incomplète, en nommant chaque colonne absente ET ce qui la lit.

#### `attachExtraColumns`

```ts
function attachExtraColumns<T extends object>(user: T, row: Readonly<Record<string, unknown>>, skip?: ReadonlySet<string>): T
```

Reporte sur un utilisateur reconstruit toutes les colonnes que `BaseUser` ne porte pas — horodatages de la ligne, et **champs métier ajoutés par l'application**.

#### `authenticatedUser`

```ts
function authenticatedUser(): IUser | null
```

L'utilisateur AUTHENTIFIÉ de la requête courante, typé `IUser` — ou `null` (hors zone, anonyme, ou principal qui n'est pas un `IUser`).

#### `createUserAdminApi`

```ts
function createUserAdminApi(container: Container): IAdminApi
```

Producteur `IAdminApi` du domaine **utilisateur** — exposé sous `/nodefony/user/api/users`. Défini DANS `@nodefony/user` (propriétaire du `UserService`/`IUser`) mais **enregistré par un module bootable** (`@nodefony/security`, via `registerUserAdminApi`) car `@nodefony/user` est une lib pure non-bootable — exactement le cas prévu par le core : un module qui ne dépend que de `nodefony` produit sa donnée d'admin.

#### `describeSeedFailure`

```ts
function describeSeedFailure(cause: unknown, context: ISeedFailureContext): string
```

Rédige le message d'un semis raté : QUEL compte, QUELLE règle, QUEL geste.

#### `encoderFromConfig`

```ts
function encoderFromConfig(specs: readonly IEncoderSpec[]): IPasswordEncoder
```

Traduit une liste ORDONNÉE de specs d'encodeurs en encodeur exécutable — le pont entre la section `encoders` de la config sécurité et le `UserService`.

#### `listUserStores`

```ts
function listUserStores(): string[]
```

Liste des backends utilisateur disponibles — alimente le champ `available` du statut user (écran Studio « Stores »). `"memory"` est mis EN TÊTE (baseline builtin, toujours disponible = le repli qui marche partout), les adapters ORM suivent triés. L'ordre est celui affiché dans la colonne « Backends dispo ».

#### `mergeProfileIntoMetadata`

```ts
function mergeProfileIntoMetadata(metadata: unknown, patch: Partial<Record<ProfileField, string>>): Record<string, unknown>
```

Fusionne un patch validé dans la `metadata` existante en **préservant les autres clés**. Les champs de profil vidés (`""`) sont RETIRÉS (pas de clé fantôme). Rend la nouvelle `metadata` complète, prête pour `updateOne({ metadata })`.

#### `missingUserColumns`

```ts
function missingUserColumns(present: Iterable<string>, expected?: readonly IUserColumn[]): readonly IUserColumn[]
```

Les colonnes du contrat qu'une définition d'entité ne rend PAS.

#### `profileFromClaims`

```ts
function profileFromClaims(claims: Record<string, unknown>): Partial<Record<ProfileField, string>>
```

Pré-remplit un profil depuis des **claims OIDC/OAuth** (provisioning JIT d'un Shadow User social). Mappe les claims standard (`given_name`/`family_name`/ `name`/`email`/`picture`/`locale`, + `avatar_url` GitHub) vers `IUserProfile`, **best-effort par champ** : chaque valeur est validée isolément (bornes/format) et un claim invalide est ignoré sans bloquer les autres ni le login. Les claims viennent d'un tiers → lecture défensive.

#### `projectProfile`

```ts
function projectProfile(metadata: unknown): IUserProfile
```

Projette la `metadata` brute d'une entité vers un `IUserProfile` — lecture par **allowlist** (seules les clés connues, typées string non vide). Garantit qu'aucune autre clé de `metadata` (applicative/sensible) n'entre dans le DTO.

#### `projectProviderRoles`

```ts
function projectProviderRoles(metadata: unknown): Record<string, string[]>
```

Rôles gérés par CHAQUE fournisseur, lus dans `metadata` — pour l'affichage.

#### `readProviderRoles`

```ts
function readProviderRoles(metadata: unknown, provider: string): string[]
```

Rôles que `provider` a accordés au dernier calcul, lus dans `metadata`.

#### `reconcileProviderRoles`

```ts
function reconcileProviderRoles(current: readonly string[], previous: readonly string[], next: readonly string[]): IProviderRolesReconciliation
```

Recalcule l'ensemble effectif : rôles actuels − ceux que le fournisseur gérait, ∪ ceux qu'il accorde maintenant.

#### `registerUserAdminApi`

```ts
function registerUserAdminApi(registry: IAdminRegistry, container: Container): void
```

Enregistre le producteur admin utilisateur sur le broker — **idempotent**. À appeler au `onKernelBoot` d'un module **bootable** qui dépend de `@nodefony/user` (typiquement `@nodefony/security`), `@nodefony/user` n'étant pas lui-même un module.

#### `registerUserStore`

```ts
function registerUserStore(name: string): void
```

Déclare un backend de persistance utilisateur disponible (idempotent).

#### `requestUser`

```ts
function requestUser(identifier: string): IUser | null
```

L'utilisateur DÉJÀ chargé pour la requête courante, s'il est bien celui qu'on cherche — sinon `null`, et l'appelant relit auprès du fournisseur.

#### `toUserSummary`

```ts
function toUserSummary(user: IUser): IUserSummary
```

Projette un `IUser` en `IUserSummary` redacté. Fonction **pure** (cœur de la garantie anti-fuite, testée isolément) : `currentRole`/ `socialProviders`/timestamps sont lus **défensivement** (présents sur l'entité ORM, absents du contrat strict `IUser`) — `password` jamais lu ; de `metadata`, seules `profile` (allowlist) et `providerRoles` (des noms de rôles) passent.

#### `truncatedPasswordHash`

```ts
function truncatedPasswordHash(plain: string): number
```

Les 4 premiers octets du SHA-1, en entier non signé.

#### `validateProfilePatch`

```ts
function validateProfilePatch(input: unknown): { ok: true; value: Partial<Record<ProfileField, string>>; } | { ok: false; error: string; }
```

Valide + normalise un patch de profil reçu d'un client. Allowlist stricte : seules les clés `PROFILE_FIELDS` sont lues (anti-injection d'une clé `metadata` arbitraire). Chaque valeur est `trim`ée ; une chaîne vide ou `null` = **effacement** du champ (matérialisé `""`, retiré au merge).

### Constantes (12)

#### `DEFAULT_PASSWORD_POLICY`

```ts
const DEFAULT_PASSWORD_POLICY: Required<IPasswordPolicyOptions>
```

Défauts de la politique — source unique, relue par les tests.

#### `PROVIDER_ROLES_KEY`

```ts
const PROVIDER_ROLES_KEY = "providerRoles"
```

Clé de `metadata` : `{ [fournisseur]: rôles accordés au dernier calcul }`.

#### `ROLE_ANONYMOUS`

```ts
const ROLE_ANONYMOUS = "ROLE_ANONYMOUS"
```

Rôle unique d'un utilisateur non authentifié.

#### `USER_COLUMNS`

```ts
const USER_COLUMNS: readonly IUserColumn[]
```

#### `USER_CREATED_EVENT`

```ts
const USER_CREATED_EVENT = "onUserCreated"
```

Événement kernel — un compte vient d'être créé (charge utile `IUserCreatedEvent`). Émis par `UserService.create` et **attendu** : `@nodefony/security` y retire les facteurs (TOTP, passkeys) laissés sous le même identifiant par un ancien titulaire, et une connexion immédiate ne doit pas les trouver encore là.

#### `USER_DEFAULT_ORDER`

```ts
const USER_DEFAULT_ORDER: NonNullable<IPageQuery["order"]>
```

Ordre appliqué quand le client n'en demande aucun : par identifiant croissant — le seul champ toujours présent et unique, donc le seul qui rende une pagination offset déterministe sans départage supplémentaire.

#### `USER_REVOKED_EVENT`

```ts
const USER_REVOKED_EVENT = "onUserRevoked"
```

Événement kernel — l'accès d'un compte doit être révoqué partout (suppression, désactivation, verrouillage, changement de mot de passe). **Point d'extension** : un module qui possède des artefacts liés à un compte (sessions, jetons, webhooks…) s'y abonne et nettoie LES SIENS — zéro couplage avec `@nodefony/user`. Émis par `UserService` seul, et attendu.

#### `USER_SORTABLE_FIELDS`

```ts
const USER_SORTABLE_FIELDS: readonly [ "identifier", "enabled", "createdAt", "updatedAt", "id" ]
```

**Le vocabulaire de tri des utilisateurs** — source unique, en noms publics.

#### `USER_SORTABLE_FIELDS_COMMON`

```ts
const USER_SORTABLE_FIELDS_COMMON: readonly [ "identifier", "enabled", "id" ]
```

Socle garanti par **tous** les backends d'utilisateurs. C'est ce sur quoi une interface peut compter sans savoir quelle base est branchée.

#### `USER_SORTABLE_FIELDS_IN_MEMORY`

```ts
const USER_SORTABLE_FIELDS_IN_MEMORY: readonly [ "identifier", "enabled", "id" ]
```

Sous-ensemble réellement triable par l'annuaire **en mémoire**.

#### `USER_TABLE_NAME`

```ts
const USER_TABLE_NAME = "User"
```

Le nom de la TABLE (ou collection) qui porte les utilisateurs.

#### `anonymousUser`

```ts
const anonymousUser: AnonymousUser
```

Singleton d'`AnonymousUser` — instance partagée et gelée à réutiliser à chaque requête non authentifiée (zéro allocation dans le hot path).

### Interfaces (26)

#### `Argon2idOptions`

```ts
interface Argon2idOptions
```

Paramètres de coût Argon2id (RFC 9106).

- `memoryKiB?: number` — Mémoire par hash en KiB (défaut 19456 = 19 MiB, minimum OWASP).
- `timeCost?: number` — Nombre de passes sur la mémoire (défaut 3 — voir DEFAULT_TIME_COST).
- `parallelism?: number` — Nombre de threads/lanes (défaut 1 — chaque lane alloue `memoryKiB`).

#### `IBaseUserOptions`

```ts
interface IBaseUserOptions
```

Options de construction d'un `BaseUser` — signature en objet (lisibilité + extensibilité).

- `id: string` — Identifiant interne (UUID).
- `identifier: string` — Identifiant fonctionnel (email, login...).
- `roles?: string[]` — Rôles plats accordés (copiés défensivement).
- `password?: string | null` — Hash du mot de passe local, ou `null` (compte OAuth-only).
- `enabled?: boolean` — Compte activé.
- `locked?: boolean` — Compte verrouillé.
- `currentRole?: string | null` — Profil de rôle actif en session.
- `socialProviders?: ISocialProvider[]` — Comptes externes liés (OAuth/OIDC).
- `metadata?: Record<string, unknown>` — Métadonnées applicatives libres.
- `credentialsVersion?: number | null` — Version des identifiants (cf `IUser.credentialsVersion`).

#### `ICreateUserInput`

```ts
interface ICreateUserInput
```

Données d'entrée de création d'un utilisateur — le mot de passe est fourni en **clair** puis haché par `UserService.createUser` (jamais persisté tel quel).

- `identifier: string` — Identifiant fonctionnel (email, login...).
- `plainPassword?: string | null` — Mot de passe en clair, ou `null`/absent pour un compte sans credential local.
- `roles?: string[]` — Rôles plats initiaux.

#### `IEncoderSpec`

```ts
interface IEncoderSpec
```

Spécification déclarative d'UN encodeur de mot de passe — miroir structurel de la section `encoders` du schéma Zod de `@nodefony/security` (qui valide bornes et défauts), SANS en dépendre : ce module reste la couche basse, l'inversion de dépendance est préservée (security consomme user, jamais l'inverse).

- `type: "argon2id" | "bcrypt"` — Algorithme : `argon2id` (RFC 9106, défaut) ou `bcrypt` (legacy).
- `memoryKiB?: number` — Argon2id : mémoire par hash (KiB).
- `timeCost?: number` — Argon2id : passes d'itération.
- `parallelism?: number` — Argon2id : lanes parallèles.
- `rounds?: number` — bcrypt : coût (ignoré par argon2id).

#### `IOAuthProfile`

```ts
interface IOAuthProfile
```

Profil d'identité **normalisé** extrait d'un fournisseur OAuth/OIDC.

- `readonly provider: string` — Fournisseur (`"google"`, `"github"`...).
- `readonly providerId: string` — Identifiant **stable** du compte chez le fournisseur (`sub` OIDC, `id` GitHub).
- `readonly email: string | null` — Email retourné par le fournisseur, ou `null` (compte sans email exposé).
- `readonly emailVerified: boolean` — `true` si le fournisseur **certifie** l'email vérifié.
- `readonly name: string | null` — Nom d'affichage, ou `null`.
- `readonly raw: Record<string, unknown>` — Charge utile brute du fournisseur (claims / payload) — pour un provisioner custom.

#### `IOAuthProvisionPolicy`

```ts
interface IOAuthProvisionPolicy
```

Politique de provisioning décidée par l'appelant (config `oauth2` de `@nodefony/security`) et transmise au provisioner — celui-ci ne lit aucune config, il applique ce qu'on lui passe (un provisioner applicatif peut ignorer ces valeurs et appliquer sa propre logique).

- `readonly defaultRoles: string[]` — Rôles plats accordés au Shadow User **à la création uniquement**.
- `readonly allowSignup: boolean` — `true` : créer une ligne locale au premier login externe (JIT).
- `readonly providerRoles?: readonly string[]` — Rôles que le fournisseur accorde MAINTENANT, déjà traduits en rôles de l'application (`roleMapping` de `@nodefony/security`).

#### `IOAuthUserProvisioner`

```ts
interface IOAuthUserProvisioner
```

Capability de **provisioning d'un utilisateur OAuth** — pattern *Shadow User* Just-In-Time.

- `provisionOAuthUser(profile: IOAuthProfile, policy: IOAuthProvisionPolicy): Promise<IUser>` — Retourne l'utilisateur lié au compte externe, en le **créant** si absent (selon `policy.allowSignup`).
- `syncOAuthRoles?(provider: string, providerId: string, roles: readonly string[]): Promise<IUser>` — Recalcule les rôles gérés par un fournisseur pour le compte qui lui est lié — appelé à chaque jeton d'API, sans passer par une connexion.

#### `IPasswordAuthenticatedUser`

```ts
interface IPasswordAuthenticatedUser extends IUser
```

Utilisateur **porteur d'un credential mot de passe local** — extension de `IUser`.

- `readonly password: string | null` — Hash du mot de passe stocké, ou `null` pour un compte sans mot de passe local.

#### `IPasswordBlocklist`

```ts
interface IPasswordBlocklist
```

Contrat de **liste de blocage de mots de passe compromis** (NIST SP 800-63B §5.1.1.2) — consulté à la CRÉATION et au CHANGEMENT de mot de passe, jamais au login (le hash stocké ne permet plus de juger le clair, et refuser un login existant verrouillerait l'utilisateur).

- `isBlocked(plain: string, subject?: IPasswordSubjectHint): Promise<boolean>` — Le mot de passe en clair est-il connu-compromis / interdit ?
- `violation?(plain: string, subject?: IPasswordSubjectHint): Promise<string | null>` — La règle enfreinte, en français, ou `null` si le mot de passe est accepté.

#### `IPasswordEncoder`

```ts
interface IPasswordEncoder
```

Contrat d'un encodeur de mot de passe — abstraction de l'algorithme de hachage.

- `supports(hash: string): boolean` — Indique si un hash stocké est au format de CET encodeur (parsing pur, sync).
- `hash(plain: string): Promise<string>` — Hache un mot de passe en clair (sel inclus dans la sortie).
- `verify(plain: string, hash: string): Promise<boolean>` — Vérifie qu'un mot de passe en clair correspond à un hash stocké.
- `needsRehash(hash: string): boolean` — Indique si un hash devrait être recalculé (paramètres de coût obsolètes).

#### `IPasswordPolicyOptions`

```ts
interface IPasswordPolicyOptions
```

Réglages d'une politique — tout est optionnel, les défauts sont sains.

- `minLength?: number` — Longueur minimale acceptée.
- `blocklist?: readonly string[]` — Mots de passe refusés en propre (noms métier, du produit, du client).
- `blocklistFile?: string | null` — Fichier de mots de passe refusés, une valeur par ligne (UTF-8).
- `checkCommonPasswords?: boolean` — Consulter les empreintes embarquées.

#### `IPasswordSubjectHint`

```ts
interface IPasswordSubjectHint
```

Ce qu'un appelant peut dire du compte visé — tout est optionnel.

- `identifier?: string` — Identifiant du compte (courriel, login).

#### `IPasswordVerifier`

```ts
interface IPasswordVerifier
```

Contrat de **vérification d'un credential mot de passe** — le guichet auquel `@nodefony/security` présente un couple identifiant/mot de passe et qui répond par un verdict, jamais par un hash.

- `authenticate(identifier: string, plain: string): Promise<IUser | null>` — Vérifie un couple identifiant/mot de passe.

#### `IProviderRolesReconciliation`

```ts
interface IProviderRolesReconciliation
```

Résultat d'un recalcul.

- `readonly roles: string[]` — Ensemble effectif à écrire dans `roles`.
- `readonly changed: boolean` — `true` si `roles` OU la trace des rôles gérés doit être réécrite.

#### `ISeedFailureContext`

```ts
interface ISeedFailureContext
```

Ce que l'appelant sait du semis, et que l'erreur ignore.

- `identifier: string` — Identifiant du compte qu'on tentait de semer (`"admin"`).
- `envVar: string` — Variable d'environnement qui porte le mot de passe (`"NF_ADMIN_PASSWORD"`).
- `fromEnv: boolean` — Le mot de passe venait-il de `envVar` ?
- `admin?: boolean` — Le compte visait-il un rôle d'administration ?

#### `ISocialProvider`

```ts
interface ISocialProvider
```

Référence à un compte d'un fournisseur d'identité externe (OAuth / OIDC).

- `readonly provider: string` — Identifiant du fournisseur (`"google"`, `"github"`, `"microsoft"`...).
- `readonly providerId: string` — Identifiant du compte chez le fournisseur.
- `readonly createdAt: Date` — Date de liaison du compte.

#### `IUser`

```ts
interface IUser
```

Contrat **strict** d'un utilisateur Nodefony — surface minimale garantie au framework.

- `readonly id: string` — Identifiant interne — UUID (jamais `string | number`).
- `readonly identifier: string` — Identifiant fonctionnel d'authentification (email, login...).
- `readonly roles: string[]` — Rôles **plats** accordés (sans hiérarchie résolue).
- `hasRole(role: string): boolean` — Indique si l'utilisateur possède le rôle exact donné (sans hiérarchie).
- `isActive(): boolean` — Indique si le compte est actif (activé et non expiré).
- `isLocked(): boolean` — Indique si le compte est verrouillé (ex.
- `readonly credentialsVersion?: number | null` — Version des identifiants du compte, incrémentée à chaque changement de mot de passe — absente ou `null` vaut 0.

#### `IUserColumn`

```ts
interface IUserColumn
```

Une colonne du contrat utilisateur : son nom, ce qu'elle contient, et **qui la lit**.

- `readonly name: string` — Nom de la colonne, identique sur tous les moteurs (figé en v1).
- `readonly type: UserColumnType` — Ce que la colonne contient, indépendamment du moteur.
- `readonly nullable: boolean` — `true` si la colonne accepte l'absence de valeur.
- `readonly unique?: boolean` — `true` si la valeur doit être unique dans l'annuaire (implique un index).
- `readonly origin: UserColumnOrigin` — Qui fournit la valeur — cf `UserColumnOrigin`.
- `readonly makeDefault?: () => unknown` — Fabrique du défaut, appelée à CHAQUE insertion.
- `readonly refreshedOnWrite?: boolean` — `true` si la valeur est régénérée à CHAQUE écriture (horodatage de modification).
- `readonly readers: readonly string[]` — Les lecteurs qui cassent si la colonne manque — nommés dans les refus.
- `readonly description: string` — Rôle de la colonne, en une phrase.

#### `IUserCreatedEvent`

```ts
interface IUserCreatedEvent
```

Charge utile de `USER_CREATED_EVENT`.

- `readonly id: string` — `IUser.id` du compte créé.
- `readonly identifier: string` — `IUser.identifier` — clé sous laquelle ses facteurs seront rangés.

#### `IUserListQuery`

```ts
interface IUserListQuery extends IPageQuery
```

Requête de **listing paginé** d'utilisateurs — le contrat de page standard du core (`IPageQuery`) enrichi des filtres propres à l'utilisateur.

- `role?: string` — Rôle plat devant figurer dans `roles` (containment natif).
- `enabled?: boolean` — Restreint à l'état actif (`isActive()`).
- `locked?: boolean` — Restreint aux comptes **verrouillés** (`isLocked()`), ou aux non verrouillés.
- `hasSocial?: boolean` — Restreint aux comptes liés à **au moins un fournisseur d'identité externe** (OAuth), ou à ceux qui n'en ont aucun.

#### `IUserProfile`

```ts
interface IUserProfile
```

Profil **public** d'un utilisateur — sous-ensemble des *standard claims* OpenID Connect (OIDC §5.1) en camelCase (convention Nodefony). Stocké dans `BaseUser.metadata.profile`, PAS dans des colonnes dédiées : `IUser` reste identité + rôles (le profil = donnée d'affichage anti-migration). Exposé par **allowlist** dans le DTO admin (`IUserSummary.profile`) — les autres clés de `metadata` (applicatives, potentiellement sensibles) ne fuitent jamais.

- `givenName?: string` — Prénom — OIDC `given_name`.
- `familyName?: string` — Nom de famille — OIDC `family_name`.
- `displayName?: string` — Nom affiché — OIDC `name` (sinon dérivable « givenName familyName »).
- `email?: string` — Adresse e-mail de contact — OIDC `email` (distincte de l'`identifier`).
- `locale?: string` — Préférence de langue — OIDC `locale` (BCP 47, ex.
- `picture?: string` — URL d'avatar — OIDC `picture` (http/https).

#### `IUserProvider`

```ts
interface IUserProvider
```

Contrat de **fourniture** d'utilisateurs — la source d'identité (DB, LDAP, SSO...).

- `loadUserByIdentifier(identifier: string): Promise<IUser>` — Charge un utilisateur par son identifiant fonctionnel (email, login...).
- `loadUserByOAuth(provider: string, providerId: string): Promise<IUser>` — Charge un utilisateur lié à un compte d'un fournisseur OAuth/OIDC.
- `refreshUser(user: IUser): Promise<IUser>` — Recharge un utilisateur depuis la source (rôles/état à jour) à chaque requête.

#### `IUserRepository`

```ts
interface IUserRepository extends IRepository<IPasswordAuthenticatedUser>, ISortableSource
```

Repository **spécialisé utilisateur** — `IRepository<IPasswordAuthenticatedUser>` enrichi de finders métier.

- `findByIdentifier(identifier: string): Promise<IPasswordAuthenticatedUser | null>` — Retrouve un utilisateur par son identifiant fonctionnel (email, login...).
- `findBySocialProvider(provider: string, providerId: string): Promise<IPasswordAuthenticatedUser | null>` — Retrouve un utilisateur lié à un compte d'un fournisseur OAuth/OIDC.
- `listPage(query: IUserListQuery): Promise<IPage<IPasswordAuthenticatedUser>>` — Liste **paginée NATIVEMENT** d'utilisateurs — ne matérialise **jamais** plus d'une page en mémoire (règle perf/mémoire absolue de Nodefony).
- `countActiveAdmins(adminRole: string): Promise<number>` — Compte les administrateurs **actifs** (`isActive()` **et** porteurs de `adminRole`) — garde-fou anti-lockout, calculé **au store** (SQL `COUNT` avec containment de rôle), jamais en chargeant tous les …
- `countUsers(query: IUserListQuery): Promise<number>` — Compte les comptes correspondant aux filtres, **sans les énumérer**.

#### `IUserRevokedEvent`

```ts
interface IUserRevokedEvent
```

Charge utile de `USER_REVOKED_EVENT`. `identifier` = clé de jointure des artefacts (session `user`, PAT `subjectId`). `tenantId` = slot multi-tenant (toujours `null` en mono-tenant — réserve coût-0 pour une cascade scopée).

- `id: string`
- `identifier: string`
- `tenantId: string | null`
- `reason: "deleted" | "disabled" | "locked" | "password_changed"` — Ce qui a coupé l'accès du porteur.

#### `IUserRow`

```ts
interface IUserRow
```

Forme plate d'un utilisateur tel qu'un dépôt le rend, avant reconstruction en `BaseUser` — pendant TypeScript de `USER_COLUMNS`.

- `id: string`
- `identifier: string`
- `password: string | null`
- `roles: string[]`
- `enabled: boolean`
- `locked: boolean`
- `currentRole: string | null`
- `socialProviders: ISocialProvider[]`
- `metadata: Record<string, unknown>`
- `credentialsVersion: number | null`
- `createdAt: Date`
- `updatedAt: Date`

#### `IUserSummary`

```ts
interface IUserSummary
```

Projection **publique** d'un utilisateur pour l'ADMINISTRATION (Studio, P6.15). Redaction PAR CONSTRUCTION (allowlist) — ne porte **jamais** `password`, jamais `metadata` (peut contenir du sensible), et les liens sociaux sont exposés **sans jeton** (`provider`/`providerId`/`createdAt` seulement).

- `id: string`
- `identifier: string`
- `roles: string[]`
- `enabled: boolean` — Compte actif (`isActive()`), pilotable via PATCH `enabled`.
- `locked: boolean` — Compte verrouillé (`isLocked()`), pilotable via PATCH `locked`.
- `hasPassword: boolean` — `true` si le compte a un mot de passe LOCAL (par opposition à OAuth-only).
- `currentRole: string | null` — Profil de rôle actif en session (P5.11), ou `null`.
- `socialProviders: { provider: string; providerId: string; createdAt: number | null; }[]` — Comptes externes liés — jamais de jeton, seulement la référence.
- `profile: IUserProfile` — Profil d'affichage (claims OIDC : prénom/nom/email/locale/avatar), lu par allowlist depuis `metadata.profile` — jamais les autres clés de `metadata`.
- `providerRoles: Record<string, string[]>` — Rôles GÉRÉS par un fournisseur d'identité (`roleMapping`), par fournisseur — sous-ensemble de `roles` recalculé à chaque connexion.
- `createdAt: number | null` — Création (epoch ms) si l'entité la porte (ORM), sinon `null`.
- `updatedAt: number | null` — Dernière mise à jour (epoch ms) si connue, sinon `null`.
- `tenantId: string | null` — Réserve multi-tenant (toujours `null` en mono-tenant — slot coût-0).

### Types (3)

#### `AuthFailureReason`

```ts
type AuthFailureReason = "unknown_identifier" | "disabled" | "locked" | "no_password" | "bad_credentials"
```

Raison d'un échec d'authentification (émise avec `onAuthenticationFailure`).

#### `UserColumnOrigin`

```ts
type UserColumnOrigin = "identity" | "column" | "audit"
```

D'où vient la valeur d'une colonne — ce qui décide si un adaptateur doit la DÉCLARER ou peut la laisser au moteur.

#### `UserColumnType`

```ts
type UserColumnType = "uuid" | "string" | "string[]" | "integer" | "boolean" | "object" | "object[]" | "date"
```

Type **logique** d'une colonne de l'utilisateur — ce que la donnée EST, jamais comment un moteur la range.

---

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