jypi
  • Explore
ChatWays to LearnMind mapAbout

jypi

  • About Us
  • Our Mission
  • Team
  • Careers

Resources

  • Ways to Learn
  • Mind map
  • Blog
  • Help Center
  • Community Guidelines
  • Contributor Guide

Legal

  • Terms of Service
  • Privacy Policy
  • Cookie Policy
  • Content Policy

Connect

  • Twitter
  • Discord
  • Instagram
  • Contact Us
jypi

© 2026 jypi. All rights reserved.

CS50 - Web Programming with Python and JavaScript
Chapters

1Orientation and Web Foundations

2Tools, Workflow, and Git

3HTML5 and Semantic Structure

4CSS3, Layouts, and Responsive Design

5Python Fundamentals for the Web

6Flask, Routing, and Templates

7Data, SQL, and ORM Patterns

8State, Sessions, and Authentication

9JavaScript Essentials and the DOM

10Asynchronous JS, APIs, and JSON

Fetch API fundamentalsPromises chaining and errorsAsync await patternsJSON parsing and schemasCORS and preflight requestsRESTful API design basicsWebSockets and realtimeServer Sent Events overviewFormData and uploadsDebouncing and throttlingPagination and infinite scrollCaching and ETagsRate limits and retriesClient side routing basicsProgressive web app concepts

11Frontend Components and React Basics

12Testing, Security, and Deployment

Courses/CS50 - Web Programming with Python and JavaScript/Asynchronous JS, APIs, and JSON

Asynchronous JS, APIs, and JSON

26875 views

Fetch and process data asynchronously, design and consume APIs, and add realtime features.

Content

5 of 15

CORS and preflight requests

CORS and Preflight Requests Explained for Web Developers
2786 views
intermediate
humorous
web development
javascript
gpt-5-mini
2786 views

Versions:

CORS and Preflight Requests Explained for Web Developers

Watch & Learn

AI-discovered learning video

Sign in to watch the learning video for this topic.

Sign inSign up free

Start learning for free

Sign up to save progress, unlock study materials, and track your learning.

  • Bookmark content and pick up later
  • AI-generated study materials
  • Flashcards, timelines, and more
  • Progress tracking and certificates

Free to join · No credit card required

CORS and Preflight Requests — Why the Browser Plays Gatekeeper

"The browser is not being annoying — it's protecting your users from someone else's sketchy API."

You're coming off async/await flows and happily parsing JSON responses (nice work!), and now the browser slams the door when you try to fetch data from another origin. Welcome to CORS and preflight requests — the part of web development that sounds like a security feature and feels like a bureaucracy. Let's make it make sense.


What is CORS, in one dramatic sentence?

CORS (Cross-Origin Resource Sharing) is a browser security mechanism that decides whether a web page at origin A is allowed to access resources from origin B. If the server at B doesn't explicitly say "it's okay", the browser blocks the response — not the network request.

Why this matters: without CORS, a malicious page could read private data from another site (cookies, APIs) just because your browser happens to be logged in. So the browser acts like a bouncer asking for ID.


Quick recap connections (building on what you already know)

  • You've used fetch with async/await: const res = await fetch(url); const data = await res.json(); — good.
  • You've parsed JSON and used schemas to validate data shapes — also good.

Now: some fetch calls cause the browser to send a preflight (an extra request) before the real request. That preflight must be answered by the server with the right headers for the real request to proceed.


Simple requests vs. requests that trigger preflight

Browsers allow simple requests without preflight. A request is simple if all of these are true:

  • Method is GET, POST, or HEAD
  • Allowed Content-Type: text/plain, multipart/form-data, or application/x-www-form-urlencoded
  • You don't use custom headers (like X-My-App) or authentication headers like Authorization

If any of those are violated (e.g., you POST JSON with Content-Type: application/json, or use PUT, or add a custom header), the browser first sends an OPTIONS request — the preflight.

Imagine it like a club entrance

  • Simple request: you walk in, bouncer nods.
  • Non-simple: bouncer radios the manager (preflight OPTIONS). Manager checks the guest list (server checks headers). Manager says "OK" (Access-Control-Allow-Origin), or "Nope" (blocked).

