Naar de inhoud

Toegang

Authenticatie

Elk endpoint vraagt een bearer-token, op twee na: de specificatie en de voorwaarden. Een ppl_live_-token werkt op de REST-API en op de MCP-server; een OAuth-token alleen op de MCP-server.

Het token meesturen

Stuur het token mee in de Authorization-header, bij elk verzoek:

http
Authorization: Bearer ppl_live_...

Zonder header, met een onbekend of ingetrokken token krijg je 401 unauthorized. Een geldig token zonder het recht dat het endpoint vraagt krijgt 403 forbidden. Zet een token nooit in een URL of in code die bij gebruikers draait.

Rechten (scopes)

Een token draagt een of meer rechten. Elk endpoint vraagt er precies één; in de referentie staat bij elk endpoint welke.

RechtWie het kan krijgenWat het opent
readElke organisatie in het portaal; via OAuth iedereen (Alleen lezen).De openbare agenda, je eigen events en je token. (16 endpoints)
scanOrganisaties in het portaal; via OAuth de rollen aan de deur.Tickets valideren en op gebruikt zetten aan de deur. (1 endpoint)
attendanceOrganisaties in het portaal; via OAuth de rollen die events bewerken.Aantallen gaan, interesse en tickets van je eigen events, en externe verkoop doorgeven. (3 endpoints)
ticketsOrganisaties in het portaal, voor een koppeling met hun eigen ticketshop. Nooit via OAuth.De ticketlijst van je eigen shop aanleveren, zodat tickets bij de koper in de app komen. (2 endpoints)
adminAlleen het platform zelf, in /admin/api of als beheerder via OAuth.Het werk van het agenda-team.

OAuth 2.1 met PKCE (voor de MCP-server)

Voor de MCP-server is er OAuth 2.1, zodat een assistent kan koppelen zonder dat iemand een token kopieert. Wat er is geïmplementeerd:

  • Authorization code met PKCE, alleen S256. Geen implicit flow en geen wachtwoorden.
  • Dynamische registratie van clients (RFC 7591) op /oauth/register. Een redirect-URI is https, of http op een loopback-adres (localhost, 127.0.0.1, [::1]) met elke poort.
  • Resource indicators (RFC 8707): een token is uitgegeven voor https://partyppl.nl/mcp en werkt nergens anders, ook niet op de REST-API.
  • Metadata volgens RFC 8414 en RFC 9728, en iss in het antwoord (RFC 9207).
  • Een access token (ppl_oat_) leeft 60 minuten; een refresh token (ppl_ort_) 30 dagen en wordt bij elk gebruik vervangen. Een autorisatiecode is 60 seconden geldig en één keer te gebruiken; het verzoek wacht 10 minuten tot de gebruiker heeft ingelogd en ja gezegd.
  • Intrekken via /oauth/revoke (RFC 7009), of door de gebruiker zelf bij Gekoppelde apps in zijn instellingen.

Wat een koppeling mag, beslist de gebruiker op de toestemmingspagina, op basis van zijn rol: Alleen lezen geeft read; een organisatie geeft wat die rol daar mag (read, en attendance en scan voor de rollen die events bewerken of aan de deur staan). Verandert de rol, dan verandert wat het token mag, bij het volgende verzoek. Het recht tickets wordt nooit via OAuth gegeven.

De metadata van de autorisatieserver, zoals deze server hem uitgeeft:

/.well-known/oauth-authorization-server
{
  "issuer": "https://partyppl.nl",
  "authorization_endpoint": "https://partyppl.nl/oauth/authorize",
  "token_endpoint": "https://partyppl.nl/oauth/token",
  "registration_endpoint": "https://partyppl.nl/oauth/register",
  "revocation_endpoint": "https://partyppl.nl/oauth/revoke",
  "response_types_supported": [
    "code"
  ],
  "response_modes_supported": [
    "query"
  ],
  "grant_types_supported": [
    "authorization_code",
    "refresh_token"
  ],
  "token_endpoint_auth_methods_supported": [
    "none",
    "client_secret_post",
    "client_secret_basic"
  ],
  "revocation_endpoint_auth_methods_supported": [
    "none",
    "client_secret_post",
    "client_secret_basic"
  ],
  "code_challenge_methods_supported": [
    "S256"
  ],
  "scopes_supported": [
    "read",
    "attendance",
    "scan",
    "admin"
  ],
  "authorization_response_iss_parameter_supported": true,
  "service_documentation": "https://partyppl.nl/api",
  "ui_locales_supported": [
    "nl",
    "en"
  ]
}

De flow in stappen

Een MCP-client als Claude doet dit zelf. Bouw je je eigen client, dan zijn dit de stappen:

  1. Vraag /mcp zonder token. Het antwoord is 401 met een WWW-Authenticate-header die naar de metadata van de resource wijst.
  2. Lees /.well-known/oauth-protected-resource en daarna /.well-known/oauth-authorization-server.
  3. Registreer je client met POST /oauth/register en bewaar de client_id.
  4. Maak een code_verifier en de bijbehorende code_challenge (SHA-256, base64url), en stuur de gebruiker naar /oauth/authorize met response_type=code, client_id, redirect_uri, code_challenge, code_challenge_method=S256, state en resource.
  5. Na ja komt de gebruiker terug op je redirect_uri met code, state en iss. Controleer state en iss.
  6. Wissel de code in met POST /oauth/token (grant_type=authorization_code, code, redirect_uri, client_id, code_verifier), als application/x-www-form-urlencoded.
  7. Stuur het access token mee naar /mcp. Verlopen? Vraag een nieuw met grant_type=refresh_token.
bash
# 1. PKCE
verifier=$(openssl rand -base64 48 | tr -d '=+/' | cut -c1-64)
challenge=$(printf %s "$verifier" | openssl dgst -sha256 -binary | openssl base64 | tr '+/' '-_' | tr -d '=')

# 2. Register a client
curl -s -X POST "https://partyppl.nl/oauth/register" \
  -H "Content-Type: application/json" \
  -d '{"client_name":"My app","redirect_uris":["http://127.0.0.1:8765/callback"]}'

# 3. Send the person to the consent page (in a browser)
# https://partyppl.nl/oauth/authorize?response_type=code&client_id=$CLIENT_ID
#   &redirect_uri=http%3A%2F%2F127.0.0.1%3A8765%2Fcallback
#   &code_challenge=$challenge&code_challenge_method=S256&state=$STATE
#   &resource=https://partyppl.nl/mcp

# 4. Exchange the code
curl -s -X POST "https://partyppl.nl/oauth/token" \
  -d grant_type=authorization_code -d code="$CODE" -d client_id="$CLIENT_ID" \
  -d redirect_uri=http://127.0.0.1:8765/callback -d code_verifier="$verifier"

Bijgewerkt