---
title: "Verbinden met OAuth"
description: "Machtiging verlenen aan MCP-clients en de ThunderPhone CLI zonder een API-sleutel te delen."
---

OAuth laat een app verbinding maken met één ThunderPhone-organisatie met de machtigingen die je goedkeurt. Directory-clients moeten standaard OAuth gebruiken. Organisatie-API-sleutels blijven beschikbaar voor clients die een handmatig geconfigureerd Bearer-token vereisen.

## Een verbinding goedkeuren

Start de verbinding in je MCP-client. Log in bij ThunderPhone, controleer de appnaam en aangevraagde machtigingen, kies een organisatie en selecteer **Goedkeuren**. Selecteer **Weigeren** als je de verbinding niet hebt gestart of de app niet vertrouwt. Appnamen worden door hun ontwikkelaars opgegeven en vormen geen verificatiebadge.

Leesmachtigingen geven toegang tot de genoemde gegevens, inclusief opnamen en transcripties wanneer `calls:read` wordt aangevraagd. Schrijfmachtigingen kunnen resources wijzigen of verwijderen; oproepen, campagnes, telefoonaankopen en implementaties kunnen kosten met zich meebrengen of invloed hebben op de productieomgeving. Je organisatierol blijft van toepassing.

Open voor een CLI-verbinding de verificatielink die in je terminal wordt weergegeven, vergelijk de achttekencode, selecteer je organisatie en keur goed. Alleen het openen van de link geeft geen toegang. Codes verlopen na 15 minuten.

## De verbinding met een app verbreken

Open **Organisatie → API-sleutels → Geautoriseerde apps** in het dashboard en kies **Intrekken**. Hiermee trek je de geselecteerde autorisatie voor de huidige organisatie in, inclusief de toegangs- en vernieuwingstokens. Maak opnieuw verbinding vanuit de app als je deze opnieuw wilt autoriseren.

## Detectie voor MCP-clients

Gebruik de server-URL `https://api.thunderphone.com/v1/mcp`. Een verzoek zonder geldige authenticatie ontvangt `401` met:

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

Haal dat document op en haal vervolgens de metagegevens van de autorisatieserver op via `https://api.thunderphone.com/.well-known/oauth-authorization-server`. Metagegevens voor resources zijn ook beschikbaar via `/.well-known/oauth-protected-resource/v1/mcp`. Gebruik de geretourneerde eindpunten in plaats van ze zelf samen te stellen. De resource-id is `https://api.thunderphone.com/v1/mcp`.

De server ondersteunt de autorisatiecodeflow met **S256 PKCE**, roterende refresh-tokens, openbare dynamische clientregistratie, intrekking en de apparaatautorisatiegrant. Er zijn geen clientsecrets of impliciete grants. OpenID-detectie is ook beschikbaar via `/.well-known/openid-configuration`; deze bevat dezelfde velden voor de autorisatieserver plus `subject_types_supported: ["public"]` en het userinfo-eindpunt. ID-tokens en Client ID Metadata Documents (CIMD) worden niet ondersteund.

### Een openbare client registreren

Stuur JSON naar `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"]
}
```

Sla de geretourneerde `client_id` op. Omleidingen moeten HTTPS gebruiken, of HTTP op `127.0.0.1` of `localhost`. Registreer de exacte callback-URI, inclusief poort en pad. Fragmenten en ingesloten inloggegevens worden geweigerd. Optionele `client_uri` en `logo_uri` moeten HTTPS gebruiken; ThunderPhone haalt deze niet op tijdens registratie. Registratie is onderhevig aan rate limiting. Geregistreerde clients verlopen niet en blijven geregistreerd wanneer een verbinding wordt ingetrokken. HTTPS-callbacks omvatten `https://chatgpt.com/connector/oauth/<id>` en `https://chatgpt.com/connector_platform_oauth_redirect`. Elke verbinding kan een eigen client registreren.

### Autorisatiecode

Open het gedetecteerde autorisatie-eindpunt met `client_id`, de exact geregistreerde `redirect_uri`, `response_type=code`, een willekeurige `state`, `scope`, `code_challenge`, `code_challenge_method=S256` en `resource=https://api.thunderphone.com/v1/mcp`. Bereken de challenge als de base64url SHA-256-digest zonder padding van een nieuwe PKCE-verifier met hoge entropie. Controleer de geretourneerde `state` en `iss` voordat je de code uitwisselt. Elk autorisatieantwoord, inclusief weigeringen en protocolfouten, identificeert de uitgever met `iss`, dat exact overeenkomt met de gedetecteerde `issuer`. Fouten voor een ongeldige client of callback worden lokaal geretourneerd zonder om te leiden naar die callback.