Anatomy of the preflight (what actually happens)

  1. Browser sends an OPTIONS request to the target URL.
    • Includes Origin header (where request is coming from)
    • Includes Access-Control-Request-Method and Access-Control-Request-Headers describing the real request
  2. Server responds to OPTIONS with CORS headers telling the browser what's allowed
    • If acceptable, browser proceeds to the real request
    • If not, browser blocks the response (your JS never gets access)

Important response headers the server should supply:

  • Access-Control-Allow-Origin: https://your-site.com (or * in permissive cases)
  • Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
  • Access-Control-Allow-Headers: Content-Type, Authorization, X-My-App
  • Access-Control-Allow-Credentials: true (if you need cookies)
  • Access-Control-Max-Age: 600 (cache preflight for 10 minutes)

Practical examples

The client (JS) - triggers preflight because we send JSON and a custom header

// triggers preflight because Content-Type is application/json
const res = await fetch('https://api.example.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-My-App': 'cs50-demo'
  },
  body: JSON.stringify({ name: 'Ada Lovelace' }),
  credentials: 'include' // cookies — means server must allow credentials
});

const result = await res.json();
console.log(result);

The server (Express) — answering the preflight

// Node + Express minimal CORS handling
app.options('/data', (req, res) => {
  res.set({
    'Access-Control-Allow-Origin': 'https://your-frontend.com',
    'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
    'Access-Control-Allow-Headers': 'Content-Type, X-My-App',
    'Access-Control-Allow-Credentials': 'true',
    'Access-Control-Max-Age': '600'
  });
  return res.sendStatus(204); // no content
});

app.post('/data', (req, res) => {
  // normal handling
  res.json({ ok: true });
});

Flask example (Python):

from flask import Flask, request, make_response

@app.route('/data', methods=['OPTIONS', 'POST'])
def data():
    if request.method == 'OPTIONS':
        resp = make_response('', 204)
        resp.headers['Access-Control-Allow-Origin'] = 'https://your-frontend.com'
        resp.headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
        resp.headers['Access-Control-Allow-Headers'] = 'Content-Type, X-My-App'
        resp.headers['Access-Control-Allow-Credentials'] = 'true'
        return resp
    # POST handling
    return {'ok': True}

Cookies, credentials, and a pitfall to avoid

If your fetch uses credentials: 'include' (or same-origin), the server must:

  • Set Access-Control-Allow-Credentials: true
  • NOT set Access-Control-Allow-Origin: * — it must echo the specific origin

If you set * and Allow-Credentials: true, the browser will reject it. The server must return the actual origin string.


Debugging tips (because the console error is your enemy and also your teacher)

  • Check browser console: it shows CORS errors and often the missing header.
  • Network tab → look at the OPTIONS request and response to see which header is absent.
  • If OPTIONS returns 404 or 500, your server isn't handling preflight — add an OPTIONS handler.
  • Use curl -I to inspect headers (but remember curl doesn't enforce CORS — only browsers do). Example:
    curl -i -X OPTIONS https://api.example.com/data -H "Origin: https://your-frontend.com"

Quick checklist: How to fix CORS problems

  1. Identify whether a preflight is sent (Network tab).
  2. Ensure server responds to OPTIONS with the right Access-Control-* headers.
  3. If using credentials, return a specific origin (not *) and set Allow-Credentials: true.
  4. If you control client code, avoid unnecessary custom headers/methods or use application/x-www-form-urlencoded when possible — but don’t compromise security.
  5. Use CORS libraries (e.g., cors in Express) for sane defaults during development, but configure origins for production.

Key takeaways (so this sticks in your brain like a good meme)

  • CORS is a browser-enforced safety policy. Servers must opt into allowing cross-origin access.
  • Preflight = OPTIONS request the browser sends when a request is "non-simple".
  • Server must reply with Access-Control-Allow- headers* that match the request.
  • Use specific origins when credentials are involved — wildcard won't cut it.

Final thought: You've already mastered async/await and JSON parsing — now think of CORS as the handshake step. Your fetch waits politely while the server shows its ID. Once both sides nod, the real conversation begins.


Tags: intermediate, humorous, web development, javascript

Flashcards
Mind Map
Speed Challenge

Comments (0)

Please sign in to leave a comment.

No comments yet. Be the first to comment!

Ready to practice?

Sign up now to study with flashcards, practice questions, and more — and track your progress on this topic.

Study with flashcards, timelines, and more
Earn certificates for completed courses
Bookmark content for later reference
Track your progress across all topics