Ein Frontend ruft eine API auf – und plötzlich steht in der Konsole „blocked by CORS policy“. Das Problem liegt selten „in der API“, sondern fast immer in der Browser-Regel dahinter. Wer die Mechanik versteht, kann CORS gezielt konfigurieren, statt blind Header zu raten.
In diesem Artikel wird CORS (Cross-Origin Resource Sharing) einfach erklärt: warum es existiert, welche Header wichtig sind und wie typische Fehler sauber behoben werden – ohne die Sicherheit nebenbei auszuschalten.
CORS kurz erklärt: Warum der Browser überhaupt blockiert
Same-Origin-Policy: die Grundregel
Browser schützen Nutzer:innen mit der „Same-Origin-Policy“ (gleicher Ursprung). „Origin“ bedeutet: Protokoll (http/https) + Domain + Port. Wenn eine Website von https://app.example JavaScript ausführt, soll dieses Skript nicht einfach Daten von https://bank.example lesen können. Genau deshalb blockiert der Browser bestimmte Cross-Origin-Zugriffe.
Wichtig: CORS ist ein Browser-Thema, kein Server-Firewall-Thema
Der Server kann eine Anfrage technisch oft ganz normal beantworten. Aber der Browser entscheidet, ob die Antwort an JavaScript „freigegeben“ wird. Ein häufiger Denkfehler: „Ich rufe die API mit Postman ab, also kann es nicht CORS sein.“ Postman ist kein Browser und setzt diese Regel nicht durch.
Welche Requests betroffen sind (und welche nicht)
CORS betrifft vor allem Fetch/XHR-Aufrufe aus dem Browser. Server-zu-Server-Kommunikation (z. B. ein Node.js-Backend ruft eine andere API) ist nicht betroffen. Auch Navigationen (Link klicken, Form submit) haben andere Regeln als JavaScript-Requests – CORS ist hier nicht der gleiche Gatekeeper.
Die wichtigsten CORS-Header verständlich erklärt
Access-Control-Allow-Origin: wer darf zugreifen?
Der zentrale Hebel ist Access-Control-Allow-Origin. Dieser Header sagt dem Browser, welche Origin JavaScript-Zugriff auf die Antwort bekommt.
- Access-Control-Allow-Origin: https://app.example (empfohlen fĂĽr produktive Setups)
- Access-Control-Allow-Origin: * (nur sinnvoll, wenn wirklich öffentlich und ohne Credentials)
Wichtig: Wenn Cookies oder HTTP-Auth im Spiel sind, ist „*“ nicht erlaubt (dazu gleich mehr).
Access-Control-Allow-Methods und Allow-Headers: was ist erlaubt?
Wenn der Browser vorab prüfen muss (Preflight), fragt er: „Darf ich POST senden?“ oder „Darf ich diesen Header mitsenden?“ Dafür sind diese beiden Header relevant:
- Access-Control-Allow-Methods: z. B. GET, POST, PATCH, DELETE
- Access-Control-Allow-Headers: z. B. Content-Type, Authorization
Hier passieren viele Fehler, weil zwar die Origin stimmt, aber der Browser im Preflight „Authorization“ oder einen Custom-Header nicht erlaubt bekommt.
Access-Control-Allow-Credentials: Cookies und Logins
Wenn der Browser Cookies mitsenden oder eine HTTP-Auth verwenden soll, braucht es Access-Control-Allow-Credentials: true. Zusätzlich muss die Origin dann konkret gesetzt werden (kein „*“). Außerdem muss das Frontend den Request explizit mit Credentials ausführen (z. B. fetch mit credentials: include).
Preflight-Requests (OPTIONS) richtig einordnen
Was ist ein Preflight und warum passiert er?
Ein Preflight ist eine automatische OPTIONS-Anfrage des Browsers vor dem eigentlichen Request. Der Browser macht das, wenn der geplante Request nicht als „einfach“ gilt. Beispiele: Methoden wie PUT/PATCH/DELETE, der Authorization-Header oder ein Content-Type wie application/json können dazu führen.
Typisches Symptom: „CORS error“, obwohl der Endpoint existiert
Viele APIs haben für OPTIONS keine Route, oder Middleware blockiert sie. Dann kommt kein gültiger CORS-Response zurück, der Browser bricht ab – und der eigentliche GET/POST wird gar nicht erst gesendet. Im Netzwerk-Tab sieht man dann oft nur die OPTIONS-Anfrage, die fehlschlägt.
Was eine Preflight-Antwort enthalten sollte
Eine korrekte Antwort auf OPTIONS muss nicht den Business-Content liefern, aber sie muss die passenden CORS-Header enthalten und mit einem Erfolgscode antworten. Wichtig ist vor allem, dass die erlaubten Methods und Header zur geplanten Anfrage passen.
Typische CORS-Fehlerbilder und wie sie gelöst werden
Fehler: „No ‚Access-Control-Allow-Origin‘ header“
Das heißt: Der Server liefert entweder gar keinen CORS-Header oder er wird unterwegs entfernt (Reverse Proxy, CDN, Framework-Konfiguration). Lösung: CORS auf dem Server aktivieren – idealerweise zentral (Middleware) und nicht pro Route „zusammenklicken“.
Fehler: „The value of the ‚Access-Control-Allow-Origin‘ header must not be ‚*‘ when credentials mode is ‚include’“
Hier sind Cookies/Session gefragt, aber die Antwort ist zu offen. Lösung: eine konkrete Origin zurückgeben (z. B. https://app.example) und Allow-Credentials aktivieren. Das ist ein Sicherheits-Feature: Mit „*“ und Cookies könnte sonst jede Website im Namen eines eingeloggten Nutzers lesen.
Fehler: Preflight blockiert wegen Allow-Headers
Wenn das Frontend z. B. Authorization sendet, muss der Server diesen Header im Preflight erlauben. Lösung: die tatsächlich verwendeten Header whitelisten (nicht „alles erlauben“, wenn es nicht nötig ist). Bei Frameworks heißt die Option oft „allowedHeaders“ oder ähnlich.
Fehler: CORS funktioniert lokal, aber nicht in Produktion
Häufige Ursachen sind unterschiedliche Domains/Ports, ein Proxy vor der App oder mehrere Umgebungen (Staging, Preview-URLs). Lösung: Origins sauber pflegen (Konfiguration pro Umgebung) und prüfen, ob ein Reverse Proxy (z. B. Nginx) OPTIONS korrekt durchlässt und Header weiterreicht.
Sichere CORS-Konfiguration: pragmatische Regeln fĂĽr den Alltag
Origin-Whitelist statt Wildcard
In produktiven Apps ist eine Liste erlaubter Origins meist die beste Wahl. So bleibt klar, welche Frontends wirklich auf die API zugreifen dürfen. „Wildcard für alles“ spart kurzfristig Zeit, öffnet aber unnötig viele Türen.
Credentials nur aktivieren, wenn sie wirklich gebraucht werden
Wenn Tokens im Authorization-Header genutzt werden (z. B. Bearer Token), sind Cookies oft nicht nötig. Dann kann Allow-Credentials aus bleiben, und das Setup wird einfacher. Wenn Sessions per Cookie verwendet werden, dann Credentials bewusst aktivieren und Origins strikt halten.
CORS nicht mit Auth verwechseln
CORS ist keine Authentifizierung. Es verhindert nicht, dass jemand die API von einem Server aus aufruft. Es verhindert nur, dass beliebige Websites im Browser-Kontext Antworten lesen dĂĽrfen. FĂĽr echte Zugriffskontrolle bleiben Authentifizierung und Berechtigungen entscheidend. FĂĽr saubere Fehlerkommunikation helfen klare HTTP-Statuscodes, siehe API-Design mit Statuscodes.
So geht’s: CORS-Probleme systematisch debuggen
- Origin prüfen: Stimmt Protokoll/Domain/Port exakt? Auch „http“ vs. „https“ zählt.
- Network-Tab öffnen: Gibt es eine OPTIONS-Anfrage vor dem eigentlichen Call? Wenn ja, zuerst diese fixen.
- Response-Header ansehen: Kommen Access-Control-Allow-Origin/Methods/Headers wirklich in der Antwort an?
- Request-Header vergleichen: Welche Header sendet das Frontend tatsächlich (z. B. Authorization, Content-Type)?
- Credentials klären: Werden Cookies benötigt? Dann Allow-Credentials + konkrete Origin setzen und im Frontend „include“ aktivieren.
- Proxy/CDN testen: Falls ein Reverse Proxy davor liegt: Werden OPTIONS und Header korrekt durchgereicht?
Entscheidungshilfe: Braucht es Preflight, Cookies oder beides?
- Wird ein Authorization-Header oder application/json gesendet?
- Ja: Preflight ist wahrscheinlich. OPTIONS muss funktionieren und Allow-Headers muss passen.
- Nein: Es kann ein „einfacher“ Request sein, der ohne Preflight auskommt (abhängig von Methode und Headern).
- Sollen Cookies/Sessions mitgeschickt werden?
- Ja: Allow-Credentials aktivieren und Allow-Origin darf nicht „*“ sein.
- Nein: Credentials aus lassen, Setup bleibt einfacher.
- Gibt es mehrere Frontends (z. B. App + Admin)?
- Ja: Eine gepflegte Origin-Whitelist nutzen, pro Umgebung konfigurierbar.
- Nein: Eine feste Origin ist oft ausreichend.
Mini-Fallbeispiel: Frontend auf Vercel, API auf eigener Domain
Ausgangslage
Das Frontend läuft auf einer eigenen Domain (z. B. app.example) oder auf einer Hosting-Plattform mit Preview-URLs. Die API liegt auf api.example. Der Browser sieht das als Cross-Origin.
Saubere Lösung in der Praxis
Für Produktion wird nur die echte App-Origin erlaubt. Für Entwicklung lokal kommt zusätzlich http://localhost:3000 dazu. Falls Preview-URLs genutzt werden, sollten diese nicht pauschal mit Wildcard freigeschaltet werden, sondern gezielt über eine kontrollierte Liste oder einen klaren Staging-Mechanismus.
Wenn zusätzlich Cookies verwendet werden, muss die API die konkrete Origin spiegeln (nicht „*“) und Allow-Credentials aktivieren. Hier lohnt es sich, die Entscheidung „Cookies vs. Token“ bewusst zu treffen, weil sie CORS direkt beeinflusst.
FAQ: Häufige Fragen zu CORS im Alltag
Kann CORS im Browser „deaktiviert“ werden?
In normalen Browsern für echte Nutzer:innen nicht sinnvoll. Es gibt zwar Entwicklertools/Flags, aber das löst kein Produktionsproblem. Die Lösung liegt in der Server-Konfiguration.
Ist CORS ein Sicherheitsrisiko?
Eine zu offene CORS-Policy kann riskant sein, vor allem mit Credentials. Eine sinnvolle Policy ist dagegen ein Sicherheitsgewinn, weil sie Browser-Zugriffe kontrollierter macht. Authentifizierung und Berechtigungen bleiben trotzdem Pflicht.
Warum klappt der Aufruf mit curl, aber nicht im Browser?
curl ist kein Browser und erzwingt die Same-Origin-Policy nicht. Der Server antwortet, aber der Browser blockiert den Zugriff von JavaScript auf die Antwort, wenn CORS nicht passt.
Hängen CORS und HTTP-Header zusammen?
Ja: CORS wird über HTTP-Header gesteuert. Wer Header-Grundlagen auffrischen möchte, findet passende Beispiele in HTTP-Request-Header verstehen.
Empfehlung der Redaktion: CORS sauber halten, nicht „freischalten“
Eine gute CORS-Konfiguration ist klein, bewusst und überprüfbar: konkrete Origins, nur benötigte Methods/Headers und Credentials nur bei echtem Bedarf. Für langfristig wartbare APIs hilft außerdem eine saubere Fehlerbehandlung, z. B. über robuste API-Fehlerbehandlung.

