✦ Oplossingen · Browser- en verbindingsfouten

CORS-fout: No 'Access-Control-Allow-Origin' header is present

‘Blocked by CORS policy: No Access-Control-Allow-Origin header’? Lees waarom de browser dit blokkeert en hoe je CORS goed instelt in nginx, PHP of Express.

Zo ziet de foutmelding eruit

  • Access to fetch at 'https://api.voorbeeld.nl/data' from origin 'https://www.voorbeeld.nl' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
  • Response to preflight request doesn't pass access control check
  • The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
  • Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource
  • (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)

Waarom gebeurt dit?

Browsers volgen de same-origin policy: JavaScript op de ene ‘origin’ mag niet zomaar antwoorden lezen van een andere. Een origin is de combinatie van protocol, domein en poort. https://www.voorbeeld.nl, https://api.voorbeeld.nl en http://localhost:3000 zijn dus drie verschillende origins. Wil een pagina via fetch of XMLHttpRequest gegevens van een andere origin ophalen, dan moet die andere server expliciet toestemming geven. Dat mechanisme heet CORS (Cross-Origin Resource Sharing).

Die toestemming gaat via HTTP-headers in het antwoord van de server, vooral Access-Control-Allow-Origin. Ontbreekt die header, of staat er een andere origin in, dan krijgt jouw JavaScript het antwoord niet te zien en toont de console de fout. Belangrijk: het verzoek kan op de server wél zijn uitgevoerd; de browser houdt alleen het antwoord tegen.

Daarom is dit geen browserbug, en ook niet iets wat je in de JavaScript-code van de pagina kunt oplossen. De server van de API bepaalt wie zijn antwoorden mag lezen. De oplossing hoort dus aan de serverkant, of je laat de aanvraag via je eigen server lopen. Een veelvoorkomende variant: de echte fout is een 404 of 500 van de API, en omdat die foutpagina geen CORS-headers heeft, zie je alleen de CORS-melding.

Zo herken je dit probleem

  • De fout staat in de console van de ontwikkelaarstools (F12) en noemt ‘blocked by CORS policy’.
  • Hetzelfde adres openen in de adresbalk of met curl werkt wel; alleen het ophalen vanuit JavaScript op een andere origin faalt.
  • Noemt de melding ‘preflight’, dan gaat het mis bij een OPTIONS-verzoek dat de browser vooraf stuurt; dat kan ook een 405 Method Not Allowed of 401 op dat OPTIONS-verzoek zijn.
  • Gaat het om een https-pagina die iets via http laadt, dan is het geen CORS maar mixed content.

Zo los je het op, stap voor stap

Menunamen kunnen per versie of toestel iets anders heten. Loop de stappen op volgorde af en stop zodra het werkt.

  1. Lees de volledige melding en het Network-tabblad

    Open de ontwikkelaarstools, ga naar Network en klik op het mislukte verzoek. Kijk naar de statuscode en de antwoordheaders. Is de status 404, 500 of 401, los dan eerst die fout op; de CORS-melding is dan een gevolg. Staat er een apart OPTIONS-verzoek, dan gaat het om de preflight.

  2. Begrijp de preflight

    Bij verzoeken die verder gaan dan een eenvoudige GET of formulier-POST, bijvoorbeeld met Content-Type: application/json, een Authorization-header of de methode PUT of DELETE, stuurt de browser eerst een OPTIONS-verzoek. De server moet daarop antwoorden met een geslaagde status (zoals 204) en de headers Access-Control-Allow-Origin, Access-Control-Allow-Methods en Access-Control-Allow-Headers. Pas daarna volgt het echte verzoek.

  3. Stel de headers in op de server (nginx)

    Geef alleen origins toestemming die je vertrouwt. Gebruik always, zodat de headers ook bij foutantwoorden worden meegestuurd. Let op: zet je ergens in een location een eigen add_header, dan worden headers van een hoger niveau daar niet meer overgenomen. Test daarna met nginx -t en herlaad.

    location /api/ {
        add_header 'Access-Control-Allow-Origin' 'https://www.voorbeeld.nl' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
        add_header 'Vary' 'Origin' always;
    
        if ($request_method = 'OPTIONS') {
            return 204;
        }
        # ... rest van de configuratie (proxy_pass, try_files)
    }
  4. Of in PHP

    Werk je zonder toegang tot de webserver, zet de headers dan bovenaan het PHP-script, vóór enige uitvoer (anders krijg je headers already sent). Controleer de meegestuurde origin tegen een lijst en beantwoord een OPTIONS-verzoek direct.

    <?php
    $toegestaan = ['https://www.voorbeeld.nl', 'http://localhost:3000'];
    $origin = $_SERVER['HTTP_ORIGIN'] ?? '';
    if (in_array($origin, $toegestaan, true)) {
        header('Access-Control-Allow-Origin: ' . $origin);
        header('Vary: Origin');
        header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
        header('Access-Control-Allow-Headers: Content-Type, Authorization');
    }
    if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
        http_response_code(204);
        exit;
    }
  5. Of in Node.js met Express

    Voor Express is er het npm-pakket cors. Geef de toegestane origin op in plaats van alles open te zetten. Het pakket beantwoordt ook de preflight.

    npm install cors
    
    const express = require('express');
    const cors = require('cors');
    const app = express();
    
    app.use(cors({
      origin: ['https://www.voorbeeld.nl'],
      credentials: true
    }));
  6. Let op bij cookies en inloggegevens

    Stuur je cookies of inloggegevens mee (fetch(url, { credentials: 'include' }) of withCredentials), dan mag Access-Control-Allow-Origin geen * zijn. De server moet dan de exacte origin terugsturen én Access-Control-Allow-Credentials: true. Cookies moeten daarnaast zelf geschikt zijn voor gebruik tussen sites (SameSite=None; Secure).

  7. Geen toegang tot de API? Gebruik je eigen server als tussenstation

    Is de API van een ander en geeft die geen CORS-toestemming, dan kun je dat niet vanuit de browser omzeilen. Laat je eigen server de API aanroepen en het resultaat doorgeven aan je pagina, of stel tijdens ontwikkeling een proxy in je ontwikkelserver in. Plugins die CORS in je eigen browser uitschakelen helpen alleen jou, niet je bezoekers, en maken je browser onveiliger.

