-
Notifications
You must be signed in to change notification settings - Fork 0
Getting Started
Cette page installe Kengela dans une application, compose un point de décision (PDP) minimal, et
exécute un premier check() de bout en bout dans ses trois issues : allow, deny, step-up.
- Node.js >= 24, pnpm (le monorepo est en pnpm 10, mais une app consommatrice peut utiliser npm/yarn/pnpm).
- TypeScript (recommandé) : le socle est écrit en TS6 strict et expose des types complets.
Chaque application n'installe que les paquets dont elle a besoin. Pour un premier check RBAC, il suffit des contrats et du cœur d'autorisation :
npm add @kengela/contracts @kengela/authz-corePour un PDP en base + une intégration NestJS, on ajoute par exemple :
npm add @kengela/nestjs @kengela/adapter-persistence-prisma @kengela/adapter-authn-nativeChaque paquet est publié en double format (ESM + CommonJS). Le champ exports de chaque
package.json route vers le bon build selon la façon dont vous chargez le module :
Concrètement, les deux styles marchent sans configuration :
// ESM / TypeScript
import { RbacDecisionPoint } from '@kengela/authz-core';// CommonJS
const { RbacDecisionPoint } = require('@kengela/authz-core');Détail d'implémentation : le build ESM sort dans
dist/esmet le build CJS dansdist/cjs, chacun avec unpackage.jsonmarqueur ({"type":"module"}/{"type":"commonjs"}) pour que Node interprète correctement chaque sous-arbre.
Le PDP est le composant central : il répond à « ce Principal a-t-il le droit de faire cette action
sur cette ressource ? ». Le cœur fournit deux implémentations de PolicyDecisionPoint :
-
RbacDecisionPoint- la couche RBAC seule (grants × relation organisationnelle). -
LayeredDecisionPoint- RBAC plancher + conditions ABAC (CEL) + conditional access + step-up (voir 02-authorization.md).
Commençons par RbacDecisionPoint. Il a besoin de deux dépendances (deux ports) :
- un
AuthorizationRepositoryqui charge les grants d'un utilisateur ; - un
RelationResolverqui résout la relation organisationnelle acteur ↔ ressource.
Ci-dessous, des implémentations en mémoire (parfaites pour un test ou un prototype) :
import { RbacDecisionPoint } from '@kengela/authz-core';
import type {
AccessRequest,
AuthorizationRepository,
Principal,
RelationResolver,
} from '@kengela/contracts';
// 1. D'où viennent les droits (ici en dur ; en prod, un adapter Prisma).
const grants: AuthorizationRepository = {
async loadGrantsForUser() {
return [{ permission: 'data.orders.read', scope: 'tenant', source: 'MANUAL' }];
},
async loadRole() {
return null;
},
};
// 2. La position de la ressource par rapport à l'acteur (self/unit/subtree/tenant/none).
const relations: RelationResolver = {
async resolveRelation() {
return 'tenant';
},
};
// 3. Le PDP.
const pdp = new RbacDecisionPoint({ grants, relations });Un Principal est le « pont » produit par l'authentification et consommé par l'autorisation (voir
01-architecture.md). La permission requise est construite par le PDP comme
`${resource.type}.${action}` :
const principal: Principal = {
userId: 'u1',
tenantId: 't1',
roles: ['agent'],
mfaLevel: 'none',
authMethod: 'credential',
ctx: { authTime: Date.now() },
};
const request: AccessRequest = {
principal,
action: 'read',
resource: { type: 'data.orders', id: 'o1', tenantId: 't1' },
};
const decision = await pdp.check(request);
// required = 'data.orders.read' ; le grant 'data.orders.read' (scope tenant) couvre la relation
// 'tenant' → allow.
console.log(decision.effect); // 'allow'
console.log(decision.reason); // 'rbac_grant'Une Decision n'est jamais un simple booléen : elle porte l'effect, une reason lisible, les
signals (pour l'audit) et d'éventuelles obligations (voir step-up plus bas).
Retirez le grant, ou demandez une portée que le grant ne couvre pas, et le PDP refuse par défaut :
const noGrant: AuthorizationRepository = {
async loadGrantsForUser() {
return []; // aucun droit
},
async loadRole() {
return null;
},
};
const strictPdp = new RbacDecisionPoint({ grants: noGrant, relations });
const denied = await strictPdp.check(request);
console.log(denied.effect); // 'deny'
console.log(denied.reason); // 'no_grant'L'isolation multi-tenant est défendue au cœur : si resource.tenantId !== principal.tenantId, la
relation est ramenée à none, et seul un grant de portée global (plan plateforme) peut couvrir.
Un Principal du tenant t1 ne franchit donc jamais vers une ressource du tenant t2, même si le
RelationResolver renvoie par erreur une relation large.
Le step-up naît d'une policy déclarative : il faut le PDP en couches, un PolicyStore et un
moteur d'expressions (@kengela/adapter-expr-cel). Exemple : lire une commande est autorisé, mais
la rembourser exige une re-authentification passkey.
npm add @kengela/adapter-expr-celimport { LayeredDecisionPoint } from '@kengela/authz-core';
import { CelExpressionEngine } from '@kengela/adapter-expr-cel';
import type { Policy, PolicyStore } from '@kengela/contracts';
const policies: PolicyStore = {
async loadPolicies() {
const policy: Policy = {
resource: 'data.orders',
action: 'refund',
rules: [
{
effect: 'step_up',
obligations: [{ type: 'require_passkey' }],
reason: 'refund_needs_passkey',
},
],
};
return [policy];
},
};
const layered = new LayeredDecisionPoint({
grants, // doit couvrir data.orders.refund au niveau RBAC (plancher)
relations,
policies,
expr: new CelExpressionEngine(),
});
const decision = await layered.check({
principal,
action: 'refund',
resource: { type: 'data.orders', id: 'o1', tenantId: 't1' },
});
console.log(decision.effect); // 'step_up'
console.log(decision.obligations); // [{ type: 'require_passkey' }]Côté application, step_up se traduit en défi (relancer une MFA/passkey) plutôt qu'en 403 sec.
Avec @kengela/nestjs, le guard lève automatiquement une StepUpRequiredException
(voir 05-nestjs-integration.md).
- Comprendre le modèle : 01-architecture.md.
- Écrire des policies (CEL, obligations) : 02-authorization.md.
- Brancher l'authentification (mots de passe, MFA, sessions) : 03-authentication.md.
- Fédérer des identités (SSO, SCIM, LDAP) : 04-identity-federation.md.
🇬🇧 English
- Home
- Getting started
- Architecture
- Authorization
- Authentication
- Identity federation
- Compliance & PII
- NestJS integration
- Developing an adapter
- Security
Recipes
- NestJS + native + Prisma
- better-auth
- SCIM / Entra
- LDAP / AD
- RBAC / ABAC
- PII / GDPR
- Combo: better-auth + PII
- Combo: SCIM/Entra + authz
- Combo: full stack
🇫🇷 Français
- Accueil
- Prise en main
- Architecture
- Autorisation
- Authentification
- Fédération d'identité
- Conformité & PII
- Intégration NestJS
- Développer un adapter
- Sécurité
Recettes