Practical examples of Flask-CORS: Handling Cross-Origin Requests

If you build APIs with Flask, you will eventually run into browser CORS errors. That’s where Flask-CORS comes in. In this guide, we’ll walk through practical, real-world examples of Flask-CORS: handling cross-origin requests without losing your mind or your security posture. Instead of vague theory, you’ll see how to configure CORS for local development, production APIs, single-page apps, and authenticated requests. Modern frontend frameworks like React, Vue, and Angular almost always run on a different origin than your Flask backend during development. That mismatch is the perfect breeding ground for CORS headaches. By walking through concrete examples of Flask-CORS: handling cross-origin requests, you’ll learn how to avoid the usual misconfigurations, how to lock things down for production, and how to debug when browsers complain. If you’ve ever stared at “has been blocked by CORS policy” in your console, this article is written for you.
Written by
Jamie
Published

Let’s skip the abstract talk and go straight into real examples of Flask-CORS: handling cross-origin requests in situations you actually face as a developer. All of these examples build on the same basic pattern: install Flask-CORS, initialize it, then tighten the configuration around your real needs.

pip install flask flask-cors
from flask import Flask, jsonify
from flask_cors import CORS

app = Flask(__name__)
CORS(app)  # very open config – good for quick experiments only

@app.route("/ping")
def ping():
    return jsonify({"status": "ok"})

if __name__ == "__main__":
    app.run(debug=True)

This is the classic hello-world example of Flask-CORS: handling cross-origin requests from any domain. It’s fine for a quick prototype, but not something you should ship to production.


Example of Flask-CORS for local React + Flask development

The most common real example of Flask-CORS: handling cross-origin requests is a React frontend on http://localhost:3000 talking to a Flask API on http://127.0.0.1:5000.

Without CORS, your browser blocks these requests. With a targeted Flask-CORS config, you explicitly allow that frontend origin and keep everything else out.

from flask import Flask, jsonify
from flask_cors import CORS

app = Flask(__name__)

CORS(
    app,
    resources={r"/api/*": {"origins": "http://localhost:3000"}},
    supports_credentials=False,
)

@app.route("/api/user")
def get_user():
    return jsonify({"id": 1, "name": "Jamie"})

if __name__ == "__main__":
    app.run(debug=True)

Here, only routes under /api/ are CORS-enabled, and only for your React dev origin. That’s a much safer pattern than spraying CORS(app) across the entire app.

Why this matters in 2024–2025: most teams use separate frontend and backend repos. Local dev almost always involves multiple ports, so a clean, origin-specific configuration like this is now the default pattern for serious projects.


Best examples of Flask-CORS: handling cross-origin requests in production APIs

Development is one thing; production is where misconfigured CORS can turn into a security problem. The best examples of Flask-CORS: handling cross-origin requests in production have a few common traits:

  • Only specific trusted domains are allowed
  • Only specific HTTP methods are allowed
  • Only specific headers are exposed
  • Credentials are handled intentionally, not by default

Imagine your production API is at https://api.example.com, and your frontend is at https://app.example.com.

from datetime import timedelta
from flask import Flask, jsonify
from flask_cors import CORS

app = Flask(__name__)

CORS(
    app,
    resources={r"/api/*": {"origins": [
        "https://app.example.com",
        "https://admin.example.com",
    ]}},
    methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["Content-Type", "Authorization"],
    expose_headers=["X-Total-Count"],
    max_age=timedelta(hours=1),
)

@app.route("/api/items")
def items():
#    # X-Total-Count is visible to the browser because of expose_headers
    return ("[]", 200, {"X-Total-Count": "0", "Content-Type": "application/json"})

This example of Flask-CORS configuration shows a production-friendly pattern:

  • Multiple specific origins, not *
  • Allowed methods limited to what the API actually uses
  • Custom headers (Authorization, X-Total-Count) explicitly wired into CORS
  • max_age cutting down preflight traffic for better performance

If you want to read more about how browsers enforce CORS and preflight behavior, the MDN documentation is still the gold standard: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS


