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 hetgb_locked-gedrag: niet-abonnees krijgen artikel-metadata zonder volledige tekst en uitgaven zonderissue_file.
Gedrag & rollen¶
user.is_subscriberin de login-/me-respons weerspiegelt de rolwv-subscriberop 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/loginaanroep met geldige gegevens van een wv-subscriber, dan ontvang ik een tokenpaar metexpires_in: 3600,refresh_expires_in: 7776000enuser.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 /meaanroep met een geldig Bearer-token, dan krijg ik mijn{id, email, display_name, is_subscriber}; zonder of met ongeldig token 401. - Als client
POST /refreshaanroep 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 /logoutaanroep (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-articlesopvraag, dan isgb_locked: falsemet volledige content; als niet-abonnee isgb_locked: truezonder 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.