Ga naar inhoud

App-authenticatie (gb-app/v1)

Doel & URL('s)

Token-gebaseerde login voor de Waarheidsvriend-app (en elke headless client), geleverd door de mu-plugin gb-app-auth (actief op dev/prod). Dit is een samenvatting; de volledige endpoint-specificaties staan in Bestaand API-oppervlak en in de Swagger-documentatie op /api-docs (OpenAPI: /wp-json/custom/v1/openapi).

Basis-URL: /wp-json/gb-app/v1/

Endpoints (kort)

Endpoint Methode Auth Gedrag
/login POST open email + wachtwoord (alias password) → {token_type: "Bearer", access_token, expires_in: 3600, refresh_token, refresh_expires_in: 7776000, user: {id, email, display_name, is_subscriber}}. Fout: altijd generiek 401 "Onjuiste inloggegevens." (geen account-enumeratie). Rate limit: 5 pogingen per 15 minuten per e-mailadres én per IP → 429 "Te veel pogingen…".
/refresh POST open vernieuwbewijs (alias refresh_token) → nieuw tokenpaar; het gebruikte refresh-token vervalt (rotatie). Fout: 401 "Ongeldig vernieuwbewijs."
/logout POST open verwijdert het opgegeven refresh-token; antwoordt altijd {ok: true}.
/me GET Bearer of cookie {id, email, display_name, is_subscriber}; zonder geldig token 401.
/issues/{id}/pdf-link GET Bearer/cookie + rol wv-subscriber kortlevende (5 min) ondertekende PDF-URL; zie Uitgaven-toegang.

Token-mechanisme

  • Access-token: JWT (HS256), payload {sub, iat, exp, typ: "access"}, TTL 1 uur. Signing key = wp_salt('auth') + de wachtwoord-hash van de gebruiker → elke wachtwoordwijziging maakt alle tokens van die gebruiker ongeldig.
  • Refresh-token: opaak ({userId}.{64 hex}), TTL 90 dagen; alleen de hash wordt server-side bewaard (usermeta), maximaal 10 actieve tokens per gebruiker (oudste vervalt eerst).
  • Koppeling met de REST API: een Authorization: Bearer <access_token>- header identificeert de gebruiker op alle WordPress-REST-routes. Daarmee passeren app-clients de REST-afscherming (artikel-/uitgave-routes eisen een ingelogde gebruiker; anders 401 "Authenticatie vereist.") en bepaalt de rol het gb_locked-gedrag: niet-abonnees krijgen artikel-metadata zonder volledige tekst en uitgaven zonder issue_file.

Gedrag & rollen

  • user.is_subscriber in de login-/me-respons weerspiegelt de rol wv-subscriber op dát moment; rolverlies via de abonnee-import werkt direct door bij het eerstvolgende request.
  • Een ongeldig of verlopen Bearer-token maakt het request anoniem (→ 401 op afgeschermde routes), zonder foutdetail over het token.
  • Web-cookiesessies en app-tokens staan los van elkaar; uitloggen op de site raakt app-tokens niet, een wachtwoordwijziging raakt beide.

Acceptatiecriteria

  • Als client POST /wp-json/gb-app/v1/login aanroep met geldige gegevens van een wv-subscriber, dan ontvang ik een tokenpaar met expires_in: 3600, refresh_expires_in: 7776000 en user.is_subscriber: true.
  • Als client inlog met een fout wachtwoord óf een niet-bestaand e-mailadres, dan krijg ik in beide gevallen dezelfde generieke 401 "Onjuiste inloggegevens.".
  • Als client 6× binnen 15 minuten fout inlog op hetzelfde e-mailadres, dan krijg ik 429 "Te veel pogingen…".
  • Als client GET /me aanroep met een geldig Bearer-token, dan krijg ik mijn {id, email, display_name, is_subscriber}; zonder of met ongeldig token 401.
  • Als client POST /refresh aanroep met een geldig refresh-token, dan krijg ik een nieuw tokenpaar en is het oude refresh-token daarna ongeldig (nogmaals refreshen → 401).
  • Als client POST /logout aanroep (met geldig óf ongeldig refresh-token), dan is de respons {ok: true}; een uitgelogd refresh-token kan niet meer refreshen.
  • Als wv-subscriber met Bearer-token wp/v2/wv-articles opvraag, dan is gb_locked: false met volledige content; als niet-abonnee is gb_locked: true zonder artikeltekst.
  • Als gebruiker mijn wachtwoord wijzig (site of reset-flow), dan geven bestaande access- én refresh-tokens daarna 401.

Bekende afwijkingen

Note

Geen bekende defecten. Let op de omgevingsnuance: de mu-plugin is in de lokale legacy-Docker-omgeving niet geladen; testen van gb-app/v1 kan alleen op dev/prod (of een omgeving met Bedrock-structuur). Details en CORS-allowlist: zie Bestaand API-oppervlak.