---
title: "Connettiti con OAuth"
description: "Autorizza i client MCP e la CLI di ThunderPhone senza condividere una chiave API."
---

OAuth consente a un'app di connettersi a un'organizzazione ThunderPhone con le autorizzazioni che approvi. I client di directory devono usare OAuth per impostazione predefinita. Le chiavi API dell'organizzazione restano disponibili per i client che richiedono un token Bearer configurato manualmente.

## Approva una connessione

Avvia la connessione nel tuo client MCP. Accedi a ThunderPhone, verifica il nome dell'app e le autorizzazioni richieste, scegli un'organizzazione e seleziona **Approva**. Seleziona **Nega** se non hai avviato la connessione o non ritieni affidabile l'app. I nomi delle app sono forniti dai relativi sviluppatori e non costituiscono un badge di verifica.

Le autorizzazioni di lettura espongono i dati indicati, incluse registrazioni e trascrizioni quando viene richiesta `calls:read`. Le autorizzazioni di scrittura possono modificare o eliminare risorse; chiamate, campagne, acquisti di numeri di telefono e distribuzioni possono comportare costi o influire sulla produzione. Il tuo ruolo nell'organizzazione continua ad applicarsi.

Per una connessione CLI, apri il link di verifica mostrato nel terminale, confronta il codice di otto caratteri, seleziona la tua organizzazione e approva. La semplice apertura del link non concede l'accesso. I codici scadono dopo 15 minuti.

## Disconnetti un'app

Apri **Organizzazione → Chiavi API → App autorizzate** nella dashboard e scegli **Revoca**. Questa operazione revoca l'autorizzazione selezionata per l'organizzazione corrente, inclusi i relativi token di accesso e di aggiornamento. Riconnettiti dall'app se vuoi autorizzarla di nuovo.

## Individuazione per client MCP

Usa l'URL del server `https://api.thunderphone.com/v1/mcp`. Una richiesta senza autenticazione valida riceve `401` con:

```http
WWW-Authenticate: Bearer resource_metadata="https://api.thunderphone.com/.well-known/oauth-protected-resource"
```

Recupera quel documento, quindi recupera i metadati del server di autorizzazione all'indirizzo `https://api.thunderphone.com/.well-known/oauth-authorization-server`. I metadati della risorsa sono disponibili anche in `/.well-known/oauth-protected-resource/v1/mcp`. Usa gli endpoint restituiti anziché costruirli manualmente. L'identificatore della risorsa è `https://api.thunderphone.com/v1/mcp`.

Il server supporta il codice di autorizzazione con **S256 PKCE**, token di refresh a rotazione, registrazione dinamica di client pubblici, revoca e il grant di autorizzazione del dispositivo. Non sono presenti segreti client né grant impliciti. L'individuazione OpenID è disponibile anche in `/.well-known/openid-configuration`; include gli stessi campi del server di autorizzazione più `subject_types_supported: ["public"]` e l'endpoint userinfo. I token ID e i Client ID Metadata Documents (CIMD) non sono supportati.

### Registra un client pubblico

Invia JSON a `POST /v1/oauth/register`:

```json
{
  "client_name": "My MCP client",
  "redirect_uris": ["http://127.0.0.1:8765/callback"],
  "token_endpoint_auth_method": "none",
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"]
}
```

Salva il `client_id` restituito. I reindirizzamenti devono usare HTTPS oppure HTTP su `127.0.0.1` o `localhost`. Registra l'URI di callback esatto, inclusi porta e percorso. I frammenti e le credenziali incorporate vengono rifiutati. Gli elementi facoltativi `client_uri` e `logo_uri` devono usare HTTPS; ThunderPhone non li recupera durante la registrazione. La registrazione è soggetta a limiti di frequenza. I client registrati non scadono e restano registrati quando una connessione viene revocata. Le callback HTTPS includono `https://chatgpt.com/connector/oauth/<id>` e `https://chatgpt.com/connector_platform_oauth_redirect`. Ogni connessione può registrare il proprio client.

### Codice di autorizzazione

