PD-26 — Retour d'expérience (REX)¶
1. Résumé exécutif¶
Objectif initial : Intégration côté backend NestJS d'un fournisseur d'identité OAuth2/OIDC (Keycloak) avec validation JWT complète, modèle d'autorisation HYBRID (roles + scopes), isolation multi-tenant, journalisation conforme et fail-closed en cas d'indisponibilité JWKS.
Résultat obtenu : Module OidcAuthModule complet avec : - Service de découverte OIDC et gestion JWKS (OidcDiscoveryService) - Validation JWT conforme à la spécification normative (OidcJwtValidationService) - Guards d'authentification et d'autorisation (OidcJwtAuthGuard, AuthorizationGuard) - Intercepteur d'audit avec liste blanche fermée (AuthAuditInterceptor) - Health indicator pour signal fail-closed (AuthHealthIndicator) - Décorateurs d'autorisation (@Roles, @Scopes, @AuthorizationRule) - Configuration normative (oidc.config.ts, auth.config.ts, audit.config.ts)
Verdict d'acceptabilité : ✅ ACCEPTÉ (2026-01-08)
État des tests contractuels : - Vitest OIDC (jose ESM) : 38/38 PASS - Jest auth suites : 25 suites / 389 tests PASS - Tests PD-235 délégués : couverts via alias TC-PD235-*
2. Points fluides¶
Spécification normative complète¶
- Invariants explicites (INV-01 à INV-11) avec justifications de sécurité
- Annexe §16 avec valeurs contractuelles concrètes (issuer, audiences, algorithmes, claims)
- Politique de log/audit avec liste blanche fermée (§14)
- Modèle d'autorisation HYBRID clairement défini
Architecture NestJS idiomatique¶
- Guards globaux via
APP_GUARD(ordre : auth puis authorization) - Intercepteur global via
APP_INTERCEPTORpour audit - Configuration via
@nestjs/configavecregisterAs() - Health indicator intégré à
@nestjs/terminus - Décorateurs custom pour l'autorisation déclarative
Séparation des responsabilités claire¶
OidcDiscoveryService: découverte + gestion JWKS + fail-closedOidcJwtValidationService: validation pure du tokenOidcJwtAuthGuard: extraction token + protection routesAuthorizationGuard: évaluation roles/scopes HYBRID
Tests contractuels traçables¶
- Identifiants TC-* dans les noms de tests
- Couverture explicite de chaque invariant et critère d'acceptation
- Alias TC-PD235-* pour la délégation PD-235
3. Points difficiles¶
Compatibilité jose ESM avec Jest¶
La bibliothèque jose v6+ est ESM-only, incompatible avec le loader Jest CommonJS par défaut. - Détection : Erreurs de syntaxe à l'import des modules jose dans Jest - Résolution : Création d'une configuration Vitest dédiée (vitest.config.oidc.ts) pour les tests utilisant jose, maintien de Jest pour le reste - Impact : Deux runners de tests à exécuter (Vitest + Jest)
Écarts initiaux d'acceptabilité (E-01 à E-06)¶
La revue initiale a identifié 6 écarts majeurs entre le plan et la spécification :
| Écart | Description | Résolution |
|---|---|---|
| E-01 | Absence de preuves d'exécution des tests | Exécution documentée Vitest + Jest |
| E-02 | Signal fail-closed JWKS non documenté | AuthHealthIndicator avec HealthCheckError |
| E-03 | Contrôles realm/tenant non détaillés | validateTenant() avec liste fermée |
| E-04 | Liste blanche logs non reprise | AUDIT_ALLOWED_FIELDS + FORBIDDEN_PATTERNS |
| E-05 | Modèle HYBRID non explicite | validateAuthzClaim() + AuthorizationGuard |
| E-06 | Tolérance temporelle non documentée | clockSkewMax: 120 dans config et validation |
Délégation PD-235¶
Les tests d'erreur côté consumer (indisponibilité IdP, token sans identité) devaient être pris en charge par PD-26 : - Détection : Revue croisée PD-235 / PD-26 - Résolution : Section 2bis dans PD-26-tests.md avec alias TC-PD235-* - Traçabilité : Mapping explicite dans le plan d'implémentation (§5bis)
4. Hypothèses révélées tardivement¶
| ID | Hypothèse | Moment de découverte | Impact |
|---|---|---|---|
| - | jose v6+ est ESM-only | Configuration des tests | Double runner Vitest + Jest |
| - | Tests PD-235 délégués au backend | Revue d'acceptabilité | Ajout section 2bis et §5bis dans le plan |
| H-T05 | Horloge synchronisée < 120s | Validation temporelle | Tolérance explicite à documenter |
5. Invariants complexes¶
INV-08 — Fail-closed JWKS¶
- Complexité : Signal observable distinct de HTTP 401 (token invalide)
- Risque régression : Confusion 401 vs 503
- Implémentation :
jwksAvailableflag +ServiceUnavailableException+AuthHealthIndicator - Couverture : TC-NOM-11, TC-PD235-ERR-01, TC-PD235-ERR-03
INV-09/10/11 — Modèle HYBRID déterministe¶
- Complexité : Combinaison AND/OR explicite, refus si ni roles ni scopes
- Risque régression : Règle implicite, héritage non déclaré
- Implémentation :
@AuthorizationRule(AND|OR)obligatoire si roles + scopes déclarés - Couverture : TC-NOM-08, TC-NOM-12, TC-NR-02
INV-04 — Non-fuite dans les logs¶
- Complexité : Liste blanche fermée + détection patterns interdits
- Risque régression : Nouveau champ ajouté sans revue
- Implémentation :
AUDIT_ALLOWED_FIELDSconst +AUDIT_FORBIDDEN_PATTERNSregex - Couverture : TC-NOM-10, TC-NEG-04
6. Dette technique¶
| Dette | Raison d'acceptation | Impact | Remédiation prévue |
|---|---|---|---|
| Double runner tests (Vitest + Jest) | Compatibilité jose ESM | Complexité CI | Migration Jest vers Vitest complète |
| Pas de métriques Prometheus exposées | MVP | Observabilité limitée | Ajout @willsoto/nestjs-prometheus |
Note : Les tests E2E avec Keycloak réel sont couverts par PD-235 (infra) via les scripts tests/pd-235/*.sh exécutés en CI contre l'environnement déployé.
7. Risques résiduels¶
| Risque | Probabilité | Impact | Mitigation actuelle | Surveillance |
|---|---|---|---|---|
| Dérive horloge > 120s | Faible | Majeur (tokens rejetés) | NTP configuré | Monitoring NTP |
| Rotation clés JWKS mal gérée | Moyenne | Majeur | Refresh périodique + retry | Logs refresh |
| Injection dans logs d'audit | Faible | Critique | FORBIDDEN_PATTERNS | Tests TC-NEG-04 |
| Confusion 401 vs 503 | Faible | Mineur | Error codes distincts | Monitoring HTTP codes |
8. Améliorations de processus¶
Documentation écarts dans le plan d'implémentation¶
La revue initiale a identifié 6 écarts majeurs entre le plan et la spécification. Recommandation : - Inclure une checklist de conformité spec→plan avant validation du plan - Vérifier explicitement chaque invariant (INV-) et critère (CA-) dans le plan
Gestion des dépendances ESM¶
La bibliothèque jose v6+ étant ESM-only, les projets NestJS utilisant Jest doivent : - Anticiper la compatibilité ESM lors du choix des bibliothèques - Prévoir Vitest pour les modules ESM-only - Documenter la configuration des tests multi-runners
Traçabilité des délégations entre User Stories¶
La délégation des tests PD-235 vers PD-26 a nécessité une coordination explicite : - Créer une section dédiée dans les tests (2bis) avec alias - Ajouter un mapping dans le plan d'implémentation (§5bis) - Référencer la dépendance dans les documents des deux US
9. Enseignements clés¶
-
Compatibilité ESM/CommonJS : Les bibliothèques ESM-only (jose v6+) nécessitent Vitest ou une configuration Jest complexe. Anticiper ce choix dès la sélection des dépendances.
-
Écarts plan/spécification : Une revue systématique du plan contre les invariants et critères d'acceptation évite les écarts découverts tardivement en acceptabilité.
-
Signal fail-closed observable : Distinguer clairement HTTP 503 (service dégradé) de HTTP 401 (token invalide) pour une observabilité correcte et des alertes pertinentes.
-
Liste blanche de logs fermée : Définir les champs autorisés en amont avec des constantes typées évite les fuites accidentelles de données sensibles.
-
Modèle d'autorisation explicite : Le décorateur
@AuthorizationRule(AND|OR)rend la combinaison roles+scopes déterministe et testable, évitant les ambiguïtés d'héritage. -
Délégation inter-US : Les tests délégués d'une US infra (PD-235) vers une US backend (PD-26) doivent être explicitement tracés avec des alias pour assurer la clôture.
Références¶
- Epic : PD-182 — AUTH
- JIRA : PD-26
- Repos : backend
- Spécification : PD-26-specification.md
- Plan d'implémentation : PD-26-plan.md
- Tests contractuels : PD-26-tests.md
- Acceptabilité : PD-26-acceptability.md
- Dépendance : PD-235 (IdP Keycloak infra) — tests délégués : TC-ERR-01/03, TC-NEG-02/04