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.