Router

Router — API keys self-service

CRUD programmatique des clés API : lister, créer, modifier, révoquer. Scope escalation blocked, soft revoke, cross-org isolation. Idéal pour CI/CD, rotation et secrets management.

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é standard ne 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_at est 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 ?