← Terug naar kennisbank HOSTING

401 Unauthorized — uitgelegd en opgelost

De HTTP-status die zegt: "ik weet niet wie je bent — stuur authenticatie mee als je hier wil komen". Verwarrend genaamd, want het gaat niet om autorisatie maar om authenticatie: de server vraagt om credentials (wachtwoord, token, API-key). Komt veel voor bij REST-API's, .htpasswd-protected directories, en WordPress sites waar de Authorization-header onderweg verdwijnt. Deze gids legt uit wat 401 precies inhoudt, hoe 't verschilt van 403, en wat de drie meest-voorkomende fixes zijn.

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:

  1. Je test de REST-API lokaal met Application Passwords — werkt
  2. Je deployt naar productie (Plesk, cPanel, sommige shared hosters) — geeft 401
  3. 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:

  1. Check of de credentials geldig zijn — test ze in een logged-in browser-sessie
  2. Check de WWW-Authenticate-header in de 401-response. Staat er Basic? Stuur Basic Auth. Bearer? Stuur een token.
  3. Print je Request-headers in een debug-tool (Charles, mitmproxy) of kijk in DevTools > Network. Wordt de Authorization-header daadwerkelijk meegestuurd?
  4. 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
  5. Check of de URL klopt: 401 op /wp-json/wp/v2/users/me kan komen door een verkeerd /wp-json/-pad als je permalinks niet pretty zijn
  6. 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.