Examples of Flask-CORS: handling cross-origin requests with credentials (cookies, auth)

As soon as you introduce login sessions, CSRF protection, or cookies, CORS gets more opinionated. Browsers refuse to send credentials across origins unless both sides agree.

Here’s a realistic example of Flask-CORS: handling cross-origin requests for a cookie-based session between:

  • Frontend: https://app.example.com
  • Backend: https://api.example.com
from flask import Flask, jsonify, session
from flask_cors import CORS

app = Flask(__name__)
app.secret_key = "change-me"  # use a strong secret in real apps

CORS(
    app,
    resources={r"/api/*": {"origins": "https://app.example.com"}},
    supports_credentials=True,
)

@app.route("/api/login")
def login():
    session["user_id"] = 1
    return jsonify({"logged_in": True})

@app.route("/api/me")
def me():
    user_id = session.get("user_id")
    if not user_id:
        return jsonify({"error": "unauthorized"}), 401
    return jsonify({"id": user_id, "name": "Jamie"})

Key points in this example of credentialed CORS:

  • supports_credentials=True is required
  • The browser must send withCredentials: true in fetch or Axios
  • The Access-Control-Allow-Origin header cannot be * when credentials are involved

For modern guidance on cookies, sessions, and security headers, the OWASP Cheat Sheet Series is worth bookmarking: https://cheatsheetseries.owasp.org/


Route-level examples of Flask-CORS: handling cross-origin requests selectively

Sometimes you want most of your API locked down, but a few public endpoints need to be called from many origins. That’s where route-level decorators shine.

from flask import Flask, jsonify
from flask_cors import CORS, cross_origin

app = Flask(__name__)
CORS(app, resources={r"/api/private/*": {"origins": "https://app.example.com"}})

@app.route("/api/private/data")
def private_data():
    return jsonify({"scope": "private"})

@app.route("/api/public/info")
@cross_origin(origins="*")
def public_info():
    return jsonify({"status": "public"})

This pattern is one of the best examples of Flask-CORS: handling cross-origin requests at different security levels in the same app. Sensitive APIs stay restricted, while public, cacheable data can be shared more freely.


Real examples of debugging Flask-CORS: when things go wrong

In 2024–2025, the CORS error messages in Chrome, Firefox, and Safari are more explicit than they used to be, but they can still feel cryptic. Here are some real examples of common misconfigurations and how to fix them.

The wildcard + credentials trap

Symptom:

  • Error in console: The value of the 'Access-Control-Allow-Origin' header in the response must not be '*' when the request's credentials mode is 'include'.

Typical bad config:

CORS(app, supports_credentials=True)  # origins default to '*'

Fix: specify origins explicitly.

CORS(app, supports_credentials=True, origins=["https://app.example.com"])

The missing preflight (OPTIONS) handler

Symptom:

  • Browser sends an OPTIONS request
  • Server returns 404 or 405
  • Console shows CORS preflight failure

Fix: let Flask-CORS handle OPTIONS automatically (default), or enable it if you disabled it.

CORS(app, automatic_options=True)

And make sure your route decorators allow OPTIONS implicitly, for example by not restricting methods too tightly unless you know what you’re doing.

Mixed HTTP/HTTPS origins

Symptom:

  • Works fine in local HTTP
  • Fails in production HTTPS, especially with cookies

Fix: align schemes and cookie flags. When you move to HTTPS, set cookies with Secure=True, and make sure your frontend origin in the CORS config also uses https://.

For deeper reading on HTTPS, cookies, and browser security behavior, the US government’s web security guidance is a surprisingly clear resource: https://https.cio.gov/


Examples include Flask-CORS with blueprints and larger apps

Real projects rarely live in a single app.py file. You might be using blueprints, factory patterns, and multiple services. Here’s a slightly larger example of Flask-CORS: handling cross-origin requests in a modular app.

## app/__init__.py
from flask import Flask
from flask_cors import CORS

cors = CORS()


