Authentification & clés API à scope
Clés API à scope (§1.5) - comment créer des clés, le catalogue des 27 scopes, la hiérarchie des scopes, la rotation et l'endpoint /whoami pour l'introspection.
Chaque requête vers l’API REST de CodeCourier s’authentifie avec une clé API de projet à scope. Chaque clé porte une liste blanche explicite de 1 scope ou plus (voir le catalogue ci-dessous). Le serveur rejette les requêtes dont le scope n’est pas présent sur la clé avec une réponse 403 SCOPE_DENIED dans l’enveloppe d’erreur v2 (voir errors).
Créer une clé
Dans le dashboard : Project Settings → API Keys → Generate. Nommez la clé (p. ex. ci-pipeline) et cochez les scopes dont elle a besoin. Le secret complet s’affiche exactement une fois - copiez-le immédiatement dans votre secrets manager.
Création programmatique :
curl
curl -X POST https://<your-deployment>.convex.site/api/v1/project/api-keys/generate \
-H "Authorization: Bearer cc_live_<owner-key>" \
-H "Content-Type: application/json" \
-d '{
"name": "ci-pipeline",
"scopes": ["runs:read", "runs:write", "workflows:read"]
}'TypeScript (fetch)
const res = await fetch(
"https://<your-deployment>.convex.site/api/v1/project/api-keys/generate",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.CC_OWNER_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "ci-pipeline",
scopes: ["runs:read", "runs:write", "workflows:read"],
}),
}
);
const { data } = await res.json();
console.log(data.key); // cc_live_... - shown oncePython (requests)
import os, requests
res = requests.post(
"https://<your-deployment>.convex.site/api/v1/project/api-keys/generate",
headers={
"Authorization": f"Bearer {os.environ['CC_OWNER_KEY']}",
"Content-Type": "application/json",
},
json={
"name": "ci-pipeline",
"scopes": ["runs:read", "runs:write", "workflows:read"],
},
)
print(res.json()["data"]["key"]) # shown onceLe catalogue des 27 scopes
Les scopes suivent un pattern resource:action. read implique list + get ; write implique create + update + delete.
- Projects :
projects:read,projects:write - Workflows :
workflows:read,workflows:write - Runs :
runs:read,runs:write,runs:cancel - Personas :
personas:read,personas:write - Issues :
issues:read,issues:write - Sandboxes :
sandboxes:read,sandboxes:write,sandboxes:exec - Contexts :
contexts:read,contexts:write - Assets :
assets:read,assets:write - Learnings :
learnings:read,learnings:write - Cost Rates :
cost-rates:read,cost-rates:write - Recurring Tasks :
recurring-tasks:read,recurring-tasks:write - Webhooks :
webhooks:read,webhooks:write - Team :
team:read,team:write - Meta :
*(accès complet - à utiliser avec parcimonie)
Hiérarchie des scopes
*satisfait toute vérification de scope. Réservez-le aux automatisations au niveau owner.resource:writen’implique pasresource:read. Accordez les deux explicitement si l’appelant doit lister avant de muter.- Les clés héritées créées avant §1.5 ont été maintenues avec
*- auditez et resserrez via/whoami.
/whoami - Introspection de clé
GET /api/v1/whoami renvoie l’identité de la clé courante et ses scopes actifs. Utile pour les vérifications préalables en CI.
curl
curl https://<your-deployment>.convex.site/api/v1/whoami \
-H "Authorization: Bearer cc_live_..."TypeScript
const r = await fetch(
"https://<your-deployment>.convex.site/api/v1/whoami",
{ headers: { "Authorization": `Bearer ${key}` } }
);
const { data } = await r.json();
// { keyId, projectId, name, scopes: [...], createdAt, lastUsedAt }
if (!data.scopes.includes("runs:write")) throw new Error("scope missing");Python
import requests
r = requests.get(
"https://<your-deployment>.convex.site/api/v1/whoami",
headers={"Authorization": f"Bearer {key}"},
)
data = r.json()["data"]
assert "runs:write" in data["scopes"], "scope missing"Rotation
- Générez une nouvelle clé avec le même set de scopes (ou plus restreint).
- Déployez la nouvelle clé dans votre runtime ; attendez un cycle de requête complet.
POST /api/v1/project/api-keys/revokesur l’ancienne clé.- Confirmez que la clé révoquée renvoie
401 unauthorized.
Auditez l’usage via lastUsedAt - les clés inactives depuis 90+ jours devraient être révoquées.