Apri l'endpoint di autorizzazione individuato con `client_id`, l'esatto `redirect_uri` registrato, `response_type=code`, un `state` casuale, `scope`, `code_challenge`, `code_challenge_method=S256` e `resource=https://api.thunderphone.com/v1/mcp`. Calcola la challenge come digest SHA-256 base64url senza padding di un nuovo verifier PKCE ad alta entropia. Verifica i valori `state` e `iss` restituiti prima di scambiare il codice. Ogni risposta di autorizzazione, inclusi rifiuti ed errori di protocollo, identifica l'emittente con `iss`, che corrisponde esattamente all'`issuer` individuato. Gli errori relativi a un client o a una callback non validi vengono restituiti localmente senza reindirizzare a tale callback.

Scambia tramite `POST /v1/oauth/token` usando la codifica dei moduli (è accettato anche JSON):

```text
grant_type=authorization_code
client_id=<your client id>
code=<single-use authorization code>
redirect_uri=<exact registered redirect URI>
code_verifier=<original PKCE verifier>
resource=https://api.thunderphone.com/v1/mcp
```

Il parametro facoltativo `resource` è accettato sia nelle richieste di autorizzazione sia in quelle di token, inclusi gli scambi di refresh e dispositivo. Se omesso, usa come predefinita la risorsa MCP individuata. Se presente, deve corrispondere esattamente a quella risorsa; altri valori restituiscono `invalid_target`. I token di accesso riportano tale audience e MCP rifiuta i token con audience mancante o diversa con `401` e una challenge di individuazione.

Le richieste di autorizzazione e i codici scadono dopo 10 minuti. Ogni risposta del token contiene `access_token`, `token_type` (`Bearer`), `expires_in` (3600 secondi per impostazione predefinita), `refresh_token`, `scope`, `organization_id` e `organization_name`. Invia i token di accesso solo tramite l'header `Authorization: Bearer`. Non inserire mai token in URL, log, controllo del codice sorgente o chat.

### Aggiorna e revoca

Aggiorna con `grant_type=refresh_token`, `client_id`, `refresh_token` e `resource` nell'endpoint del token. Salva atomicamente il nuovo token di refresh e smetti di usare quello vecchio. I token di refresh scadono dopo 30 giorni senza un aggiornamento riuscito. Un `scope` facoltativo può limitare le autorizzazioni concesse. `offline_access` è sempre incluso e i token di refresh vengono sempre emessi. Una richiesta iniziale senza `scope` concede solo `offline_access`, pertanto i client devono richiedere le autorizzazioni necessarie.

Il riutilizzo di un codice e il riutilizzo di un token di refresh ruotato revocano l'intera autorizzazione. Serializza gli aggiornamenti all'interno di un client; ripetere una credenziale scambiata correttamente non è una strategia di nuovo tentativo sicura.

Per disconnettere, invia `token` e `client_id` a `POST /v1/oauth/revoke`. La revoca di uno dei due token revoca la relativa autorizzazione, inclusi tutti i token emessi da essa. Un token sconosciuto restituisce un esito positivo senza rivelare se esiste. Le sessioni del dashboard possono elencare le proprie autorizzazioni con `GET /v1/oauth/grants` e revocarle con `DELETE /v1/oauth/grants/<id>`, usando `X-ThunderPhone-Org` per selezionare l'organizzazione.

### Autorizzazione del dispositivo

L'autorizzazione del dispositivo è limitata ai client preregistrati; i client registrati dinamicamente ricevono `unauthorized_client`. Il client pubblico preregistrato `thunderphone-cli` supporta l'autorizzazione del dispositivo e l'aggiornamento. Invia `client_id=thunderphone-cli` e `scope` a `POST /v1/oauth/device/code`. Mostra all'utente `user_code` e `verification_uri` oppure apri `verification_uri_complete`.

Interroga l'endpoint del token con `grant_type=urn:ietf:params:oauth:grant-type:device_code`, `client_id` e `device_code`, attendendo almeno l'`interval` restituito (5 secondi). Continua in caso di `authorization_pending`. In caso di `slow_down`, usa il nuovo `interval` restituito nella risposta, aumentato di 5 secondi, per ogni richiesta successiva. Interrompi in caso di `access_denied`, `expired_token` o qualsiasi altro errore. Non approvare mai automaticamente un codice dispositivo.

Il client preregistrato `thunderphone-mcp` accetta `http://127.0.0.1/callback` e `http://localhost/callback` su qualsiasi porta. Schema, host, percorso e query devono corrispondere; lo scambio del token deve usare l'esatto URI di reindirizzamento, inclusa la porta, dell'autorizzazione. I client registrati dinamicamente richiedono una corrispondenza esatta dell'URI di reindirizzamento, inclusa la porta. Registra dinamicamente una callback diversa se ti serve un altro percorso.