def create_app(config_object=None):
    app = Flask(__name__)
    if config_object:
        app.config.from_object(config_object)

    cors.init_app(
        app,
        resources={
            r"/api/public/*": {"origins": "*"},
            r"/api/internal/*": {"origins": ["https://app.example.com"]},
        },
    )

    from .public import public_bp
    from .internal import internal_bp

    app.register_blueprint(public_bp, url_prefix="/api/public")
    app.register_blueprint(internal_bp, url_prefix="/api/internal")

    return app
## app/public.py
from flask import Blueprint, jsonify

public_bp = Blueprint("public", __name__)


@public_bp.get("/health")
def health():
    return jsonify({"status": "ok"})
## app/internal.py
from flask import Blueprint, jsonify

internal_bp = Blueprint("internal", __name__)


@internal_bp.get("/stats")
def stats():
    return jsonify({"users": 123})

This structure shows how examples of Flask-CORS: handling cross-origin requests scale up when you have multiple blueprints with different exposure levels.


If you’re building in 2024–2025, your Flask API might be talking to:

  • A React or Vue SPA hosted on a CDN
  • A mobile app using fetch under the hood (WebView, React Native, etc.)
  • A serverless function used as a proxy or aggregation layer

A few modern patterns and examples include:

Static SPA on https://app.example.com + Flask API on https://api.example.com

Use the production-style origin list and credentials pattern from earlier, especially if you’re using OAuth or cookie-based sessions.

Mobile apps

Native mobile apps are not subject to browser CORS in the same way, but if you embed WebViews or run JavaScript in a browser-like environment, you’ll still hit CORS constraints. The same examples of Flask-CORS: handling cross-origin requests apply; the origin might be something like capacitor://localhost or ionic://localhost instead of http://localhost:3000.

Serverless or API gateways

If you front your Flask app with an API gateway (AWS API Gateway, Cloudflare, etc.), you may configure CORS there instead. In that case, keep Flask-CORS turned off or tightly scoped to avoid conflicting headers.


FAQ: examples of Flask-CORS and common questions

Q: Can you show a minimal example of Flask-CORS that only allows GET requests?
Yes. Here’s a very focused example of Flask-CORS: handling cross-origin requests with only GET allowed:

from flask import Flask, jsonify
from flask_cors import CORS

app = Flask(__name__)

CORS(
    app,
    resources={r"/api/*": {"origins": "https://app.example.com"}},
    methods=["GET"],
)

@app.route("/api/read-only")
def read_only():
    return jsonify({"mode": "read-only"})

Q: Do I always need Flask-CORS for mobile apps?
Not always. Native mobile HTTP clients (like URLSession on iOS or OkHttp on Android) don’t enforce browser CORS rules. But if your mobile app embeds a browser or WebView, the same examples of Flask-CORS: handling cross-origin requests still apply.

Q: How do I test that my CORS configuration is correct?
Use your browser’s DevTools Network tab and look at the response headers. You should see Access-Control-Allow-Origin, Access-Control-Allow-Methods, and, when relevant, Access-Control-Allow-Credentials. You can also write small fetch tests in the browser console to simulate real calls.

Q: Are there security risks in using very open CORS configs?
Yes. When you use * for origins and allow credentials, or when you expose sensitive headers, you broaden the attack surface for CSRF-like attacks and data exfiltration. The safer pattern is what you see in the best examples of Flask-CORS: handling cross-origin requests—explicit origins, explicit methods, and explicit headers.

Q: Where can I learn more about HTTP, CORS, and browser behavior?
The MDN Web Docs CORS page is a solid reference, and OWASP’s guidance on web security gives you broader context around cross-origin risks and mitigations.


The bottom line: the strongest examples of Flask-CORS: handling cross-origin requests don’t just “make the error go away.” They encode your trust decisions in code—who can call what, with which methods, from which origins. Once you treat CORS as part of your security design instead of an afterthought, Flask-CORS becomes a very predictable, very boring piece of your stack—which is exactly what you want from security plumbing.

Explore More Flask Code Snippets

Discover more examples and insights in this category.

View All Flask Code Snippets