CORS & Cross-Origin Requests

CORS is a browser security mechanism that decides whether JavaScript on one website is allowed to read a response from an API hosted on a different origin.

Learn CORS & Cross-Origin Requests in our free Flask course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…

Part of the free Flask course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

In this lesson you'll learn what the Access-Control-Allow-* headers do, how preflight OPTIONS requests work, and how to enable CORS in Flask — both by hand and with the Flask-CORS extension.

An origin is the combination of scheme, host, and port — https://app.example.com . By default, the browser's same-origin policy stops JavaScript loaded from one origin from reading a response served by another. To permit it, the server adds an Access-Control-Allow-Origin header naming the allowed origin (or * for any).

You can add that header yourself with an after_request hook that runs after every view. The runnable example sets the header and inspects it with the test client.

Output: Allow-Origin: * and the JSON body. With that header present, a browser will let cross-origin JavaScript read the response.

A simple GET only needs Allow-Origin . But for requests with custom headers (like Authorization ) or methods like PUT and DELETE , the browser first sends a preflight OPTIONS request asking permission. The server must answer with Access-Control-Allow-Methods and Access-Control-Allow-Headers .

The example adds all three headers and shows a preflight OPTIONS call returning them, so the browser would then allow the real request.

Output: the allowed methods, the allowed headers, and the specific origin — the trio the browser checks before sending the real PUT, POST, or DELETE.

Writing the after_request hook by hand teaches you what is happening, but in production you reach for the Flask-CORS extension. It handles all the headers, the preflight, per-route configuration, and credentials with a single line. Here is the production setup, shown read-only because it relies on the flask_cors package.

Complete the CORS hook. Replace each ___ to allow a specific origin and the POST method.

❌ "No 'Access-Control-Allow-Origin' header is present"

The browser blocked the read because the server sent no Allow-Origin header. Fix it on the server — add the header or enable Flask-CORS — not in the front-end.

Your server did not answer the OPTIONS preflight with Allow-Methods / Allow-Headers . Allow OPTIONS and return those headers, or let Flask-CORS do it.

You cannot use Allow-Origin: * together with credentials. Name a specific origin and add Allow-Credentials: true .

Echo back the request's Origin only if it is on an allowlist.

Lesson complete — your API plays nicely with front-ends!

You understand origins and the same-origin policy, the Access-Control-Allow-* headers, preflight OPTIONS requests, credentials, and the Flask-CORS one-liner.

🚀 Up next: API Authentication with JWT — secure your endpoints with signed tokens instead of cookies.

Practice quiz

What does CORS stand for?

  • Cross-Origin Resource Sharing
  • Central Origin Routing System
  • Cookie Origin Request Security
  • Cross-Origin Response Standard

Answer: Cross-Origin Resource Sharing. CORS is Cross-Origin Resource Sharing, a browser mechanism for cross-origin requests.

What three parts make up an origin?

  • host, path, query
  • scheme, host, and port
  • domain and cookie only
  • method and URL

Answer: scheme, host, and port. An origin is scheme + host + port, e.g. https://app.example.com.

Which header tells the browser a cross-origin read is allowed?

  • Allow-Cross-Origin
  • X-CORS-Allow
  • Access-Control-Allow-Origin
  • Origin-Permitted

Answer: Access-Control-Allow-Origin. Access-Control-Allow-Origin names the origin (or *) that may read the response.

Where do you fix a CORS error?

  • in the browser settings
  • in the front-end fetch call
  • by disabling JavaScript
  • on the server

Answer: on the server. The browser enforces CORS, but the server grants permission via the Allow headers.

What HTTP method does a preflight request use?

  • OPTIONS
  • GET
  • HEAD
  • TRACE

Answer: OPTIONS. The browser sends an OPTIONS preflight before non-simple requests.

When does the browser send a preflight request?

  • on every GET
  • for custom headers or methods like PUT/DELETE
  • only over HTTP
  • never for JSON

Answer: for custom headers or methods like PUT/DELETE. Non-simple requests (custom headers, PUT/DELETE) trigger a preflight.

Which headers must a preflight response include for a PUT?

  • only Allow-Origin
  • Content-Type only
  • Allow-Methods and Allow-Headers
  • Set-Cookie

Answer: Allow-Methods and Allow-Headers. The preflight answer needs Access-Control-Allow-Methods and Allow-Headers.

Why can't you use Allow-Origin: * with credentials?

  • The wildcard is rejected with credentials
  • It is too slow
  • Credentials require GET
  • The port must match

Answer: The wildcard is rejected with credentials. With credentials you must name a specific origin; * is rejected by the browser.

Which header must be true to allow cookies cross-origin?

  • Access-Control-Allow-Cookies
  • Allow-Origin-Credentials
  • Access-Control-Allow-Credentials
  • Set-Credentials

Answer: Access-Control-Allow-Credentials. Access-Control-Allow-Credentials: true permits credentialed requests.

How do you enable CORS for a whole app with Flask-CORS?

  • app.cors()
  • CORS(app)
  • enable_cors(app)
  • CORS

Answer: CORS(app). Importing CORS from flask_cors and calling CORS(app) enables it everywhere.