Let op: Zet niet uit gemak Access-Control-Allow-Origin: * op een API die met cookies of inloggegevens werkt. Kopieer ook nooit blind de Origin-header terug zonder lijst: dan geeft je server elke website toestemming om namens ingelogde bezoekers gegevens te lezen.

Waarom de browser dit blokkeert

Zonder same-origin policy zou elke website die je bezoekt via jouw browser verzoeken kunnen doen naar andere sites waar je bent ingelogd, zoals je webmail of internetbankieren, en de antwoorden kunnen uitlezen. CORS is de gecontroleerde uitzondering daarop: alleen de server die de gegevens heeft, mag bepalen welke andere sites ze mogen lezen.

  • Tools zoals curl of Postman hebben geen same-origin policy en tonen daarom geen CORS-fout.
  • Een fout in de API (404, 500) zonder CORS-headers verschijnt in de browser als CORS-fout.
  • CORS beschermt bezoekers, niet je server: het is geen vervanging voor authenticatie of een firewall.

Wanneer schakel je hulp in?

  • De API is van een externe partij en je weet niet of je een server-side tussenstap nodig hebt.
  • Het werkt lokaal wel maar niet live, of alleen in sommige browsers, en je ziet niet waarom.
  • Je API werkt met inloggen en cookies, en je wilt CORS instellen zonder een beveiligingslek te maken.
  • De webserverconfiguratie wordt gedeeld met andere sites en je wilt niet dat een wijziging iets anders breekt.

Lukt het niet? Wij helpen

Kom je er met deze stappen niet uit, of wil je het liever niet zelf doen? We kijken online mee of komen langs. Hulp op afstand kost €20 per uur; komen we langs, dan is de prijs op aanvraag. Je weet vooraf waar je aan toe bent.

Aanvraag

Hulp aanvragen

Schrijf kort wat er misgaat en wat je al hebt geprobeerd. Kies of we bellen, online meekijken of langskomen.

Veelgestelde vragen

Vragen over dit probleem

Kan ik een CORS-fout oplossen in mijn JavaScript?

Nee. Opties als mode: 'no-cors' zorgen alleen dat je een leeg, onleesbaar antwoord krijgt. De server moet de toestemming geven, of je laat je eigen server het verzoek doen.

Waarom werkt het wel in Postman of met curl?

Die tools hebben geen same-origin policy. Alleen browsers handhaven CORS, omdat zij de cookies en sessies van de gebruiker bewaren.

Mag ik Access-Control-Allow-Origin: * gebruiken?

Voor openbare gegevens zonder inloggen kan dat. Werk je met cookies of inloggegevens, dan staat de browser dat niet toe en moet je de exacte origin opgeven.

Waarom krijg ik ineens een CORS-fout terwijl er niets is veranderd?

Vaak geeft de API een fout (bijvoorbeeld 500 of 502) en heeft die foutpagina geen CORS-headers. Kijk in het tabblad Network naar de echte statuscode.