Wissel uit via `POST /v1/oauth/token` met formulierversleuteling (JSON wordt ook geaccepteerd):

```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
```

De optionele parameter `resource` wordt geaccepteerd voor zowel autorisatie- als tokenverzoeken, inclusief refresh- en apparaatuitwisselingen. Als deze wordt weggelaten, is de standaardwaarde de gedetecteerde MCP-resource. Als deze aanwezig is, moet deze exact met die resource overeenkomen; andere waarden retourneren `invalid_target`. Access-tokens bevatten die doelgroep en MCP weigert tokens met een ontbrekende of afwijkende doelgroep met `401` en een detectiechallenge.

Autorisatieverzoeken en codes verlopen na 10 minuten. Elk tokenantwoord bevat `access_token`, `token_type` (`Bearer`), `expires_in` (standaard 3600 seconden), `refresh_token`, `scope`, `organization_id` en `organization_name`. Verstuur access-tokens alleen via de header `Authorization: Bearer`. Plaats tokens nooit in URL's, logs, broncodebeheer of chat.

### Vernieuwen en intrekken

Vernieuw met `grant_type=refresh_token`, `client_id`, `refresh_token` en `resource` bij het token-eindpunt. Sla het nieuwe refresh-token atomair op en gebruik het oude niet meer. Refresh-tokens verlopen na 30 dagen zonder succesvolle vernieuwing. Een optionele `scope` kan de verleende machtigingen beperken. `offline_access` wordt altijd opgenomen en refresh-tokens worden altijd uitgegeven. Een eerste verzoek zonder `scope` verleent alleen `offline_access`, dus clients moeten de machtigingen aanvragen die ze nodig hebben.

Hergebruik van codes en hergebruik van geroteerde refresh-tokens trekken de volledige autorisatie in. Serialiseer vernieuwingen binnen een client; het opnieuw afspelen van succesvol uitgewisselde inloggegevens is geen veilige retrystrategie.

Stuur om de verbinding te verbreken `token` en `client_id` naar `POST /v1/oauth/revoke`. Het intrekken van een van beide tokens trekt de bijbehorende autorisatie in, inclusief alle daaruit uitgegeven tokens. Een onbekend token retourneert succes zonder te onthullen of het bestaat. Dashboardsessies kunnen hun eigen autorisaties weergeven via `GET /v1/oauth/grants` en er één intrekken via `DELETE /v1/oauth/grants/<id>`, waarbij `X-ThunderPhone-Org` de organisatie selecteert.

### Apparaatautorisatie

Apparaatautorisatie is beperkt tot vooraf geregistreerde clients; dynamisch geregistreerde clients ontvangen `unauthorized_client`. De vooraf geregistreerde openbare client `thunderphone-cli` ondersteunt apparaatautorisatie en vernieuwing. Stuur `client_id=thunderphone-cli` en `scope` naar `POST /v1/oauth/device/code`. Toon `user_code` en `verification_uri` aan de gebruiker, of open `verification_uri_complete`.

Poll het token-eindpunt met `grant_type=urn:ietf:params:oauth:grant-type:device_code`, `client_id` en `device_code`, en wacht ten minste het geretourneerde `interval` (5 seconden). Ga door bij `authorization_pending`. Gebruik bij `slow_down` het nieuwe `interval` dat in het antwoord wordt geretourneerd (met 5 seconden verhoogd) voor elk volgend verzoek. Stop bij `access_denied`, `expired_token` of een andere fout. Keur een apparaatcode nooit automatisch goed.

De vooraf geregistreerde client `thunderphone-mcp` accepteert `http://127.0.0.1/callback` en `http://localhost/callback` op elke poort. Schema, host, pad en query moeten overeenkomen; de tokenuitwisseling moet de exacte omleidings-URI gebruiken, inclusief poort, uit de autorisatie. Dynamisch geregistreerde clients vereisen een exacte overeenkomst met de omleidings-URI, inclusief de poort. Registreer dynamisch een andere callback als je een ander pad nodig hebt.

