Sécurité de l'API
Guide complet pour sécuriser les intégrations API avec Cothon incluant l'authentification JWT, les jetons API, la limitation de débit, les politiques CORS, la sécurité des webhooks et les meilleures pratiques
Sécurité de l'API
L'API REST de Cothon fournit un accès programmatique aux données d'intelligence d'approvisionnement, permettant des intégrations avec vos systèmes d'affaires existants, des tableaux de bord personnalisés et des flux de travail automatisés. La sécurité est primordiale lors de l'exposition de données d'appels d'offres sensibles via API, donc nous avons mis en œuvre plusieurs couches de protection : authentification robuste, autorisation granulaire, limitation de débit et journalisation d'audit complète.
Ce guide couvre tout ce dont vous avez besoin pour intégrer de manière sécurisée avec l'API de Cothon, de la génération et la gestion des jetons API à la mise en œuvre de la sécurité des webhooks et à la gestion gracieuse des erreurs.
Authentification API
Tous les points de terminaison de l'API Cothon nécessitent une authentification. Nous prenons en charge deux méthodes d'authentification selon votre cas d'utilisation.
Authentification par jeton JWT (Sessions utilisateur)
Lorsque les utilisateurs interagissent avec l'application Web Cothon, l'authentification utilise des jetons Web JSON (JWT) émis lors de la connexion.
Note
Quand utiliser l'authentification JWT : Utilisez les jetons JWT pour les applications Web et mobiles où les utilisateurs se connectent de manière interactive. Les JWT fournissent un accès basé sur la session lié à des identités d'utilisateur spécifiques.
Pour les intégrations serveur à serveur, les scripts ou les pipelines CI/CD où il n'y a pas d'utilisateur interactif, utilisez plutôt l'authentification par jeton API.
Authentification par jeton API (Comptes de service)
Les jetons API fournissent un accès programmatique pour les systèmes automatisés, les scripts et les intégrations sans nécessiter d'identifiants utilisateur.
Avertissement
Réponse à la compromission de jeton : Si vous soupçonnez qu'un jeton API a été compromis :
- Révoquer immédiatement : Paramètres → Sécurité → Jetons API → Révoquer le jeton compromis
- Consulter les journaux d'audit : Vérifiez Paramètres → Sécurité → Journaux d'audit pour activité suspecte utilisant ce jeton
- Générer un nouveau jeton : Créez un jeton de remplacement avec les mêmes permissions
- Enquêter : Déterminez comment le jeton a été compromis (historique Git, journaux, violation de serveur)
- Notifier l'équipe de sécurité : Si la compromission a affecté des données sensibles, contactez security@cothon.ca
Les jetons compromis peuvent être utilisés pour accéder à toutes les données au sein de votre organisation jusqu'à révocation. Agissez rapidement.
Format et structure des jetons
Les jetons JWT et API suivent des formats spécifiques :
Jetons d'accès JWT :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyX2FiYzEyMyIsImVtYWlsIjoiamFuZS5zbWl0aEBhY21lY29ycC5jb20iLCJvcmdhbml6YXRpb25zIjpbIm9yZ194eXo3ODkiXSwicm9sZSI6Im1lbWJlciIsImlhdCI6MTcxMTgwMDAwMCwiZXhwIjoxNzExODAwOTAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Structure : <en-tête>.<charge-utile>.<signature>
- En-tête : Algorithme et type de jeton
- Charge utile : ID utilisateur, courriel, organisations, rôle, expiration
- Signature : Signature HMAC-SHA256 pour vérification
Jetons API :
cothon_live_3kT9wM2pN5qR7sX1vY4zW6bC8dE0fG2hJ4kL6mN8oP0qR2sT4uV6wX8yZ
Format : cothon_<env>_<chaîne_aléatoire>
- Préfixe :
cothon_identifie les jetons Cothon (pour l'analyse de secrets) - Environnement :
live(production) outest(sandbox) - Chaîne aléatoire : Chaîne cryptographiquement aléatoire de 58 caractères
Jetons de test vs. jetons actifs :
- Jetons de test (
cothon_test_...) : Accès à l'environnement sandbox à https://sandbox-api.cothon.ca - Jetons actifs (
cothon_live_...) : Accès à l'environnement de production à https://api.cothon.ca
N'utilisez jamais de jetons actifs dans les environnements de développement/test ou ne les validez pas dans le contrôle de version.
Autorisation API
L'authentification vérifie qui vous êtes ; l'autorisation détermine ce que vous pouvez faire.
Sécurité au niveau des lignes (RLS)
Cothon utilise la sécurité au niveau des lignes PostgreSQL pour appliquer les politiques d'accès aux données au niveau de la base de données.
Chaque table a des politiques RLS qui filtrent les données en fonction de l'utilisateur authentifié :
-- Exemple : Les utilisateurs peuvent uniquement accéder aux analyses d'appels d'offres de leurs organisations
CREATE POLICY "organisation_isolation"
ON bid_analyses FOR SELECT
USING (
organization_id IN (
SELECT organization_id
FROM organization_members
WHERE user_id = auth.uid()
)
);
-- Exemple : Seuls les Admins et Propriétaires peuvent supprimer les analyses
CREATE POLICY "admin_delete"
ON bid_analyses FOR DELETE
USING (
EXISTS (
SELECT 1
FROM organization_members
WHERE user_id = auth.uid()
AND organization_id = bid_analyses.organization_id
AND role IN ('admin', 'owner')
)
);
Avantages du RLS :
- Défense en profondeur : Même si les contrôles d'accès au niveau de l'application sont contournés, la base de données applique les politiques
- Application automatique : Pas besoin d'ajouter
WHERE organization_id = ?à chaque requête - Piste d'audit : Les vérifications RLS échouées sont journalisées pour la surveillance de sécurité
Modèle de permissions
L'accès API est contrôlé par les rôles d'organisation :
| Point de terminaison | Observateur | Membre | Admin | Propriétaire |
|---|---|---|---|---|
| GET /api/v1/bid-analyses | ✓ | ✓ | ✓ | ✓ |
| POST /api/v1/bid-analysis/analyze | ✗ | ✓ | ✓ | ✓ |
| PUT /api/v1/bid-analyses/:id | ✗ | ✓ | ✓ | ✓ |
| DELETE /api/v1/bid-analyses/:id | ✗ | ✓ | ✓ | ✓ |
| GET /api/v1/opportunities | ✓ | ✓ | ✓ | ✓ |
| POST /api/v1/opportunities/:id/analyze | ✗ | ✓ | ✓ | ✓ |
| POST /api/v1/ai/generate-proposal | ✗ | ✓ | ✓ | ✓ |
| GET /api/v1/export/organization | ✗ | ✗ | ✓ | ✓ |
| POST /api/v1/sharing/shared-analyses | ✗ | ✓ | ✓ | ✓ |
| GET /api/v1/audit-logs | ✗ | ✗ | ✓ | ✓ |
| POST /api/v1/organization/members | ✗ | ✗ | ✓ | ✓ |
| DELETE /api/v1/organization/members/:id | ✗ | ✗ | ✓ | ✓ |
| DELETE /api/v1/organization | ✗ | ✗ | ✗ | ✓ |
Mappage de portée de jeton API :
- Jetons en lecture seule : Équivalent au rôle Observateur (demandes GET uniquement)
- Jetons en lecture-écriture : Équivalent au rôle Membre (GET, POST, PUT, PATCH)
- Jetons Admin : Équivalent au rôle Admin (inclut DELETE, gestion utilisateur)
Réponses d'erreur
Lorsque l'autorisation échoue, l'API retourne des réponses d'erreur claires :
403 Interdit (authentifié mais non autorisé) :
{
"error": "forbidden",
"message": "Vous n'avez pas la permission de supprimer les analyses d'appels d'offres. Rôle requis : Admin ou Propriétaire. Votre rôle : Membre.",
"code": "INSUFFICIENT_PERMISSIONS",
"required_role": "admin",
"current_role": "member"
}
401 Non autorisé (échec d'authentification) :
{
"error": "unauthorized",
"message": "Jeton invalide ou expiré. Veuillez vous authentifier et réessayer.",
"code": "INVALID_TOKEN"
}
404 Non trouvé (la ressource existe mais vous ne pouvez pas y accéder) :
{
"error": "not_found",
"message": "Analyse d'appel d'offres non trouvée.",
"code": "RESOURCE_NOT_FOUND"
}
Note : Nous retournons 404 (pas 403) lorsque vous essayez d'accéder à des ressources d'autres organisations. Cela empêche de divulguer des informations sur l'existence de ressources.
Conseil
Débogage des erreurs d'autorisation : Si vous recevez des erreurs 403 inattendues :
- Vérifiez votre rôle : Vérifiez votre rôle d'organisation dans Paramètres → Organisation → Membres de l'équipe
- Vérifiez la portée du jeton : Vérifiez la portée du jeton API dans Paramètres → Sécurité → Jetons API
- Consultez les journaux d'audit : Vérifiez Paramètres → Sécurité → Journaux d'audit pour les vérifications de permissions échouées
- Testez avec l'interface Web : Si l'opération fonctionne dans l'interface Web mais échoue via API, contactez support@cothon.ca
Problèmes courants :
- Utilisation d'un jeton en lecture seule pour des opérations d'écriture
- Rôle Membre essayant de supprimer des éléments (nécessite Admin)
- Accès à des ressources d'organisations dont vous n'êtes pas membre
Limitation de débit
Pour assurer une utilisation équitable et prévenir les abus, Cothon met en œuvre une limitation de débit sur tous les points de terminaison de l'API.
Niveaux de limitation de débit
Les limites de débit varient selon le plan d'abonnement et le type de point de terminaison :
| Plan | Points de terminaison standard | Points de terminaison IA/intensifs en calcul | Tolérance de rafale |
|---|---|---|---|
| Gratuit | 60 req/min, 1 000 req/jour | 5 req/min, 50 req/jour | 10 demandes |
| Professionnel | 300 req/min, 10 000 req/jour | 20 req/min, 200 req/jour | 50 demandes |
| Entreprise | 1 000 req/min, 50 000 req/jour | 100 req/min, 1 000 req/jour | 200 demandes |
| Personnalisé | Négociable | Négociable | Négociable |
Points de terminaison standard : GET, POST, PUT, DELETE pour analyses d'appels d'offres, propositions, opportunités, données d'organisation
Points de terminaison IA/intensifs en calcul :
/api/v1/bid-analysis/analyze(analyse PDF)/api/v1/ai/generate-proposal(génération de proposition)/api/v1/full-extraction/extract(extraction complète de document)/api/v1/rag/search(recherche sémantique)
Tolérance de rafale : Pic à court terme de demandes au-delà de la limite par minute. Une fois épuisée, les demandes sont limitées au taux par minute.
En-têtes de limitation de débit
Chaque réponse API inclut des en-têtes de limitation de débit :
HTTP/1.1 200 OK
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1711800120
X-RateLimit-Bucket: standard
Retry-After: 42
| En-tête | Description | Exemple |
|---|---|---|
X-RateLimit-Limit | Demandes maximales par fenêtre | 300 (demandes par minute) |
X-RateLimit-Remaining | Demandes restantes dans la fenêtre actuelle | 287 |
X-RateLimit-Reset | Horodatage Unix quand la limite se réinitialise | 1711800120 (secondes epoch) |
X-RateLimit-Bucket | Catégorie de limitation de débit | standard, ai-compute |
Retry-After | Secondes avant de pouvoir réessayer (uniquement sur erreurs 429) | 42 |
Gestion des limitations de débit
Lorsque vous dépassez les limites de débit, l'API retourne 429 Trop de demandes :
{
"error": "rate_limit_exceeded",
"message": "Limite de débit dépassée. Vous avez fait 301 demandes dans la minute actuelle. Limite : 300 demandes par minute.",
"code": "RATE_LIMIT_EXCEEDED",
"retry_after_seconds": 42,
"limit": 300,
"window": "1 minute",
"reset_at": "2026-03-30T14:25:20Z"
}
Succès
Augmentations de limite de débit : Si votre cas d'utilisation légitime nécessite des limites de débit plus élevées, contactez enterprise@cothon.ca avec les détails :
- Votre plan actuel et utilisation de l'API
- Description de votre intégration
- Volume de demandes attendu (demandes par minute/jour)
- Points de terminaison spécifiques que vous appelez
Nous pouvons fournir des limites de débit personnalisées pour les clients d'entreprise et les intégrations à fort volume.
Meilleures pratiques de limitation de débit
Politiques CORS
Le partage de ressources entre origines (CORS) contrôle quelles origines Web peuvent accéder à l'API Cothon depuis les navigateurs.
Origines autorisées
Par défaut, Cothon autorise les demandes CORS depuis :
https://app.cothon.ca(frontend de production)https://sandbox.cothon.ca(frontend sandbox)http://localhost:3000(développement local)http://localhost:5173(serveur de développement Vite)
Origines personnalisées (Entreprise) : Les plans Entreprise peuvent configurer des origines autorisées supplémentaires dans Paramètres → Intégrations → Paramètres CORS.
Exemples de cas d'utilisation :
- Tableaux de bord personnalisés hébergés à
https://dashboard.acmeentreprise.com - Outils internes à
https://tools.acmeentreprise.internal - Portails partenaires à
https://partners.acmeentreprise.com
En-têtes CORS
Lors de demandes API depuis les navigateurs, Cothon retourne des en-têtes CORS :
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.cothon.ca
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type, X-Request-ID
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 86400
| En-tête | Description | Valeur |
|---|---|---|
Access-Control-Allow-Origin | Origine autorisée pour cette demande | https://app.cothon.ca |
Access-Control-Allow-Methods | Méthodes HTTP autorisées | GET, POST, PUT, PATCH, DELETE, OPTIONS |
Access-Control-Allow-Headers | En-têtes de demande autorisés | Authorization, Content-Type, X-Request-ID |
Access-Control-Allow-Credentials | Autoriser témoins/identifiants | true |
Access-Control-Max-Age | Durée de mise en cache de la réponse preflight | 86400 (24 heures) |
Demandes preflight
Pour les demandes complexes (POST, PUT, DELETE, en-têtes personnalisés), les navigateurs envoient une demande OPTIONS preflight :
OPTIONS /api/v1/bid-analyses HTTP/1.1
Origin: https://dashboard.acmeentreprise.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization, Content-Type
Cothon répond avec les méthodes et en-têtes autorisés :
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://dashboard.acmeentreprise.com
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type, X-Request-ID
Access-Control-Max-Age: 86400
Le navigateur procède ensuite avec la demande réelle.
Avertissement
CORS et sécurité : CORS est une fonctionnalité de sécurité du navigateur. Elle n'empêche PAS les clients non-navigateurs (curl, Postman, scripts côté serveur) d'accéder à l'API.
Pour les intégrations côté serveur, CORS n'est pas pertinent — l'authentification (jetons API) est le contrôle de sécurité principal.
CORS protège uniquement contre les sites Web malveillants faisant des demandes API non autorisées depuis les navigateurs des utilisateurs.
Gestion des erreurs CORS
Si vous rencontrez des erreurs CORS dans les applications basées sur navigateur :
Erreur : L'accès à fetch à 'https://api.cothon.ca/api/v1/bid-analyses' depuis l'origine 'https://monapp.com' a été bloqué par la politique CORS
Solutions :
Sécurité des webhooks
Les webhooks permettent à Cothon de notifier vos systèmes d'événements (nouvelles analyses, génération de proposition terminée, correspondances d'opportunités) sans sondage.
Configuration de webhook
Types d'événements webhook
Cothon envoie des webhooks pour ces événements :
| Événement | Description | Charge utile |
|---|---|---|
analysis.created | Nouvelle analyse d'appel d'offres démarrée | analysis_id, title, status, created_at |
analysis.completed | Analyse d'appel d'offres terminée | analysis_id, title, requirements_count, overall_score |
analysis.failed | Analyse d'appel d'offres échouée | analysis_id, error_message, failed_at |
proposal.generated | Proposition IA générée | proposal_id, analysis_id, word_count, generated_at |
opportunity.matched | Nouvelle opportunité correspondant aux capacités | opportunity_id, title, deadline, match_score |
opportunity.deadline_soon | Échéance d'opportunité sauvegardée approchant | opportunity_id, title, deadline, days_remaining |
member.added | Membre de l'équipe ajouté à l'organisation | user_id, email, role, added_at |
member.removed | Membre de l'équipe retiré de l'organisation | user_id, email, removed_at |
Sécurité des webhooks
Logique de nouvelle tentative webhook
Si votre point de terminaison retourne une erreur (réponse non-200 ou timeout), Cothon réessaie le webhook :
| Tentative | Délai | Temps total |
|---|---|---|
| 1 | Immédiat | 0s |
| 2 | 30 secondes | 30s |
| 3 | 5 minutes | 5m 30s |
| 4 | 30 minutes | 35m 30s |
| 5 | 2 heures | 2h 35m 30s |
Après 5 tentatives échouées, le webhook est marqué comme échoué et vous recevrez une alerte par courriel.
Voir les webhooks échoués : Accédez à Paramètres → Intégrations → Webhooks → « Livraisons échouées » pour voir les webhooks qui ont échoué toutes les tentatives.
Vous pouvez réessayer manuellement les webhooks échoués en cliquant sur « Réessayer la livraison ».
Conseil
Test de webhook : Utilisez des outils comme ngrok pour exposer des serveurs de développement locaux pour le test de webhook :
# Démarrer le serveur local sur le port 5000
python app.py
# Exposer via ngrok
ngrok http 5000
Utilisez l'URL ngrok (par ex. https://abc123.ngrok.io/webhooks/cothon) comme point de terminaison webhook dans les paramètres Cothon.
Alternativement, utilisez des services de test de webhook comme webhook.site pour inspecter les charges utiles webhook sans écrire de code.
Meilleures pratiques API
Gestion des erreurs
Implémentez une gestion complète des erreurs pour toutes les demandes API :
import requests
def make_api_request(url, headers, max_retries=3):
for attempt in range(max_retries):
try:
response = requests.get(url, headers=headers, timeout=30)
if response.status_code == 200:
return response.json()
elif response.status_code == 401:
raise AuthenticationError("Jeton API invalide ou expiré")
elif response.status_code == 403:
raise PermissionError(f"Permissions insuffisantes : {response.json().get('message')}")
elif response.status_code == 404:
return None # Ressource non trouvée
elif response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
time.sleep(retry_after)
continue
elif response.status_code >= 500:
# Erreur serveur, réessayer avec backoff
wait_time = 2 ** attempt
time.sleep(wait_time)
continue
else:
response.raise_for_status()
except requests.exceptions.Timeout:
if attempt == max_retries - 1:
raise TimeoutError(f"Demande expirée après {max_retries} tentatives")
time.sleep(2 ** attempt)
except requests.exceptions.ConnectionError:
if attempt == max_retries - 1:
raise ConnectionError("Impossible de se connecter à l'API Cothon")
time.sleep(2 ** attempt)
raise Exception(f"Demande échouée après {max_retries} tentatives")
Journalisation et surveillance
Journalisez toutes les interactions API pour le débogage et la surveillance :
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def make_api_request(url, headers):
logger.info(f"Demande API : GET {url}")
try:
response = requests.get(url, headers=headers, timeout=30)
logger.info(f"Réponse API : {response.status_code} - {len(response.content)} octets")
if response.status_code != 200:
logger.warning(f"Erreur API : {response.status_code} - {response.text}")
return response
except Exception as e:
logger.error(f"Exception API : {str(e)}", exc_info=True)
raise
Métriques à suivre :
- Nombre de demandes par point de terminaison
- Taux de succès/erreur
- Temps de réponse (p50, p95, p99)
- Utilisation de la limitation de débit
- Utilisation des jetons API par jeton
Utilisez des outils de surveillance comme Prometheus, Datadog ou New Relic pour suivre la santé de l'API.
ID de demande
Incluez un ID de demande unique dans chaque appel API pour le débogage :
import uuid
def make_api_request(url, headers):
request_id = str(uuid.uuid4())
headers['X-Request-ID'] = request_id
logger.info(f"Demande {request_id} : GET {url}")
response = requests.get(url, headers=headers)
logger.info(f"Demande {request_id} : {response.status_code}")
return response
Si vous rencontrez des erreurs, fournissez le X-Request-ID au support pour un dépannage plus rapide.
Pagination
Utilisez la pagination pour les points de terminaison qui retournent de grands ensembles de résultats :
def fetch_all_analyses(headers):
analyses = []
page = 1
per_page = 100
while True:
response = requests.get(
'https://api.cothon.ca/api/v1/bid-analyses',
headers=headers,
params={'page': page, 'per_page': per_page}
)
data = response.json()
analyses.extend(data['items'])
if not data.get('has_more'):
break
page += 1
return analyses
Limites de pagination :
per_pagemaximum : 100 élémentsper_pagepar défaut : 20 éléments
Utilisez per_page=100 pour minimiser les appels API.
Foire aux questions
Ressources supplémentaires
- Authentification et contrôle d'accès - Authentification utilisateur et configuration A2F
- Aperçu de la sécurité - Architecture de sécurité complète
- Référence API - Documentation complète des points de terminaison API
- Guides d'intégration - Tutoriels d'intégration étape par étape
Support API :
- Questions techniques : support@cothon.ca
- Questions de sécurité : security@cothon.ca
- Accès API Entreprise : enterprise@cothon.ca
Ressources développeur :
- État de l'API : https://status.cothon.ca
- Journal des modifications API : https://docs.cothon.ca/api/changelog
- Communauté développeur : https://community.cothon.ca
Dernière mise à jour : 30 mars 2026
Prochaine révision : 30 juin 2026
Related Articles
Was this page helpful?