### Identità dell'account e controlli del dominio del workspace

Richiedi entrambi `openid email` insieme agli scope operativi necessari al tuo client. Chiama il `userinfo_endpoint` individuato (`GET /v1/oauth/userinfo`) con il token di accesso nell'header Bearer. Una risposta riuscita contiene:

```json
{
  "sub": "123",
  "email": "person@example.com",
  "email_verified": true,
  "name": "Example User",
  "org_id": 456
}
```

`sub` è l'identificatore utente stabile; `org_id` è l'organizzazione selezionata durante il consenso. L'endpoint richiede entrambi gli scope di identità e restituisce `403` se ne manca uno. Restituisce `403` con `error=access_denied` se l'account non dispone di un profilo email verificato, anziché dichiarare attendibile un'email non verificata. I token non validi, scaduti, revocati o con audience errata restituiscono `401`. I token di sessione umana e le chiavi API dell'organizzazione non possono chiamare userinfo. Non viene emesso alcun token ID.

## Autorizzazioni disponibili

| Famiglia | Ambiti |
| --- | --- |
| Agenti e importazioni di agenti | `agents:read`, `agents:write` |
| Chiamate | `calls:read`, `calls:write` |
| Numeri di telefono, chiamanti bloccati e VoIP | `numbers:read`, `numbers:write` |
| Knowledge | `knowledge:read`, `knowledge:write` |
| Campagne | `campaigns:read`, `campaigns:write` |
| Integrazioni, endpoint webhook, server MCP | `integrations:read`, `integrations:write` |
| Voci | `voices:read` |
| Scenari di test, esecuzioni di test, convalida | `testing:read`, `testing:write` |
| Fatturazione | `billing:read` |
| Identità dell'account ed email verificata | `openid`, `email` (entrambi obbligatori per userinfo) |
| Connessione persistente | `offline_access` (sempre incluso) |

GET, HEAD e OPTIONS utilizzano scope di lettura; gli altri metodi utilizzano scope di scrittura. Le modifiche alle voci e alla fatturazione non sono disponibili tramite OAuth; `POST /v1/voices/preview` utilizza `voices:read` perché mostra l'anteprima di una voce senza modificarne la configurazione. Gli strumenti MCP applicano lo scope della relativa operazione REST sottostante. I trasferimenti tra organizzazioni vengono negati anche quando l'utente che autorizza appartiene a entrambe le organizzazioni. Altre famiglie API, inclusa la gestione delle chiavi API e le impostazioni degli account umani, non sono disponibili tramite OAuth. Un'autorizzazione mancante per un'operazione REST restituisce `403` con `WWW-Authenticate: Bearer error="insufficient_scope", scope="..."`. I token di accesso non validi o scaduti restituiscono `401`.


### Segnali di autenticazione degli strumenti MCP

Ogni strumento in `tools/list` include `securitySchemes: [{"type": "oauth2", "scopes": ["agents:read"]}]`, con lo scope dell'operazione REST di quello strumento. Gli strumenti di documentazione pubblica utilizzano un elenco di scope vuoto e richiedono comunque una connessione autenticata.

A un token valido privo dello scope di uno strumento viene restituito HTTP `200` con un `result` JSON-RPC contenente `isError: true`, testo esplicativo in `content` e `_meta["mcp/www_authenticate"]`. Quest'ultimo è un array contenente una challenge Bearer con `resource_metadata`, `error="insufficient_scope"`, `error_description` e lo `scope` richiesto. Lo strumento non viene eseguito. Utilizza questa challenge per richiedere un consenso esteso. L'autenticazione mancante o non valida continua a restituire HTTP `401` con `WWW-Authenticate`; gli errori di scope REST continuano a restituire HTTP `403`.

## Conservazione delle credenziali

L'API esegue `python manage.py oauth_cleanup` ogni ora in staging e produzione. Rimuove le richieste di autorizzazione e i codici dispositivo scaduti. I token di accesso scaduti, i codici di autorizzazione e gli hash dei token di aggiornamento vengono eliminati solo dopo la revoca della relativa concessione o quando l'intera famiglia non è più attiva. Gli hash utilizzati vengono conservati finché la famiglia dispone di un token di aggiornamento, codice di autorizzazione, codice dispositivo approvato o token di accesso utilizzabile, così la pulizia non può disabilitare il rilevamento dei replay.