### Accountidentiteit en controles van werkruimtedomeinen

Vraag zowel `openid email` aan naast de bewerkingsscopes die je client nodig heeft. Roep het gedetecteerde `userinfo_endpoint` (`GET /v1/oauth/userinfo`) aan met het access-token in de Bearer-header. Een succesvol antwoord bevat:

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

`sub` is de stabiele gebruikers-id; `org_id` is de organisatie die tijdens toestemming is geselecteerd. Het eindpunt vereist beide identiteitsscopes en retourneert `403` als een van beide ontbreekt. Het retourneert `403` met `error=access_denied` als het account geen geverifieerd e-mailprofiel heeft, in plaats van te stellen dat een niet-geverifieerd e-mailadres vertrouwd is. Ongeldige, verlopen, ingetrokken tokens of tokens met een verkeerde doelgroep retourneren `401`. Tokens voor menselijke sessies en API-sleutels van organisaties kunnen userinfo niet aanroepen. Er wordt geen ID-token uitgegeven.

## Beschikbare machtigingen

| Familie | Scopes |
| --- | --- |
| Agenten en agentimporten | `agents:read`, `agents:write` |
| Oproepen | `calls:read`, `calls:write` |
| Telefoonnummers, geblokkeerde bellers en VoIP | `numbers:read`, `numbers:write` |
| Kennis | `knowledge:read`, `knowledge:write` |
| Campagnes | `campaigns:read`, `campaigns:write` |
| Integraties, webhookeindpunten, MCP-servers | `integrations:read`, `integrations:write` |
| Stemmen | `voices:read` |
| Testscenario's, testruns, validatie | `testing:read`, `testing:write` |
| Facturering | `billing:read` |
| Accountidentiteit en geverifieerd e-mailadres | `openid`, `email` (beide vereist voor userinfo) |
| Permanente verbinding | `offline_access` (altijd inbegrepen) |

GET, HEAD en OPTIONS gebruiken leesscopes; andere methoden gebruiken schrijfscope. Mutaties van stemmen en facturering zijn niet beschikbaar via OAuth; `POST /v1/voices/preview` gebruikt `voices:read` omdat hiermee een stem wordt beluisterd zonder de configuratie te wijzigen. MCP-tools handhaven de scope van de onderliggende REST-bewerking. Overdrachten tussen organisaties worden geweigerd, zelfs wanneer de autoriserende gebruiker bij beide organisaties hoort. Andere API-families, waaronder API-sleutelbeheer en instellingen voor menselijke accounts, zijn niet beschikbaar via OAuth. Een ontbrekende machtiging voor een REST-bewerking retourneert `403` met `WWW-Authenticate: Bearer error="insufficient_scope", scope="..."`. Ongeldige of verlopen toegangstokens retourneren `401`.


### MCP-toolverificatiesignalen

Elke tool in `tools/list` bevat `securitySchemes: [{"type": "oauth2", "scopes": ["agents:read"]}]`, met de scope van de REST-bewerking van die tool. Openbare documentatietools gebruiken een lege scopelijst en vereisen nog steeds een geverifieerde verbinding.

Een geldig token zonder de scope van een tool ontvangt HTTP `200` met een JSON-RPC-`result` dat `isError: true`, toelichtende tekst in `content` en `_meta["mcp/www_authenticate"]` bevat. Dit laatste is een array met een Bearer-challenge met `resource_metadata`, `error="insufficient_scope"`, `error_description` en de vereiste `scope`. De tool wordt niet uitgevoerd. Gebruik deze challenge om uitgebreide toestemming aan te vragen. Ontbrekende of ongeldige verificatie blijft HTTP `401` met `WWW-Authenticate` retourneren; REST-scopefouten blijven HTTP `403` retourneren.

## Bewaren van referenties

De API voert elk uur `python manage.py oauth_cleanup` uit in staging en productie. Hiermee worden verlopen autorisatieverzoeken en apparaatcodes verwijderd. Verlopen toegangstokens, autorisatiecodes en refresh-tokenhashes worden pas verwijderd nadat hun toekenning is ingetrokken of de volledige familie niet meer actief is. Gebruikte hashes blijven bewaard zolang de familie een bruikbaar refresh-token, autorisatiecode, goedgekeurde apparaatcode of toegangstoken heeft, zodat opschoning replaydetectie niet kan uitschakelen.
