Wat 401 betekent (en het verschil met 403)
Een 401 zegt: "je hebt geen of ongeldige credentials meegestuurd — ik weet niet wie je bent". De response bevat altijd een WWW-Authenticate-header die vertelt welk auth-schema de server verwacht:
HTTP/2 401 Unauthorized
WWW-Authenticate: Basic realm="Klantportaal"
Content-Type: text/html
# Of voor een API:
WWW-Authenticate: Bearer realm="api", error="invalid_token"
Een 403 zegt iets anders: "ik weet wie je bent, maar je mag hier niet komen". De server identificeert je succesvol — je hebt geldig ingelogd of een API-key meegestuurd — maar je rol/permissie staat geen toegang toe.
Korte mnemoniek:
- 401 = login overnieuw / login überhaupt
- 403 = je mag hier niet, ook niet met andere credentials
Meer over het verschil staat in mijn artikel over 403-fouten oplossen.
4 plekken waar je 401 tegenkomt
1. .htpasswd-protected directory
Je hebt een staging-omgeving of admin-area afgeschermd met HTTP Basic Auth via .htaccess en .htpasswd. Bezoekers krijgen 401 met een browser-popup voor gebruikersnaam en wachtwoord. Bekend van staging.klant.nl-omgevingen.
2. WordPress REST-API met Application Passwords
Je probeert via curl/Postman/een externe app de WP REST-API te bereiken met basic auth (gebruiker + Application Password). Werkt lokaal, geeft 401 op productie. Vrijwel altijd: hostingomgeving stript de Authorization-header voordat 'ie WordPress bereikt.
3. JWT- of OAuth-API
Token verlopen, ongeldig getekend, of verkeerde scope. De server kan niet bepalen wie je bent op basis van het token, dus 401. Check de token-payload (op jwt.io) en de exp-timestamp.
4. WordPress wp-login.php met te veel pogingen
Sommige security-plugins (Wordfence, iThemes Security) sturen 401 na een aantal mislukte logins, met een Retry-After-header. Geen echte 401-betekenis — eerder rate-limiting met een verkeerde status-code. Eigenlijk hoort dat 429 te zijn.
Veroorzaak nr. 1 in WordPress: gestripte Authorization-header
Het meest voorkomende WordPress-401-issue dat ik tegenkom:
- Je test de REST-API lokaal met Application Passwords — werkt
- Je deployt naar productie (Plesk, cPanel, sommige shared hosters) — geeft 401
- De Authorization-header die je client meestuurt wordt door PHP-FPM of mod_security verwijderd vóórdat WordPress 'm ziet
Fix: voeg deze regel toe aan je .htaccess:
# Forceer doorgifte van de Authorization-header naar PHP
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [E=HTTP_AUTHORIZATION:%1]
</IfModule>
Of via Plesk: "Apache & nginx Settings" → "Additional directives for HTTPS". Daarna PHP herstarten of php_admin_value-cache flushen.
Je kunt 't testen door in een PHP-bestand print_r($_SERVER); uit te voeren met een Authorization-header in je request. Zie je 'm niet in $_SERVER? Dan wordt 'ie gestript.
HTTP Basic Auth opzetten met .htpasswd
Snelste manier om een directory af te schermen:
Stap 1: genereer .htpasswd
Via mijn htpasswd-generator — voer gebruiker en wachtwoord in, kopieer de regel. Of via command line:
htpasswd -c /pad/naar/.htpasswd gebruikersnaam
# Je krijgt een prompt voor het wachtwoord
Stap 2: plaats .htpasswd boven webroot
Plaats het bestand idealiter boven public_html (bv. /home/jouwsite/.htpasswd), zodat het niet publiek bereikbaar is via een URL.
Stap 3: .htaccess in de te beschermen directory
AuthType Basic
AuthName "Klantportaal — toegang voor klanten"
AuthUserFile /home/jouwsite/.htpasswd
Require valid-user
De waarde van AuthName is wat de bezoeker in de auth-popup ziet. AuthUserFile moet een absoluut pad zijn — relatieve paden werken niet.
Stap 4: testen
Bezoek de URL in een incognito-venster. Je krijgt een browser-popup. Verkeerd wachtwoord = nieuwe popup. Goed wachtwoord = doorgang.
401 in REST-API's: drie soorten auth
HTTP Basic Auth (gebruiker + wachtwoord, base64)
curl -u gebruiker:wachtwoord https://jouwdomein.nl/wp-json/wp/v2/posts
# Of expliciet met Authorization-header
curl -H "Authorization: Basic Z2VicnVpa2VyOndhY2h0d29vcmQ=" \
https://jouwdomein.nl/wp-json/wp/v2/posts
Voor WordPress: gebruik nooit je echte login-wachtwoord. Genereer een Application Password via Profiel > Application Passwords.
Bearer Token (JWT, OAuth)
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5..." \
https://api.jouwdomein.nl/v1/orders
Krijg je 401? Decode het token op jwt.io en check de exp-claim. Verlopen = nieuwe token nodig. Check ook of de iss en aud matchen met je server-config.
API Key (custom header)
curl -H "X-API-Key: ak_live_2A7FxC..." \
https://api.jouwdomein.nl/v1/data
Strikt genomen is dit niet HTTP-standaard auth, maar veel API's sturen wel 401 bij ontbrekende of ongeldige key.
Een 401 die niet zou moeten — debug-stappen
Je verwacht 200 maar krijgt 401. Stappen om de oorzaak te vinden:
- Check of de credentials geldig zijn — test ze in een logged-in browser-sessie
- Check de WWW-Authenticate-header in de 401-response. Staat er
Basic? Stuur Basic Auth.Bearer? Stuur een token. - Print je Request-headers in een debug-tool (Charles, mitmproxy) of kijk in DevTools > Network. Wordt de Authorization-header daadwerkelijk meegestuurd?
- Test op de server-side of de header aankomt:
print_r($_SERVER)in een PHP-script. Zie je 'm niet? → gestript door PHP-FPM/mod_security - Check of de URL klopt: 401 op
/wp-json/wp/v2/users/mekan komen door een verkeerd/wp-json/-pad als je permalinks niet pretty zijn - Check security-plugin-logs: Wordfence/Sucuri kan IP's of user agents 401-en bij verdacht verkeer
Veelgestelde vragen
Wat is het verschil tussen 401 en 403?
401 = "wie ben je?" — geen of ongeldige authenticatie. 403 = "ik weet wie je bent maar je mag hier niet komen". Bij 401 hoort altijd een WWW-Authenticate-header, bij 403 niet.
Mijn WordPress REST-API geeft 401 — wat nu?
Drie veelvoorkomende oorzaken: (1) Authorization-header wordt gestript door je hosting — fix met een .htaccess-regel die 'm doorzet, (2) verlopen nonce, (3) Basic Auth op een endpoint dat alleen JWT accepteert. Test eerst met een logged-in browser of cookie-auth wel werkt.
Hoe maak ik een wachtwoord-beveiligde directory met .htpasswd?
Genereer een .htpasswd via mijn htpasswd-generator, plaats 'm boven public_html, en zet in de te beschermen directory een .htaccess met AuthType Basic, AuthUserFile (absoluut pad), en Require valid-user.
Browser blijft 401 geven na correcte login — hoe stop ik dat?
Browsers cachen Basic Auth-credentials per session. Sluit de browser of gebruik incognito. Voor specifiek wissen: in Chrome via Browse-gegevens wissen > Wachtwoorden en andere inloggegevens. Of forceer logout met https://verkeerd:verkeerd@jouwdomein.nl/.
Geeft 401 SEO-problemen?
Niet als 'ie correct gebruikt wordt voor admin- en klantportalen — Google indexeert die URLs niet. Probleem wordt 't als per ongeluk je hele site 401 geeft door een vergeten staging-blokkade. Check productie altijd zonder cookies na een deploy.