# Autentificare cu codai (/ro/docs/auth)

auth.codai.ro este un provider OpenID Connect standard. Îl folosești când aplicația ta trebuie să acționeze în numele unui utilizator codai; folosești o cheie API simplă când nu trebuie.

`https://auth.codai.ro` este provider-ul de identitate al codai — un server **OpenID Connect** conform standardelor, cu discovery, PKCE, refresh token-uri, RP-initiated logout și back-channel logout. Fiecare cont codai se autentifică prin el (parolă, passkey, magic link sau Google), iar fiecare suprafață first-party — hub, pay, docs, aplicațiile desktop și de telefon — este un relying party al lui.

Pentru tine, ca integrator, face un singur lucru pe care restul OIDC nu îl face: după ce un utilizator se autentifică și își dă consimțământul, **`GET /connect/key` emite o cheie API de gateway legată de acel utilizator și de acel consimțământ**, astfel încât aplicația ta poate apela `https://ai.codai.ro` *în numele lui* — facturat pe planul lui, revocabil de el, fără să vezi vreodată parola sau celelalte chei ale lui.

## Ai nevoie de el? [#ai-nevoie-de-el]

| Construiești… | Folosești |
| --- | --- |
| Un server, script, bot sau job CI care apelează codai **ca tine** | O cheie API simplă din [hub.codai.ro](https://hub.codai.ro) → Keys. Fără OIDC. Vezi [startul rapid pentru gateway](../gateway/index.mdx). |
| O aplicație în care **fiecare utilizator al tău** vine cu propriul cont codai și plătește pentru propriul consum | **Autentificare cu codai** — [fluxul de autentificare](./connect-flow.mdx). Un redirect, un schimb de token, un `GET /connect/key`. |
| O aplicație web care trebuie doar să știe *cine* este utilizatorul codai (SSO), fără inferență | Fluxul OIDC standard cu code; ceri `openid email profile` și citești ID token-ul. |
| Un client MCP care trebuie să ajungă la uneltele și memoria codai | OIDC cu scope-ul `mcp` pe resursa `https://ai.codai.ro/mcp`; clienții se pot înregistra singuri prin Dynamic Client Registration. |
| Un CLI fără browser pe aceeași mașină | Grant-ul de device authorization este implementat, dar astăzi e provizionat doar pentru clienții first-party — întreabă-ne. |

## Discovery [#discovery]

```bash
curl -s https://auth.codai.ro/.well-known/openid-configuration | jq '{issuer, authorization_endpoint, token_endpoint, userinfo_endpoint, jwks_uri, end_session_endpoint, grant_types_supported, code_challenge_methods_supported, token_endpoint_auth_methods_supported, scopes_supported}'
```

| Endpoint | Cale |
| --- | --- |
| Authorization | `GET /auth` |
| Token | `POST /token` — limitat la 60 de cereri/min per IP (`429 { "error": "rate_limited" }`) |
| UserInfo | `GET /me` |
| JWKS | `GET /jwks` — toate cheile RS256 nerevocate; cea mai nouă semnează |
| Introspection / revocation | `POST /token/introspection`, `POST /token/revocation` |
| End session | `GET /session/end` |
| Dynamic registration | `POST /reg` (doar clienți publici) |
| Device authorization | `POST /device/auth` |
| **Emitere cheie de gateway** | `GET /connect/key` — specific codai, vezi [fluxul de conectare](./connect-flow.mdx) |

Lucruri bune de știut înainte să scrii cod:

- **PKCE (`S256`) este obligatoriu pentru fiecare client**, public sau confidențial. Nu există flux implicit sau hibrid; `response_type` este întotdeauna `code`.
- Metode de autentificare a clientului: `none` (public), `client_secret_basic`, `client_secret_post`, `private_key_jwt`. `client_secret_jwt` nu este oferit.
- Tipuri de grant: `authorization_code`, `refresh_token`, `urn:ietf:params:oauth:grant-type:device_code`.
- Durate de viață ale token-urilor: access token 1 h, ID token 1 h, authorization code 10 min, refresh token 30 de zile cu rotație (≤ 1 an în total), grant de consimțământ 90 de zile, sesiune de browser pe IdP 14 zile.
- Refresh token-urile se emit doar când clientul are grant-ul `refresh_token` **și** cererea a cerut `offline_access`. Clienții publici rotesc întotdeauna la folosire.
- Access token-urile pentru resursa implicită (`https://ai.codai.ro/v1`) sunt opace — le validezi prin introspection sau le folosești direct la `/connect/key`. Token-urile pentru `https://ai.codai.ro/mcp` sunt JWT-uri RS256 pe care gateway-ul le verifică local.
- Step-up: `acr_values` acceptă `urn:codai:acr:pwd`, `urn:codai:acr:passkey`, `urn:codai:acr:mfa`; IdP-ul cere din nou autentificarea dacă metoda sesiunii este mai slabă sau mai veche de 10 minute.

## Înregistrarea unui client [#înregistrarea-unui-client]

Nu există încă înregistrare self-service a clienților pentru fluxul de conectare — clienții sunt provizionați de echipa codai. Trimite-ne numele clientului, redirect URI-urile exacte (fără wildcard-uri; `http://` doar pe loopback), dacă clientul este public (`none`) sau confidențial (`client_secret_basic`, `client_secret_post` sau `private_key_jwt`) și scope-urile de care ai nevoie. Primești un `client_id` și, pentru clienții confidențiali, un secret afișat o singură dată.

Clienții MCP sunt excepția: `POST /reg` acceptă înregistrări RFC 7591 fără un initial access token, creând un client public (`dcr_…`) cu 1 – 5 redirect URI-uri `https://` / loopback / cu schemă personalizată și grant-ul `authorization_code`.

## Deconectare [#deconectare]

- **RP-initiated**: trimiți browser-ul la `GET /session/end?id_token_hint=<id_token>&post_logout_redirect_uri=<registered>&state=<yours>`. Redirect URI-ul trebuie să fie înregistrat **exact** (fără query string — poartă ținta ta locală în `state`). Fără `id_token_hint`, IdP-ul afișează întâi o pagină de confirmare.
- **Back-channel**: dacă clientul tău a înregistrat un `backchannel_logout_uri`, IdP-ul face `POST` cu un `logout_token` (form-encoded, potrivit pe `sid`) când sesiunea utilizatorului se încheie oriunde. Răspunzi `200` sau `204`.

<Callout type="info">
Revocarea consimțământului — utilizatorul își deconectează aplicația ta sau un admin revocă grant-ul — revocă și orice cheie de gateway emisă pentru el. Cheia `codai_…` pe care o stochezi va începe să returneze `401 invalid_api_key`; tratează asta ca „cere-i utilizatorului să se conecteze din nou".
</Callout>
