Autentificare
Trei credențiale, trei publicuri
| Credențială | Cine o ține | Durată | Ce acoperă |
|---|---|---|---|
| Cheie de API privată | Backend-ul tău, CI-ul, CLI-ul | Până e revocată | Tot ce îi permit scope-urile |
| Cheie publică | Un bundle de browser | Până e revocată | Se schimbă pe un client token, nimic altceva |
| JWT de client | Un browser, pentru o sesiune | Minute | O organizație, un asistent, o sesiune |
Control plane-ul emite ca_sk_ și ca_pk_. Astea sunt prefixele pe care le vei vedea efectiv.
Web SDK-ul e mai permisiv la intrare, pentru că trebuie să respingă și chei lipite din alte locuri: tratează sk_ și ca_sk_ ca private și le refuză, și acceptă pk_, ca_pk_ și pub_ ca publice. O listă mai largă de prefixe publice e o propunere de design, nu ceva ce emite platforma.
Chei private
Sunt acceptate ambele headere, deci alege-l pe cel care îți vine mai ușor din clientul HTTP:
Authorization: Bearer <cheie>X-CallAgent-Key: <cheie>Se stochează ca sha256(cheie) în api_keys.key_hash, deci o scurgere din baza de date nu produce nimic reutilizabil — iar o cheie pierdută se rotește, nu se recuperează. O cheie poate fi restricționată pe scope, pe origin, pe asistent permis și pe allowlist de IP-uri; toate patru sunt verificate la fiecare request de App\Http\Middleware\AuthenticateApiKey.
Organizația se deduce din cheie. Nu există niciun parametru organization_id nicăieri în API, deci nu are ce să fie falsificat; o resursă din altă organizație întoarce 404, identic cu una care nu a existat niciodată.
Request-urile sunt limitate per cheie — 300 pe minut implicit, suprascrise de api_rate_limit_per_minute al planului tău dacă e setat, și 60 pe minut per IP când nu ești autentificat. Observă consecința: o organizație cu trei chei are trei bucket-uri separate. Vezi Limite de rate.
GET /api-keys/scopes întoarce tot vocabularul de scope-uri. Scope-urile sunt <resursă>.<verb> — call.read, recording.delete, assistant.publish — iar <resursă>.* dă tot grupul.
Nu pune niciodată o cheie privată într-un browser. Web SDK-ul o refuză din prima:
new CallAgent({ publicKey: 'sk_…' });
// CallAgentError: private_key_rejected — "That looks like a private/secret key…"Chei publice și client tokens
Browserele primesc o cheie publică, inutilă în sine. SDK-ul o schimbă pe un JWT de scurtă durată:
POST /api/v1/client-tokens
Authorization: Bearer <cheie publică>
Origin: https://example.com
{ "public_key": "<cheie publică>", "assistant_id": "01JQ…", "ttl": 900 }
201 {
"data": {
"token": "eyJ…",
"token_type": "Bearer",
"expires_at": "2026-01-01T12:15:00+00:00",
"expires_in": 900,
"organization_id": "01J…",
"session_id": "01J…"
}
}Header-ul Origin e verificat față de origin-urile permise ale cheii: o cheie validă prezentată de pe un site pe care nu îl numește e refuzată. Token-urile sunt semnate HS256 cu o cheie derivată din CREDENTIAL_ENCRYPTION_KEY, deci supraviețuiesc unei rotiri de APP_KEY, iar un APP_KEY scurs nu le poate genera. Durată implicită 900 s, maxim 3600 s.
POST /api/v1/client-tokens/verify verifică unul, ceea ce e util când dezvolți un SDK.
Claim-urile token-ului mărginesc ce poate face pagina:
organization care tenant
assistant ce asistent poate fi apelat
user id-ul opac al utilizatorului tău final
session doar sesiunea asta
origins ce site-uri îl pot prezenta
exp când moareSDK-ul reîmprospătează cu 60 de secunde înainte de exp, în loc să aștepte un 401, și retrimite token-ul curent la fiecare reconectare. Dacă preferi să generezi token-uri pe backend-ul tău, dă-i { token } în loc de { publicKey } — atunci SDK-ul nu mai apelează deloc schimbul.
Starea endpoint-ului
Schimbul de token e viu. Pornirea unui apel din browser cu token-ul acela (POST /api/v1/client/calls) e implementată în SDK, dar nu e publicată de control plane. Vezi Browserul și Ce nu este construit.
Credențialele CLI-ului
callagent login # cere cheia, fără ecou pe ecran
echo "$KEY" | callagent login --stdin
callagent whoami
callagent logoutPrima cheie nu poate veni de aici. POST /api-keys are nevoie de o cheie ca să fie apelat, deci prima se creează din dashboard — vezi Pornire rapidă, pasul 1.
Ordinea de rezolvare:
CALLAGENT_API_KEY— bate tot, nu atinge niciodată discul. Folosește asta în CI.- Keychain-ul sistemului (macOS Keychain, libsecret pe Linux).
~/.callagent/credentials.json, creat cu mod0600într-un director0700.
Cheia nu e transmisă niciodată ca argument de linie de comandă, deci nu ajunge nici în istoricul shell-ului, nici într-un ps.
Autentificarea webhook-urilor
Webhook-urile de ieșire sunt semnate, nu autentificate cu o cheie. Vezi Webhooks.