Skip to content
Learni
Voir tous les tutoriels
Sécurité

Comment implémenter ABAC dans une API Node.js en 2026

Read in English

Introduction

L'ABAC (Attribute-Based Access Control) révolutionne la gestion des autorisations en entreprise. Contrairement au RBAC (rôles fixes), ABAC évalue dynamiquement l'accès en croisant les attributs de l'utilisateur (rôle, département, localisation), de la ressource (propriétaire, sensibilité), de l'action (lire, écrire, supprimer) et de l'environnement (heure, IP).

Pourquoi l'adopter en 2026 ? Les régulations comme GDPR et les architectures microservices exigent une granularité fine. Imaginez un employé RH qui accède aux dossiers seulement si son département correspond et l'heure est dans les heures ouvrées – ABAC le gère nativement.

Ce tutoriel beginner crée une API Node.js/Express sécurisée ABAC from scratch. Vous obtiendrez un middleware réutilisable, des politiques configurables en JSON et des tests fonctionnels. À la fin, votre API refusera les accès non autorisés avec des réponses HTTP 403 précises. Prêt à sécuriser comme un pro ? (128 mots)

Prérequis

  • Node.js 20+ installé
  • Connaissances basiques en TypeScript et Express
  • Un éditeur comme VS Code
  • 10 minutes pour tester localement

Initialiser le projet et installer les dépendances

terminal
mkdir abac-api && cd abac-api
npm init -y
npm install express jsonwebtoken @types/express @types/jsonwebtoken @types/node
tnpm install -D typescript ts-node nodemon @types/node
npx tsc --init

Cette séquence crée le dossier projet, initialise npm, installe Express pour le serveur, JWT pour simuler l'authentification, et TypeScript pour le typage statique. Les dev-deps permettent de compiler et exécuter TS directement avec ts-node et nodemon pour le hot-reload.

Configurer TypeScript

Avant de coder, adaptons tsconfig.json pour un support moderne. Cela active le strict mode pour catcher les erreurs tôt, comme un filet de sécurité. Exécutez npx tsc --init si pas fait, puis modifiez comme ci-dessous.

tsconfig.json complet

tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "commonjs",
    "lib": ["ES2022"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Ce fichier configure TypeScript pour ES2022, un outDir pour la build, et le strict mode qui force le typage explicite – évitant les bugs runtime comme undefined sur des props optionnelles. resolveJsonModule permet d'importer nos politiques ABAC en JSON.

Définir les types ABAC

ABAC repose sur des attributs structurés. Nous typons User (rôle, dept, location), Resource (propriétaire, type), Action et Environment. Cela rend le code auto-documenté et IntelliSense-friendly.

Types pour attributs ABAC

src/types.ts
export interface UserAttributes {
  sub: string;
  role: 'admin' | 'manager' | 'employee';
  department: string;
  location: string;
}

export interface ResourceAttributes {
  owner: string;
  type: 'post' | 'document';
  department: string;
  sensitivity: 'public' | 'private';
}

export type Action = 'read' | 'write' | 'delete';

export interface EnvironmentAttributes {
  time: string;
  ip: string;
}

export interface AbacRequest {
  user: UserAttributes;
  resource: ResourceAttributes;
  action: Action;
  env: EnvironmentAttributes;
}

Ces interfaces définissent précisément les attributs évalués par ABAC. Par exemple, UserAttributes inclut department pour des règles comme 'accès intra-département'. Utilisez-les partout pour un typage fort qui prévient les erreurs de props manquantes.

Créer le moteur de politiques ABAC

Le cœur d'ABAC est un évaluateur de règles. Nous chargeons des politiques JSON simples (règles logiques) et les appliquons. Analogie : comme un juge qui vérifie si tous les critères d'une loi sont remplis.

Moteur ABAC et politiques JSON

src/abac.ts
import { AbacRequest, UserAttributes, ResourceAttributes, Action, EnvironmentAttributes } from './types';

import policies from '../policies.json';

export function evaluateAbac(req: AbacRequest): boolean {
  const policy = policies.find(p => 
    p.resourceType === req.resource.type &&
    p.action === req.action
  );

  if (!policy) return false;

  for (const rule of policy.rules) {
    if (!rule.condition(req.user, req.resource, req.action, req.env)) {
      return false;
    }
  }
  return true;
}

export function getUserFromToken(token: string): UserAttributes | null {
  try {
    // Simulation JWT decode (utilisez jwt.verify en prod)
    const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
    return {
      sub: payload.sub,
      role: payload.role,
      department: payload.department,
      location: payload.location
    };
  } catch {
    return null;
  }
}

Cette fonction charge des règles JSON, itère sur elles et applique des conditions personnalisées. getUserFromToken extrait les attributs user d'un JWT mock. Piège : toujours valider le token signature en prod avec jwt.verify pour éviter les fakes.

Fichier de politiques ABAC JSON

policies.json
[
  {
    "resourceType": "post",
    "action": "read",
    "rules": [
      {
        "condition": (user: any, resource: any) => user.role === 'admin' || user.department === resource.department
      },
      {
        "condition": (user: any, resource: any, action: any, env: any) => new Date(env.time).getHours() >= 9 && new Date(env.time).getHours() <= 17
      }
    ]
  },
  {
    "resourceType": "post",
    "action": "write",
    "rules": [
      {
        "condition": (user: any, resource: any) => user.sub === resource.owner || user.role === 'admin'
      }
    ]
  }
]

Ce JSON définit des règles ABAC déclaratives : lecture si même dept ou admin ET heures ouvrées ; écriture si propriétaire. Facile à éditer sans redeploy. Ajoutez des règles dynamiques via DB en prod.

Implémenter le middleware ABAC

Le middleware intercepte chaque requête, extrait les attributs et appelle l'évaluateur. Il renvoie 403 si échec, avec détails pour debug.

Middleware ABAC protecteur

src/middleware/abac.ts
import { Request, Response, NextFunction } from 'express';
import { evaluateAbac, getUserFromToken } from '../abac';
import { ResourceAttributes, Action, EnvironmentAttributes } from '../types';

declare global {
  namespace Express {
    interface Request {
      userAttrs?: any;
      resourceAttrs?: ResourceAttributes;
      action?: Action;
    }
  }
}

export function abacMiddleware(requiredResourceType: string, action: Action) {
  return (req: Request, res: Response, next: NextFunction) => {
    const token = req.headers.authorization?.split(' ')[1];
    if (!token) return res.status(401).json({ error: 'Token requis' });

    const user = getUserFromToken(token);
    if (!user) return res.status(401).json({ error: 'Token invalide' });

    req.userAttrs = user;
    req.action = action;

    const resource: ResourceAttributes = req.body.resource || { owner: 'unknown', type: requiredResourceType as any, department: 'default', sensitivity: 'public' };
    req.resourceAttrs = resource;

    const env: EnvironmentAttributes = {
      time: new Date().toISOString(),
      ip: req.ip || 'unknown'
    };

    if (evaluateAbac({ user, resource, action, env })) {
      next();
    } else {
      res.status(403).json({ error: 'Accès refusé par ABAC' });
    }
  };
}

Ce factory middleware prend resourceType et action, parse le token, construit le contexte ABAC et évalue. Extension Request pour typer les props custom. Piège : mock resource via req.body pour démo ; en prod, fetch de DB.

Créer le serveur et les routes protégées

Assemblons tout dans server.ts. Ajoutons des routes /posts/read et /posts/write protégées ABAC. Lancez avec npx nodemon src/server.ts.

Serveur Express complet avec ABAC

src/server.ts
import express from 'express';
import { abacMiddleware } from './middleware/abac';

const app = express();
app.use(express.json());

const PORT = 3000;

// Token mock pour tests (générez avec jwt.sign en prod)
const mockTokens = {
  admin: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwicm9sZSI6ImFkbWluIiwiZGVwYXJ0bWVudCI6IkhSIiwibG9jYXRpb24iOiJQYXJpcyJ9.dummy',
  employee: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyIiwicm9sZSI6ImVtcGxveWVlIiwiZGVwYXJ0bWVudCI6IkhSIiwibG9jYXRpb24iOiJQYXJpcyJ9.dummy'
};

app.post('/posts/read', abacMiddleware('post', 'read'), (req, res) => {
  res.json({ message: 'Post lu avec succès', data: { id: 1, content: 'Contenu sensible' } });
});

app.post('/posts/write', abacMiddleware('post', 'write'), (req, res) => {
  const resource = req.body.resource || {};
  resource.owner = (req as any).userAttrs.sub;
  res.json({ message: 'Post écrit avec succès', resource });
});

app.listen(PORT, () => {
  console.log(`Serveur ABAC sur http://localhost:${PORT}`);
  console.log('Tokens test: admin=', mockTokens.admin);
  console.log('employee=', mockTokens.employee);
});

Serveur complet avec routes ABAC. Tokens mock payload visibles (HR dept). Testez avec curl: curl -H "Authorization: Bearer " -d '{"resource":{"department":"HR"}}' localhost:3000/posts/read. Admin passe toujours, employee seulement si dept match + heures.

Bonnes pratiques

  • Séparez politiques en DB : Chargez JSON depuis PostgreSQL pour mises à jour dynamiques sans restart.
  • Cachez l'évaluation : Utilisez Redis pour mémoriser résultats fréquents (TTL 5min).
  • Loggez les refus : Ajoutez Winston pour tracer evaluateAbac=false avec contexte.
  • Testez exhaustivement : Mocha + cas edge (mauvais token, hors heures).
  • Limitez attributs sensibles : Ne mettez jamais password dans user attrs.

Erreurs courantes à éviter

  • Oublier env attrs : Sans time, les règles horaires échouent silencieusement.
  • Pas de fallback admin : Toujours prioriser role === 'admin' en première règle.
  • JWT sans signature : Mock ok pour dev, mais jwt.verify(secret) obligatoire en prod.
  • Resource non fourni : Validez req.body.resource avec Zod pour éviter crashes.

Pour aller plus loin

Maîtrisez ABAC avancé avec OPA (Open Policy Agent) pour Kubernetes. Explorez Cerbos pour policies as code.

Découvrez nos formations Learni sur la sécurité backend : Node.js Expert, Authentification Avancée. Rejoignez la newsletter pour tutos 2026 !

Comment implémenter ABAC Node.js - 2026 (Tutoriel) | Learni