Un guide pratique de l'authentification et de l'autorisation des API, y compris OAuth 2.0, JWT et la gestion des clés API.
OAuth 2.0 est le cadre d'autorisation le plus largement utilisé pour l'accès aux API. Il est essentiel de sélectionner le type de subvention approprié.
| Type de subvention | Cas d'utilisation | Niveau de sécurité |
|---|---|---|
| Authorization Code + PKCE | SPA et applications mobiles (recommandé) | Le plus élevé |
| Authorization Code | Applications web côté serveur | Haut |
| Client Credentials | Communication de serveur à serveur (M2M) | Moyen |
| Implicite (obsolète) | Anciennes ZPS | Faible |
| Mot de passe du propriétaire de la ressource (obsolète) | Uniquement des tiers de confiance | Faible |
L'octroi implicite est désormais obsolète car le jeton est exposé dans le fragment d'URL. Utilisez le code d'autorisation + PKCE pour les SPA.
// Génération aléatoire d'un vérificateur de code function generateCodeVerifier() { const array = new Uint8Array(32); crypto.getRandomValues(array); return btoa(String.fromCharCode(...array)) .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); } // Générer le code_challenge avec SHA-256 async function generateCodeChallenge(verifier) { const encoder = new TextEncoder(); const data = encoder.encode(verifier); const digest = await crypto.subtle.digest('SHA-256', data); return btoa(String.fromCharCode(...new Uint8Array(digest))) .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); } // Demande d'autorisation const verifier = generateCodeVerifier(); const challenge = await generateCodeChallenge(verifier); const authUrl = `https://auth.example.com/authorize?` + `response_type=code&` + `client_id=${clientId}&` + `redirect_uri=${redirectUri}&` + `code_challenge=${challenge}&` + `code_challenge_method=S256&` + `scope=read write`;
Le JWT est largement utilisé comme jeton d'authentification sans état, mais les erreurs de mise en œuvre entraînent directement des vulnérabilités en matière de sécurité.
const jwt = require('jsonwebtoken'); // --- Émission de jetons --- function issueTokens(user) { const accessToken = jwt.sign( { sub: user.id, role: user.role }, process.env.JWT_SECRET, { algorithm: 'HS256', expiresIn: '15m', issuer: 'api.example.com', audience: 'app.example.com', } ); const refreshToken = jwt.sign( { sub: user.id, type: 'refresh' }, process.env.REFRESH_SECRET, { algorithm: 'HS256', expiresIn: '7d' } ); return { accessToken, refreshToken }; } // --- Token Verification --- function verifyAccessToken(token) { return jwt.verify(token, process.env.JWT_SECRET, { algorithms: ['HS256'], ← Toujours préciser ! issuer: 'api.example.com', audience: 'app.example.com', }); }
| Lieu de stockage | Résistance aux XSS | Résistance au CSRF | Recommandation |
|---|---|---|---|
| HttpOnly Cookie | ◎ | △ (nécessite le paramètre SameSite) | Recommandé |
| Mémoire (variable) | ◎ | ◎ | Perte de la navigation sur la page |
| localStorage | ✕ (peut être volé via XSS) | ◎ | Non recommandé |
| sessionStorage | ✕ (peut être volé via XSS) | ◎ | Utilisation limitée |
L'approche la plus sûre consiste à stocker le jeton d'accès dans un cookie avec les attributs HttpOnly, Secure et SameSite=Strict. Cela permet d'éviter le vol du jeton par des attaques XSS.
Les clés API constituent un mécanisme d'authentification simple, mais une mauvaise gestion peut entraîner des risques graves.
Générer avec une entropie suffisante (256 bits ou plus). Stocker le texte haché ; ne jamais conserver de texte en clair dans la base de données.
Attribuer des portées minimales par clé (lecture seule, ressources spécifiques uniquement, etc.). Évitez les autorisations de type "joker".
Procéder à une rotation régulière des clés (dans un délai de 90 jours). Fixer un délai de grâce pour les anciennes clés. Révoquer immédiatement les clés en cas de fuite.
Envoyer via un en-tête (X-API-Key ou Authorization). Ne pas inclure dans les paramètres de requête de l'URL (ils apparaissent dans les journaux).
Ne pas coder les clés en dur dans le code source. Gérez-les à l'aide de variables d'environnement ou d'un gestionnaire de secrets.
Surveiller l'utilisation des clés API. Détecter les schémas anormaux (demandes massives, accès à partir d'IP inconnues).
const crypto = require('crypto'); // Hacher la clé de l'API avec SHA-256 et comparer async function validateApiKey(req, res, next) { const apiKey = req.headers['x-api-key']; if (!apiKey) { return res.status(401).json({ error: 'API key required' }); } // Hachage et recherche dans la base de données (timingSafeEqual non nécessaire puisque nous comparons des hachages) const hashedKey = crypto .createHash('sha256') .update(apiKey) .digest('hex'); const keyRecord = await db.findApiKey(hashedKey); if (!keyRecord || keyRecord.revokedAt) { return res.status(403).json({ error: 'Invalid API key' }); } // Vérifier l'expiration if (keyRecord.expiresAt && new Date() > keyRecord.expiresAt) { return res.status(403).json({ error: 'API key expired' }); } req.apiClient = keyRecord; next(); }
AI agents and LLM-powered applications require additional authentication and authorization patterns beyond traditional API security.
Assign different access levels per model tier (e.g., GPT-4 requires elevated scope). Prevent unauthorized use of expensive or sensitive models.
Embed token budgets in access tokens or API key metadata. Enforce per-request and per-day limits to prevent denial-of-wallet attacks.
Check user permissions before executing certain prompt types (e.g., code generation, data analysis). Map prompt categories to role-based permissions.
Ensure conversation history, fine-tuned models, and RAG data are isolated per tenant. Use tenant-scoped API keys with namespace enforcement.
Assign cryptographic identities to AI agents. Use signed JWTs for inter-agent communication. Verify agent identity before granting tool access.
Automate API key rotation for LLM providers. Use short-lived tokens for agent sessions. Revoke credentials immediately when agents are decommissioned.
| Scenario | Auth Method | Required Scope | Approval |
|---|---|---|---|
| Agent reads public data | API Key | data:read |
Automatic |
| Agent modifies user data | OAuth 2.0 (delegated) | data:write |
User consent required |
| Agent calls external API | OAuth 2.0 + mTLS | external:invoke |
Human-in-the-loop |
| Agent executes code / shell | Scoped JWT + Sandbox | exec:sandbox |
Admin approval + audit log |
import jwt import time from datetime import datetime, timedelta class AgentTokenIssuer: """Issues scoped, short-lived tokens for AI agents.""" ALLOWED_SCOPES = { "reader": ["data:read"], "writer": ["data:read", "data:write"], "executor": ["data:read", "data:write", "exec:sandbox"], } def __init__(self, secret_key: str): self.secret_key = secret_key def issue_agent_token( self, agent_id: str, role: str, tenant_id: str, token_budget: int = 10000, ttl_minutes: int = 15, ) -> str: # Validate role and resolve scopes if role not in self.ALLOWED_SCOPES: raise ValueError(f"Invalid role: {role}") payload = { "sub": agent_id, "tenant": tenant_id, "scopes": self.ALLOWED_SCOPES[role], "token_budget": token_budget, "iat": datetime.utcnow(), "exp": datetime.utcnow() + timedelta(minutes=ttl_minutes), "type": "agent", } return jwt.encode(payload, self.secret_key, algorithm="HS256") def verify_tool_access(self, token: str, required_scope: str) -> dict: # Decode and verify agent token payload = jwt.decode( token, self.secret_key, algorithms=["HS256"] ) if required_scope not in payload["scopes"]: raise PermissionError( f"Agent {payload['sub']} lacks scope: {required_scope}" ) return payload
Related: LLM06: Excessive Agency, ASI01: Excessive Agency, ASI03: Insecure Tool/Function Calling
| Méthode | Apatride | Cas d'utilisation | Considérations relatives à la sécurité |
|---|---|---|---|
| OAuth 2.0 + PKCE | ○ | API nécessitant l'autorisation de l'utilisateur | état/PKCE requis, gestion de l'expiration des jetons |
| JWT Bearer | ○ | Communication inter-microservices | Spécification de l'algorithme requise, pas de données sensibles dans la charge utile |
| Clé API | ○ | Serveur à serveur, intégrations externes | Rotation et restriction du champ d'application requises |
| mTLS | ○ | Communication M2M de haute sécurité | Coût opérationnel élevé pour la gestion des certificats |
| Cookie de session | ✕ | Applications web traditionnelles | Protection CSRF requise, problèmes d'évolutivité |