Router — API keys self-service
Gérez vos clés API Meridian programmatiquement. Complément à l'UI /settings/api-keys — l'API est idéale pour :
- CI/CD : créer une clé éphémère pour une pipeline, la révoquer à la fin
- Rotation automatique : script de rotation quotidien/hebdomadaire
- Secrets management : intégration avec HashiCorp Vault, AWS Secrets Manager, etc.
- Multi-environnements : script d'onboarding qui crée les clés
dev,staging,production
Sécurité
- Cross-org isolation : cross-org queries retournent 404 identique, pas d'info leak
- Scope escalation blocked : clé
standardne peut pas créer clésuper_admin - Soft revoke : révocation =
is_active: false, audit history préservée - Secret shown once : retourné seulement à la création
Lister les clés
curl https://router.signalorange.ca/api/v1/api_keys \
-H "Authorization: Bearer $ROUTER_API_KEY"
{
"data": [
{
"id": 12,
"name": "production",
"scope": "standard",
"is_active": true,
"user_id": 42,
"last_used_at": "2026-04-21T12:00:00Z",
"expires_at": null,
"inserted_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-04-21T12:00:00Z"
},
{
"id": 13,
"name": "ci-ephemeral-2026-04-21",
"scope": "standard",
"is_active": false,
"expires_at": "2026-04-22T00:00:00Z",
"..."
}
]
}
Le key (secret) n'est jamais dans la liste.
Créer une clé
curl https://router.signalorange.ca/api/v1/api_keys \
-H "Authorization: Bearer $ROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "ci-build-12345",
"scope": "standard",
"expires_at": "2026-04-22T00:00:00Z"
}'
201 Created — la réponse contient le key une seule fois :
{
"id": 14,
"name": "ci-build-12345",
"scope": "standard",
"is_active": true,
"key": "sk-mer-abc123def456ghi789jkl...",
"user_id": 42,
"expires_at": "2026-04-22T00:00:00Z",
"inserted_at": "2026-04-21T14:00:00Z",
"updated_at": "2026-04-21T14:00:00Z"
}
Champs
| Champ | Requis | Notes |
|---|---|---|
name |
✅ | Pour vous y retrouver (production, staging, ci-build-12345) |
scope |
non (default standard) |
standard ou super_admin — voir scope escalation ci-dessous |
expires_at |
non | ISO-8601. Sans expires_at, la clé n'expire jamais |
Scope escalation blocked
Si la clé appelante est de scope standard et vous demandez super_admin :
HTTP 403
{
"error": {
"message": "Only super_admin-scope keys can create super_admin keys (privilege escalation prevented)",
"type": "scope_escalation_blocked"
}
}
Protection contre une clé compromise qui tenterait de fabriquer une clé plus privilégiée.
Modifier (name, expires_at)
curl -X PATCH https://router.signalorange.ca/api/v1/api_keys/14 \
-H "Authorization: Bearer $ROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "ci-build-12345-extended",
"expires_at": "2026-04-30T00:00:00Z"
}'
Seuls name et expires_at sont modifiables. scope et user_id sont immutables après création (prévention de mutation de privilèges).
Révoquer (soft delete)
curl -X DELETE https://router.signalorange.ca/api/v1/api_keys/14 \
-H "Authorization: Bearer $ROUTER_API_KEY"
Retourne la clé avec is_active: false. La clé ne peut plus authentifier aucune requête. L'historique est préservé pour audit (pas de DELETE SQL, juste un flag).
Patterns d'usage
Rotation manuelle
#!/bin/bash
# rotate-prod.sh — remplace la clé production
OLD_ID=12
# 1. Créer la nouvelle clé
NEW_KEY=$(curl -s https://router.signalorange.ca/api/v1/api_keys \
-H "Authorization: Bearer $ROUTER_API_KEY" \
-d '{"name":"production-'$(date -u +%Y%m%d)'"}' | jq -r '.key')
# 2. Mettre à jour votre secrets manager
vault kv put secret/meridian/prod api_key="$NEW_KEY"
# 3. Redéployer vos services (ils pickent la nouvelle valeur)
kubectl rollout restart deployment/api
# 4. Révoquer l'ancienne après que les rollouts sont finis
curl -X DELETE "https://router.signalorange.ca/api/v1/api_keys/$OLD_ID" \
-H "Authorization: Bearer $ROUTER_API_KEY"
Clé éphémère pour un job CI
# Au début du job
KEY_JSON=$(curl -s https://router.signalorange.ca/api/v1/api_keys \
-H "Authorization: Bearer $MGMT_API_KEY" \
-d '{
"name": "ci-'$CI_JOB_ID'",
"expires_at": "'$(date -u -d '+2 hours' -Iseconds)'"
}')
CI_API_KEY=$(echo "$KEY_JSON" | jq -r '.key')
KEY_ID=$(echo "$KEY_JSON" | jq -r '.id')
# ... utilisez $CI_API_KEY pour les appels Router ...
# À la fin du job (trap EXIT)
curl -X DELETE "https://router.signalorange.ca/api/v1/api_keys/$KEY_ID" \
-H "Authorization: Bearer $MGMT_API_KEY"
Note : actuellement l'
expires_atest indicatif. Le cron de révocation automatique des clés expirées arrivera dans une itération future. Pour l'instant, révoquez explicitement à la fin du job.
Audit — qui a utilisé quoi
La propriété last_used_at est mise à jour à chaque appel Router authentifié. Utile pour :
- Détecter les clés oubliées (last_used_at > 90 jours)
- Vérifier qu'une clé neuve est bien utilisée après un déploiement
curl https://router.signalorange.ca/api/v1/api_keys \
-H "Authorization: Bearer $ROUTER_API_KEY" | \
jq '.data[] | select(.is_active) | {name, last_used_at}'
Et après ?
- Router — Démarrage rapide — première utilisation
- Router — Webhooks — événements sortants (les webhooks utilisent leur propre secret, séparé des clés API)