825 lines
20 KiB
Markdown
825 lines
20 KiB
Markdown
# 📚 Documentation Complète API mcV3
|
|
|
|
## Table des matières
|
|
|
|
1. [Architecture générale](#architecture-générale)
|
|
2. [Authentification](#authentification)
|
|
3. [Endpoints API](#endpoints-api)
|
|
4. [Gestion des clés API](#gestion-des-clés-api)
|
|
5. [Rôles et permissions](#rôles-et-permissions)
|
|
6. [Codes HTTP et erreurs](#codes-http-et-erreurs)
|
|
7. [Intégrations](#intégrations)
|
|
8. [Configuration avancée](#configuration-avancée)
|
|
9. [FAQ et dépannage](#faq-et-dépannage)
|
|
|
|
---
|
|
|
|
## Architecture générale
|
|
|
|
### Vue d'ensemble
|
|
|
|
Votre API utilise une **authentification hybride** combinant deux modes:
|
|
|
|
1. **Token API (Bearer Token)** - Pour applications externes/services
|
|
2. **Session utilisateur** - Pour utilisateurs connectés au site web
|
|
|
|
```
|
|
┌─────────────────────────────────────────────┐
|
|
│ Requête /api/* │
|
|
└────────────────┬────────────────────────────┘
|
|
│
|
|
┌───────┴──────────┐
|
|
│ │
|
|
┌────▼─────┐ ┌───────▼──────┐
|
|
│ Bearer │ │ Session │
|
|
│ Token? │ │ Active? │
|
|
└────┬─────┘ └───────┬──────┘
|
|
│ │
|
|
┌────▼──────────────────▼────┐
|
|
│ ApiTokenHandler OR │
|
|
│ Session Storage │
|
|
└────┬──────────────────────┘
|
|
│
|
|
┌────▼──────────────────────┐
|
|
│ Load User + Roles │
|
|
└────┬──────────────────────┘
|
|
│
|
|
┌────▼──────────────────────┐
|
|
│ Verify @IsGranted() │
|
|
└────┬──────────────────────┘
|
|
│
|
|
✅ 200 OK ou ❌ 401/403
|
|
```
|
|
|
|
### Flux de sécurité
|
|
|
|
1. **Firewall `/api`** - Accepte les requêtes `/api/*`
|
|
2. **ApiBearerTokenAuthenticator** - Vérifie les Bearer tokens
|
|
3. **http_basic** - Charge la session du context partagé
|
|
4. **Contrôles d'accès** - Vérifie `@IsGranted()` sur les routes
|
|
5. **ApiExceptionListener** - Convertit les erreurs en JSON
|
|
|
|
---
|
|
|
|
## Authentification
|
|
|
|
### Mode 1: Bearer Token (Clé API)
|
|
|
|
#### Génération du token
|
|
|
|
**Via CLI:**
|
|
```bash
|
|
php bin/console app:api-key:create pseudo_utilisateur "Nom de l'application"
|
|
```
|
|
|
|
Le token est généré automatiquement (64 caractères hexadécimaux, cryptographiquement sécurisé).
|
|
|
|
**Via API (utilisateur connecté):**
|
|
```http
|
|
POST /api/api-keys
|
|
Content-Type: application/json
|
|
Authorization: Bearer existing_token
|
|
|
|
{
|
|
"name": "Application mobile",
|
|
"expiresAt": "2027-04-03T23:59:59Z" // optionnel
|
|
}
|
|
```
|
|
|
|
#### Utilisation du token
|
|
|
|
Le token doit être envoyé dans l'en-tête `Authorization`:
|
|
|
|
```http
|
|
GET /api/profile
|
|
Authorization: Bearer abc123def456...
|
|
```
|
|
|
|
#### Caractéristiques
|
|
|
|
- ✅ Unique par clé API
|
|
- ✅ Peut avoir une date d'expiration
|
|
- ✅ Peut être désactivé/révoqué
|
|
- ✅ Stateless (pas de session serveur)
|
|
- ✅ Audit (tracking du dernier accès)
|
|
|
|
### Mode 2: Session utilisateur
|
|
|
|
#### Établir une session
|
|
|
|
```http
|
|
POST /login
|
|
Content-Type: application/x-www-form-urlencoded
|
|
|
|
_username=john&_password=secret
|
|
```
|
|
|
|
Un cookie `PHPSESSID` est créé et stocké.
|
|
|
|
#### Utiliser la session
|
|
|
|
Tous les cookies sont envoyés automatiquement par le navigateur. Via cURL:
|
|
|
|
```bash
|
|
curl -b cookies.txt -X POST http://localhost:8000/login \
|
|
-d "_username=john&_password=secret"
|
|
|
|
curl -b cookies.txt http://localhost:8000/api/profile
|
|
```
|
|
|
|
#### Caractéristiques
|
|
|
|
- ✅ Basée sur les cookies
|
|
- ✅ Automatique dans le navigateur
|
|
- ✅ Partage avec le firewall `main`
|
|
- ✅ Timeout configurable
|
|
- ✅ Plus sécurisée pour les applications web
|
|
|
|
### Détection du mode d'authentification
|
|
|
|
La réponse `/api/profile` indique le mode utilisé:
|
|
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"pseudo": "john",
|
|
"roles": ["ROLE_USER"],
|
|
"authenticatedVia": "api_key" // ou "session"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Endpoints API
|
|
|
|
### GET /api/health
|
|
|
|
**Authentification**: ❌ Non requise
|
|
|
|
Vérifier l'état de l'API.
|
|
|
|
**Exemple:**
|
|
```bash
|
|
curl http://localhost:8000/api/health
|
|
```
|
|
|
|
**Réponse (200 OK):**
|
|
```json
|
|
{
|
|
"status": "ok",
|
|
"timestamp": "2026-04-03T10:30:00+00:00"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### GET /api/profile
|
|
|
|
**Authentification**: ✅ Requise (Bearer token ou session)
|
|
|
|
Récupérer le profil de l'utilisateur authentifié.
|
|
|
|
**Exemple avec Bearer token:**
|
|
```bash
|
|
curl -X GET http://localhost:8000/api/profile \
|
|
-H "Authorization: Bearer your_token"
|
|
```
|
|
|
|
**Réponse (200 OK):**
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"pseudo": "john",
|
|
"roles": ["ROLE_USER", "ROLE_ADMIN"],
|
|
"authenticatedVia": "api_key"
|
|
}
|
|
```
|
|
|
|
**Erreurs possibles:**
|
|
- `401 Unauthorized` - Token invalide/expiré ou pas de session
|
|
|
|
---
|
|
|
|
### GET /api/api-keys
|
|
|
|
**Authentification**: ✅ Requise (Bearer token ou session)
|
|
|
|
Lister les clés API.
|
|
|
|
- **ROLE_USER**: Voit uniquement SES propres clés
|
|
- **ROLE_ADMIN**: Voit TOUTES les clés du système
|
|
|
|
**Exemple:**
|
|
```bash
|
|
curl -X GET http://localhost:8000/api/api-keys \
|
|
-H "Authorization: Bearer your_token"
|
|
```
|
|
|
|
**Réponse (200 OK):**
|
|
```json
|
|
{
|
|
"apiKeys": [
|
|
{
|
|
"id": 1,
|
|
"name": "Mobile App",
|
|
"token": "a1b2c3d4e5...", // masqué pour sécurité
|
|
"createdAt": "2026-04-01T10:00:00+00:00",
|
|
"lastUsedAt": "2026-04-03T15:30:00+00:00",
|
|
"expiresAt": "2026-12-31T23:59:59+00:00",
|
|
"isActive": true
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### POST /api/api-keys
|
|
|
|
**Authentification**: ✅ Requise (Bearer token ou session)
|
|
|
|
Créer une nouvelle clé API.
|
|
|
|
**Body (JSON):**
|
|
```json
|
|
{
|
|
"name": "Nouvelle application",
|
|
"expiresAt": "2027-04-03T23:59:59Z" // optionnel
|
|
}
|
|
```
|
|
|
|
**Exemple:**
|
|
```bash
|
|
curl -X POST http://localhost:8000/api/api-keys \
|
|
-H "Authorization: Bearer your_token" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"name": "API Desktop",
|
|
"expiresAt": "2026-12-31T23:59:59Z"
|
|
}'
|
|
```
|
|
|
|
**Réponse (201 Created):**
|
|
```json
|
|
{
|
|
"id": 5,
|
|
"name": "API Desktop",
|
|
"token": "abc123def456...xyz", // Complet à la création uniquement!
|
|
"createdAt": "2026-04-03T16:45:00+00:00",
|
|
"message": "Copier le token en lieu sûr, il ne sera plus visible ultérieurement"
|
|
}
|
|
```
|
|
|
|
**⚠️ IMPORTANT**: Le token complet n'est affiché qu'à la création. Stockez-le immédiatement.
|
|
|
|
**Erreurs possibles:**
|
|
- `400 Bad Request` - Paramètre "name" manquant
|
|
- `401 Unauthorized` - Authentification invalide
|
|
|
|
---
|
|
|
|
### DELETE /api/api-keys/{id}
|
|
|
|
**Authentification**: ✅ Requise (Bearer token ou session)
|
|
|
|
Supprimer une clé API.
|
|
|
|
- **ROLE_USER**: Peut supprimer uniquement ses propres clés
|
|
- **ROLE_ADMIN**: Peut supprimer n'importe quelle clé
|
|
|
|
**Exemple:**
|
|
```bash
|
|
curl -X DELETE http://localhost:8000/api/api-keys/1 \
|
|
-H "Authorization: Bearer your_token"
|
|
```
|
|
|
|
**Réponse (200 OK):**
|
|
```json
|
|
{
|
|
"message": "API key deleted"
|
|
}
|
|
```
|
|
|
|
**Erreurs possibles:**
|
|
- `403 Forbidden` - Essai de supprimer la clé d'un autre utilisateur
|
|
- `404 Not Found` - Clé inexistante
|
|
|
|
---
|
|
|
|
### PATCH /api/api-keys/{id}/deactivate
|
|
|
|
**Authentification**: ✅ Requise (Bearer token ou session)
|
|
|
|
Désactiver une clé API sans la supprimer.
|
|
|
|
**Exemple:**
|
|
```bash
|
|
curl -X PATCH http://localhost:8000/api/api-keys/1/deactivate \
|
|
-H "Authorization: Bearer your_token"
|
|
```
|
|
|
|
**Réponse (200 OK):**
|
|
```json
|
|
{
|
|
"message": "API key deactivated"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Gestion des clés API
|
|
|
|
### Cycle de vie d'une clé
|
|
|
|
```
|
|
Création
|
|
│
|
|
├─→ Actif et utilisable
|
|
│
|
|
├─→ Peut être désactivé (sans suppression)
|
|
│
|
|
├─→ Peut avoir une expiration automatique
|
|
│
|
|
└─→ Peut être supprimé définitivement
|
|
```
|
|
|
|
### Bonnes pratiques
|
|
|
|
1. **Créer des clés par application** - Une clé par service/app
|
|
2. **Définir une expiration** - Rotation annuelle recommandée
|
|
3. **Révoquer régulièrement** - Supprimer les vieilles clés
|
|
4. **Ne jamais partager** - Chaque clé est personnelle
|
|
5. **Monitorer l'accès** - Vérifier `lastUsedAt`
|
|
|
|
### Exemple: Rotation de clés
|
|
|
|
```bash
|
|
# 1. Créer une nouvelle clé
|
|
curl -X POST http://localhost:8000/api/api-keys \
|
|
-H "Authorization: Bearer old_token" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"name": "Mobile App v2"}'
|
|
|
|
# 2. Mettre à jour l'application avec la nouvelle clé
|
|
# ... déployer avec new_token ...
|
|
|
|
# 3. Désactiver l'ancienne clé
|
|
curl -X PATCH http://localhost:8000/api/api-keys/1/deactivate \
|
|
-H "Authorization: Bearer new_token"
|
|
|
|
# 4. (Optionnel) Supprimer après confirmation
|
|
curl -X DELETE http://localhost:8000/api/api-keys/1 \
|
|
-H "Authorization: Bearer new_token"
|
|
```
|
|
|
|
---
|
|
|
|
## Rôles et permissions
|
|
|
|
### Hiérarchie de rôles
|
|
|
|
```
|
|
ROLE_ADMIN
|
|
└── ROLE_USER
|
|
|
|
ROLE_MODERATOR
|
|
└── ROLE_USER
|
|
|
|
ROLE_USER (base)
|
|
```
|
|
|
|
### Permissions par rôle
|
|
|
|
| Action | ROLE_USER | ROLE_ADMIN |
|
|
|--------|-----------|-----------|
|
|
| Voir son profil | ✅ | ✅ |
|
|
| Voir ses clés | ✅ | ✅ |
|
|
| Voir les clés d'autres | ❌ | ✅ |
|
|
| Créer ses clés | ✅ | ✅ |
|
|
| Supprimer ses clés | ✅ | ✅ |
|
|
| Supprimer les clés d'autres | ❌ | ✅ |
|
|
| Accéder à /api/* | ✅ | ✅ |
|
|
| Accéder à /administration | ❌ | ✅ |
|
|
|
|
### Implémentation dans le code
|
|
|
|
```php
|
|
// Protéger une route par rôle
|
|
#[Route('/api/mon-endpoint')]
|
|
#[IsGranted('ROLE_USER')]
|
|
public function monEndpoint(): JsonResponse { }
|
|
|
|
// Logique conditionnelle selon le rôle
|
|
if ($this->isGranted('ROLE_ADMIN')) {
|
|
// Admin seulement
|
|
return $this->json($allData);
|
|
}
|
|
return $this->json($userData);
|
|
```
|
|
|
|
---
|
|
|
|
## Codes HTTP et erreurs
|
|
|
|
### Codes de succès
|
|
|
|
| Code | Signification | Utilisation |
|
|
|------|---------------|-------------|
|
|
| 200 | OK | Requête réussie (GET, POST, PATCH, DELETE) |
|
|
| 201 | Created | Ressource créée (POST) |
|
|
| 204 | No Content | Succès sans contenu (rare) |
|
|
|
|
### Codes d'erreur client (4xx)
|
|
|
|
#### 400 Bad Request
|
|
Requête invalide (paramètres manquants, JSON malformé).
|
|
|
|
**Exemple:**
|
|
```json
|
|
{
|
|
"error": "Bad Request",
|
|
"message": "name is required"
|
|
}
|
|
```
|
|
|
|
**Solutions:**
|
|
- Vérifier le format JSON
|
|
- Ajouter les paramètres requis
|
|
|
|
#### 401 Unauthorized
|
|
Non authentifié ou authentification invalide.
|
|
|
|
**Cas courants:**
|
|
- Token manquant: `curl http://localhost:8000/api/profile`
|
|
- Token invalide: `Authorization: Bearer wrong_token`
|
|
- Token expiré: Token dont la date d'expiration est passée
|
|
- Session expirée: Cookies invalides/écoulés
|
|
|
|
**Réponse:**
|
|
```json
|
|
{
|
|
"error": "Unauthorized",
|
|
"message": "Authentication required. Please provide a valid API token or be logged in."
|
|
}
|
|
```
|
|
|
|
**Solutions:**
|
|
- Ajouter le header `Authorization: Bearer YOUR_TOKEN`
|
|
- Renouveler le token expiré
|
|
- Se reconnecter (pour session)
|
|
|
|
#### 403 Forbidden
|
|
Authentifié mais permissions insuffisantes.
|
|
|
|
**Cas courants:**
|
|
- ROLE_USER essayant de supprimer la clé d'un autre
|
|
- Accès à un endpoint réservé aux admins
|
|
|
|
**Réponse:**
|
|
```json
|
|
{
|
|
"error": "Forbidden",
|
|
"message": "You do not have permission to access this resource"
|
|
}
|
|
```
|
|
|
|
**Solutions:**
|
|
- Utiliser un compte admin si nécessaire
|
|
- Vérifier les droits requis
|
|
|
|
#### 404 Not Found
|
|
Ressource inexistante.
|
|
|
|
**Cas courants:**
|
|
- Clé API inexistante: `DELETE /api/api-keys/99999`
|
|
- Endpoint invalide: `GET /api/nonexistent`
|
|
|
|
**Solutions:**
|
|
- Vérifier l'ID de la ressource
|
|
- Vérifier le chemin de la route
|
|
|
|
### Codes d'erreur serveur (5xx)
|
|
|
|
#### 500 Internal Server Error
|
|
Erreur serveur générique.
|
|
|
|
**Cause:** Bug ou exception non gérée.
|
|
|
|
**Solutions:**
|
|
- Vérifier les logs: `tail -f var/log/dev.log`
|
|
- Contacter le développeur
|
|
|
|
---
|
|
|
|
## Intégrations
|
|
|
|
### JavaScript / Fetch API
|
|
|
|
```javascript
|
|
// Configuration
|
|
const API_BASE_URL = 'http://localhost:8000';
|
|
const API_TOKEN = 'your_api_token';
|
|
|
|
// Helper pour les appels API
|
|
async function apiCall(endpoint, options = {}) {
|
|
const url = `${API_BASE_URL}${endpoint}`;
|
|
const headers = {
|
|
'Authorization': `Bearer ${API_TOKEN}`,
|
|
'Content-Type': 'application/json',
|
|
...options.headers,
|
|
};
|
|
|
|
const response = await fetch(url, {
|
|
...options,
|
|
headers,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const error = await response.json();
|
|
throw new Error(`${response.status}: ${error.message}`);
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
// Utilisation
|
|
async function getProfile() {
|
|
try {
|
|
const profile = await apiCall('/api/profile');
|
|
console.log('Profil:', profile);
|
|
} catch (error) {
|
|
console.error('Erreur:', error.message);
|
|
}
|
|
}
|
|
|
|
async function createApiKey(name) {
|
|
try {
|
|
const key = await apiCall('/api/api-keys', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ name }),
|
|
});
|
|
console.log('Clé créée:', key.token);
|
|
} catch (error) {
|
|
console.error('Erreur:', error.message);
|
|
}
|
|
}
|
|
|
|
// Appels
|
|
getProfile();
|
|
createApiKey('Mon App');
|
|
```
|
|
|
|
### Python / Requests
|
|
|
|
```python
|
|
import requests
|
|
import json
|
|
|
|
class ApiClient:
|
|
def __init__(self, base_url, api_token):
|
|
self.base_url = base_url
|
|
self.api_token = api_token
|
|
self.session = requests.Session()
|
|
self.session.headers.update({
|
|
'Authorization': f'Bearer {api_token}',
|
|
'Content-Type': 'application/json',
|
|
})
|
|
|
|
def request(self, method, endpoint, data=None):
|
|
url = f"{self.base_url}{endpoint}"
|
|
try:
|
|
if method == 'GET':
|
|
response = self.session.get(url)
|
|
elif method == 'POST':
|
|
response = self.session.post(url, json=data)
|
|
elif method == 'DELETE':
|
|
response = self.session.delete(url)
|
|
elif method == 'PATCH':
|
|
response = self.session.patch(url, json=data)
|
|
|
|
response.raise_for_status()
|
|
return response.json()
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"Erreur: {e}")
|
|
return None
|
|
|
|
def get_profile(self):
|
|
return self.request('GET', '/api/profile')
|
|
|
|
def list_keys(self):
|
|
return self.request('GET', '/api/api-keys')
|
|
|
|
def create_key(self, name, expires_at=None):
|
|
data = {'name': name}
|
|
if expires_at:
|
|
data['expiresAt'] = expires_at
|
|
return self.request('POST', '/api/api-keys', data)
|
|
|
|
# Utilisation
|
|
client = ApiClient('http://localhost:8000', 'your_api_token')
|
|
|
|
profile = client.get_profile()
|
|
print(f"Profil: {profile}")
|
|
|
|
keys = client.list_keys()
|
|
print(f"Clés: {keys}")
|
|
|
|
new_key = client.create_key('Python App')
|
|
print(f"Nouvelle clé: {new_key['token']}")
|
|
```
|
|
|
|
### PHP / cURL
|
|
|
|
```php
|
|
class ApiClient {
|
|
private $baseUrl;
|
|
private $apiToken;
|
|
|
|
public function __construct($baseUrl, $apiToken) {
|
|
$this->baseUrl = rtrim($baseUrl, '/');
|
|
$this->apiToken = $apiToken;
|
|
}
|
|
|
|
private function request($method, $endpoint, $data = null) {
|
|
$url = $this->baseUrl . $endpoint;
|
|
|
|
$options = [
|
|
'http' => [
|
|
'method' => $method,
|
|
'header' => [
|
|
"Authorization: Bearer {$this->apiToken}",
|
|
'Content-Type: application/json',
|
|
],
|
|
'timeout' => 10,
|
|
],
|
|
];
|
|
|
|
if ($data && in_array($method, ['POST', 'PATCH'])) {
|
|
$options['http']['content'] = json_encode($data);
|
|
}
|
|
|
|
$context = stream_context_create($options);
|
|
$response = @file_get_contents($url, false, $context);
|
|
|
|
if ($response === false) {
|
|
return ['error' => 'Erreur de connexion'];
|
|
}
|
|
|
|
return json_decode($response, true);
|
|
}
|
|
|
|
public function getProfile() {
|
|
return $this->request('GET', '/api/profile');
|
|
}
|
|
|
|
public function listKeys() {
|
|
return $this->request('GET', '/api/api-keys');
|
|
}
|
|
|
|
public function createKey($name, $expiresAt = null) {
|
|
$data = ['name' => $name];
|
|
if ($expiresAt) {
|
|
$data['expiresAt'] = $expiresAt;
|
|
}
|
|
return $this->request('POST', '/api/api-keys', $data);
|
|
}
|
|
}
|
|
|
|
// Utilisation
|
|
$client = new ApiClient('http://localhost:8000', 'your_api_token');
|
|
|
|
$profile = $client->getProfile();
|
|
var_dump($profile);
|
|
|
|
$keys = $client->listKeys();
|
|
var_dump($keys);
|
|
|
|
$newKey = $client->createKey('PHP App');
|
|
echo "Nouvelle clé: " . $newKey['token'];
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration avancée
|
|
|
|
### Ajouter des endpoints personnalisés
|
|
|
|
```php
|
|
// Dans src/Controller/ApiController.php
|
|
|
|
#[Route('/api/custom-endpoint')]
|
|
#[IsGranted('ROLE_USER')]
|
|
public function customEndpoint(): JsonResponse
|
|
{
|
|
$user = $this->getUser();
|
|
|
|
return $this->json([
|
|
'message' => 'Données personnalisées',
|
|
'user' => $user->getPseudo(),
|
|
]);
|
|
}
|
|
```
|
|
|
|
### Filtrer par rôle dans un endpoint
|
|
|
|
```php
|
|
#[Route('/api/admin-data')]
|
|
#[IsGranted('ROLE_USER')]
|
|
public function adminData(): JsonResponse
|
|
{
|
|
if (!$this->isGranted('ROLE_ADMIN')) {
|
|
return $this->json(
|
|
['error' => 'Accès admin requis'],
|
|
JsonResponse::HTTP_FORBIDDEN
|
|
);
|
|
}
|
|
|
|
return $this->json([
|
|
'adminData' => 'Secret data',
|
|
]);
|
|
}
|
|
```
|
|
|
|
### Valider les requêtes
|
|
|
|
```php
|
|
#[Route('/api/create-item', methods: ['POST'])]
|
|
#[IsGranted('ROLE_USER')]
|
|
public function createItem(Request $request): JsonResponse
|
|
{
|
|
$data = json_decode($request->getContent(), true);
|
|
|
|
// Valider les paramètres requis
|
|
if (empty($data['name'])) {
|
|
return $this->json(
|
|
['error' => 'name is required'],
|
|
JsonResponse::HTTP_BAD_REQUEST
|
|
);
|
|
}
|
|
|
|
// Traiter les données...
|
|
|
|
return $this->json(['id' => 1, 'name' => $data['name']]);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## FAQ et dépannage
|
|
|
|
### Q: Erreur "Invalid or expired API token"
|
|
**R:** Le token est invalide ou expiré.
|
|
- Vérifier que le token est correct
|
|
- Créer une nouvelle clé: `php bin/console app:api-key:create`
|
|
- Vérifier l'expiration
|
|
|
|
### Q: Comment mettre à jour ma clé?
|
|
**R:** Les clés ne peuvent pas être mises à jour. Solutions:
|
|
- Créer une nouvelle clé avec une date d'expiration plus lointaine
|
|
- Révoquer l'ancienne clé
|
|
|
|
### Q: Puis-je utiliser la même clé pour plusieurs applications?
|
|
**R:** Techniquement oui, mais **déconseillé** pour des raisons de sécurité:
|
|
- Une compromission affecte toutes les applications
|
|
- Impossible de révoquer une seule application
|
|
- Créer une clé par application
|
|
|
|
### Q: Comment changer l'expiration d'une clé?
|
|
**R:** Ce n'est pas possible directement. Options:
|
|
1. Créer une nouvelle clé avec expiration souhaitée
|
|
2. Révoquer l'ancienne
|
|
3. Mettre à jour l'application
|
|
|
|
### Q: L'API fonctionne-t-elle avec HTTPS?
|
|
**R:** Oui, recommandé en production. Assurez-vous que:
|
|
- Les certificats sont valides
|
|
- Les URLs sont en HTTPS
|
|
- Les cookies ont le flag `Secure`
|
|
|
|
### Q: Puis-je accéder à l'API depuis un autre domaine (CORS)?
|
|
**R:** CORS n'est pas configuré par défaut. Pour l'activer:
|
|
1. Installer bundle CORS: `composer require nelmio/cors-bundle`
|
|
2. Configurer les domaines autorisés
|
|
|
|
### Q: Comment monitorer l'utilisation de l'API?
|
|
**R:** Vérifier:
|
|
- `lastUsedAt` dans GET `/api/api-keys`
|
|
- Les logs: `var/log/dev.log`
|
|
- Implémenter un logging personnalisé
|
|
|
|
### Q: Erreur "403 Forbidden"
|
|
**R:** Vous n'avez pas les permissions. Vérifier:
|
|
- Votre rôle (GET `/api/profile`)
|
|
- Les droits requis (@IsGranted)
|
|
- Si vous essayez de modifier les données d'un autre
|
|
|
|
### Q: Comment réinitialiser toutes mes clés?
|
|
**R:**
|
|
1. Lister les clés: `GET /api/api-keys`
|
|
2. Supprimer une par une: `DELETE /api/api-keys/{id}`
|
|
3. Créer de nouvelles clés
|
|
|
|
---
|
|
|
|
**Documentation à jour: 2026-04-03**
|
|
|