Autenticazione & chiavi API con scope
Chiavi API con scope (§1.5) - come creare le chiavi, il catalogo dei 27 scope, la gerarchia degli scope, la rotazione e l'endpoint /whoami per l'introspezione.
Ogni richiesta all’API REST di CodeCourier si autentica con una chiave API di progetto con scope. Ogni chiave porta una allow-list esplicita di 1 o più scope (vedi il catalogo qui sotto). Il server rifiuta le richieste il cui scope non è presente sulla chiave con una risposta 403 SCOPE_DENIED nell’envelope di errore v2 (vedi errors).
Creare una chiave
Nel dashboard: Project Settings → API Keys → Generate. Dai un nome alla chiave (ad es. ci-pipeline) e spunta gli scope di cui ha bisogno. Il secret completo viene mostrato esattamente una volta - copialo subito nel tuo secrets manager.
Creazione programmatica:
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 onceIl catalogo dei 27 scope
Gli scope seguono un pattern resource:action. read implica list + get; write implica 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:
*(accesso completo - da usare con parsimonia)
Gerarchia degli scope
*soddisfa ogni controllo di scope. Riservalo alle automazioni a livello di owner.resource:writenon implicaresource:read. Concedi entrambi esplicitamente se il chiamante deve elencare prima di modificare.- Le chiavi legacy create prima di §1.5 sono state mantenute con
*- fai audit e restringi tramite/whoami.
/whoami - Introspezione della chiave
GET /api/v1/whoami restituisce l’identità della chiave corrente e i suoi scope attivi. Utile per i controlli preliminari in 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"Rotazione
- Genera una nuova chiave con lo stesso set di scope (o più ristretto).
- Distribuisci la nuova chiave nel tuo runtime; attendi un ciclo di richiesta completo.
POST /api/v1/project/api-keys/revokesulla vecchia chiave.- Conferma che la chiave revocata restituisca
401 unauthorized.
Fai audit dell’utilizzo tramite lastUsedAt - le chiavi inattive da 90+ giorni dovrebbero essere revocate.