What Does CORS Mean?
On This Page
Quick Definition
CORS stands for Cross-Origin Resource Sharing. It is a security feature built into web browsers that prevents a website from making requests to a different website without permission. When a frontend app hosted on one domain tries to fetch data from an API on another domain, the browser checks with the API to see if the request is allowed. If the API sends back the right CORS headers, the browser lets the data through; otherwise, it blocks the request.
Commonly Confused With
Same-origin policy is a stricter browser security feature that completely blocks any cross-origin request from reading the response. CORS is a way to relax the same-origin policy for specific, trusted origins. SOP applies by default; CORS is an opt-in mechanism.
If there is no CORS, the browser enforces SOP and blocks all cross-origin reads. With CORS, the server can say 'I trust this origin' and allow the read.
CSRF is an attack that tricks a user into performing an unwanted action on a trusted site. CORS is not designed to prevent CSRF; in fact, CORS can enable cross-origin requests that might be used in CSRF attacks. CSRF protection relies on tokens or same-site cookies, not on CORS.
CORS allows a legitimate app to read data from another domain. CSRF protection prevents a malicious site from forging a request that the user's browser makes to a trusted site.
JSONP is an older technique to bypass the same-origin policy by injecting a `<script>` tag. It only supports GET requests and requires the server to wrap the response in a callback function. CORS is the modern, standard replacement that supports all HTTP methods and is more secure and flexible.
JSONP: server returns `callback({data})`. CORS: server returns HTTP header `Access-Control-Allow-Origin: *` with the JSON body.
A proxy server forwards requests from the frontend to the backend, making the request same-origin from the browser’s perspective. This avoids CORS entirely. CORS, on the other hand, allows the browser to directly communicate with a different origin without a proxy.
Instead of the browser hitting `api.example.com`, you set up a proxy at `app.example.com/api` that forwards to the API. The browser sees only same-origin requests, so CORS is not needed.
Must Know for Exams
CORS is a recurring topic in the AWS Certified Developer – Associate exam. The exam objectives include “Configure CORS for an S3 bucket” and “Enable CORS on API Gateway.” You will see multiple-choice questions that present a scenario where a static website hosted on S3 cannot load an image from another S3 bucket. The question tests whether you know to add a CORS configuration to the second bucket.
Another common exam question involves API Gateway. For example, a web application calls a REST API through API Gateway, but the browser shows a CORS error. The solution is to enable CORS on the API Gateway endpoint and redeploy. The exam may ask you to identify which header is missing, such as `Access-Control-Allow-Origin` or `Access-Control-Allow-Methods`.
CORS is also tested in the context of CloudFront with Lambda@Edge. You might need to add or modify CORS headers at the edge to allow cross-origin requests from a mobile app. Questions about preflight requests and the OPTIONS method also appear. The exam expects you to know that preflight requests are automatically sent by the browser for non-simple requests and that the server must respond appropriately.
the exam may combine CORS with other topics like IAM policies and bucket policies. For instance, a question might present a scenario where an authenticated user on `app.example.com` tries to upload a file to an S3 bucket via a pre-signed URL. The CORS configuration on the bucket must allow the origin `app.example.com` and the method PUT. You need to understand that CORS and IAM policies work together: CORS allows the browser to read the response, but IAM controls who can perform the action.
To prepare, practice reading the AWS documentation on CORS configurations for S3 and API Gateway. The exam will present the exact header names and values. Also, be aware of the limitation: `Access-Control-Allow-Origin: *` cannot be used with `Access-Control-Allow-Credentials: true`. This specific nuance is a frequent exam trap.
Simple Meaning
Imagine you live in a secure apartment building. You can freely walk into your own apartment, but to enter a neighbor’s apartment, you need their permission. The building’s security guard (the browser) stops you if you try to open their door without a key. CORS is like that security guard’s rulebook.
When you visit a website in your browser, that website is your “origin”, it’s your apartment. Now, suppose that website wants to show you live weather data from a different server, like a weather API. That request is like trying to enter another apartment. The browser checks with the weather server: “Is this website allowed to access your data?” If the weather server says yes by sending special HTTP headers (like a permission slip), the browser lets the data through. If the server says no or doesn’t respond with the right headers, the browser blocks the request, and you don’t get the weather data.
CORS is not a firewall or a server-level security feature; it’s purely a browser behavior. The server itself can receive the request and even send a response, but the browser discards the response if the CORS policy isn’t satisfied. This prevents malicious websites from quietly stealing data from other services while you are logged in. For example, a sketchy forum should not be able to fetch your private emails from your email provider’s API without your email provider’s explicit permission. CORS makes that permission check visible and enforceable.
Full Technical Definition
Cross-Origin Resource Sharing (CORS) is a W3C standard that defines a way for a web server to allow a web browser to access resources from a different origin. An origin is defined by the combination of protocol (HTTP/HTTPS), domain (example.com), and port (443, 8080). If any of these three differ, the request is considered cross-origin.
CORS works through a set of HTTP headers that the server includes in its responses. The most important header is `Access-Control-Allow-Origin`. When a browser makes a cross-origin request, it checks this header in the server’s response. If the header contains the requesting origin (or a wildcard `*`), the browser allows the response to be read by the JavaScript running on the page. If the header is missing or does not match, the browser blocks the response.
There are two types of cross-origin requests: simple requests and preflight requests. Simple requests are HTTP GET, HEAD, or POST requests with no custom headers and with content types limited to `application/x-www-form-urlencoded`, `multipart/form-data`, or `text/plain`. For these, the browser sends the request directly and checks the response headers.
For all other requests, such as those using HTTP methods like PUT, DELETE, or PATCH, or requests that include custom headers like `Authorization` or `X-Requested-With`, the browser first sends a preflight request using the HTTP OPTIONS method. The preflight asks the server: “Are you willing to accept this request?” The server responds with headers like `Access-Control-Allow-Methods` and `Access-Control-Allow-Headers`, which list the allowed HTTP methods and headers. If the server’s response satisfies the browser’s policy, the actual request is sent.
In practice, an AWS Developer Associate candidate must understand how to configure CORS on an S3 bucket, API Gateway, or Lambda function. For example, when a web application hosted on CloudFront tries to fetch a font from an S3 bucket, the S3 bucket must have a CORS configuration that allows the origin of the CloudFront distribution. The configuration specifies allowed origins, methods, and headers, and may also include `Access-Control-Max-Age` to cache the preflight result for a period of time, reducing latency.
CORS is not a replacement for authentication or authorization. It only controls whether the browser can expose the response to the requesting page. The server can still reject the request using application-level logic. CORS does not protect the server from malicious requests made outside the browser, such as curl or Postman, because those tools do not enforce CORS policies.
Real-Life Example
Think of a library with a strict checkout policy. Each library card (origin) is tied to a specific branch. You have a card for the downtown branch. You want to borrow a book from the uptown branch. Uptown has different rules.
You go to the uptown branch front desk (the browser makes the cross-origin request). The uptown librarian (the server) checks your downtown card and says: “I need a permission note from my head office.” The head office checks if downtown branch cards are allowed to borrow books here. That is the preflight request. If the head office says “Yes, downtown cards are allowed for fiction books only,” the librarian lets you check out the book (the browser allows the response).
If the head office says “No, downtown cards are not allowed,” the librarian politely refuses, and you go home empty-handed (the browser blocks the response). The book itself is still on the shelf (the server processed your request), but you cannot take it out because the policy says no.
Now, if you visited the downtown branch instead, you would have no issue at all. That is a same-origin request. CORS is the policy that governs whether a card from one branch can be used at another branch. The card itself is your web application, and the branch is the server. The policy is the CORS headers that the server returns. If you ever try to borrow a book without any card (like a non-browser tool), you can still walk out with the book because nobody checks the policy outside the library.
Why This Term Matters
CORS is critical in modern web development because applications increasingly rely on APIs hosted on different domains. For example, a single-page application (SPA) built with React or Angular might run on `app.example.com` but fetch data from `api.example.com`. Without CORS, the browser would block all requests to the API, making the application unusable.
Understanding CORS is essential for developers who work with cloud services. In AWS, you often need to configure CORS for S3 buckets, API Gateway endpoints, Lambda function URLs, and CloudFront distributions. If a web app cannot load images, fonts, or API responses, the first thing to check is usually the browser’s developer console for CORS errors.
CORS also has security implications. A correctly configured CORS policy protects users from cross-origin data theft. If a developer mistakenly sets `Access-Control-Allow-Origin: *` on a service that handles sensitive data, any website can read the response, potentially exposing user information. AWS Developer Associate exam questions often test this scenario: “What is the security risk of using a wildcard origin with credentials?” The correct answer is that it is not allowed, because the browser will reject it.
CORS can confuse beginners because the error messages in the browser console are often misleading. The request might succeed at the network level, but the browser blocks the response. This leads to wasted debugging time. Knowing how to read network tab headers and configure the server correctly is a fundamental skill. For an IT professional, mastering CORS means faster troubleshooting, secure API design, and the ability to build modern, decoupled architectures.
How It Appears in Exam Questions
CORS questions in the AWS Developer Associate exam appear in three main patterns: configuration, troubleshooting, and security.
Configuration questions present a scenario where a developer must enable cross-origin requests. For example: “A developer hosts a single-page application on Amazon S3 static website hosting. The app needs to fetch data from an API hosted on EC2. What must the developer configure?” The answer usually involves adding a CORS configuration to the API server or using API Gateway with CORS enabled.
Troubleshooting questions describe a situation where the browser console shows a CORS error. The question might list several potential causes: missing header, wrong origin, or the server not responding to OPTIONS. You need to identify the root cause. For instance: “A user reports that the web app fails to load fonts from a CloudFront distribution. The CloudFront access logs show the request was served. What is the most likely issue?” The answer is that the origin (the S3 bucket) does not have a CORS configuration allowing the CloudFront domain, or the response headers are not passed through.
Security-related questions test the limitations of CORS. A classic example: “A developer sets `Access-Control-Allow-Origin: *` on an API that returns a user’s private data. Is this secure?” The correct answer is no, because any website can read the response. The exam may also ask why you cannot combine a wildcard origin with credentials.
Another pattern involves the difference between same-origin and cross-origin requests. A question might ask: “A web app makes a GET request to a different port on the same domain. Is this a cross-origin request?” The answer is yes, because the port differs.
Finally, there are questions about the preflight process. For example: “Why does the browser send an OPTIONS request before a PUT request?” The answer: because the browser must check if the server allows the method and custom headers before sending the actual request. The exam expects you to know that the preflight cache is controlled by the `Access-Control-Max-Age` header.
Practise CORS Questions
Test your understanding with exam-style practice questions.
Example Scenario
Imagine you are building a photo gallery website that displays images stored in an Amazon S3 bucket. Your website is hosted at `www.mygallery.com`, but the images are stored in a bucket named `my-photo-bucket` in the US East region. The bucket is configured for static website hosting at `my-photo-bucket.s3-website-us-east-1.amazonaws.com`.
When a visitor opens your gallery page, the browser tries to fetch the image URLs from the S3 bucket. Because the website origin (`www.mygallery.com`) is different from the bucket origin (`my-photo-bucket.s3-website-us-east-1.amazonaws.com`), the browser sees a cross-origin request. Without CORS, the browser will block the images, and the visitor sees broken image icons.
You, as the developer, need to configure CORS on the `my-photo-bucket` bucket. You go to the S3 bucket permissions and add a CORS configuration that looks like this:
``` [ { "AllowedOrigins": ["https://www.mygallery.com"], "AllowedMethods": ["GET", "HEAD"], "AllowedHeaders": ["*"] } ] ```
This configuration tells the browser: “Allow requests from `https://www.mygallery.com` using GET and HEAD methods.” After saving the configuration, the browser receives the appropriate headers (`Access-Control-Allow-Origin: https://www.mygallery.com`) and allows the images to load.
Now, if a user tries to access your gallery from `https://evil-site.com`, the browser checks the CORS policy of `my-photo-bucket`. The `evil-site.com` origin is not in the `AllowedOrigins` list, so the browser blocks the images. This protects your photo bucket from being accessed by unauthorized websites.
This simple scenario shows why CORS is essential for any web application that uses external resources. Without it, your gallery would not work, and without proper configuration, your data could be exposed.
Common Mistakes
Setting Access-Control-Allow-Origin to * when credentials are included in the request.
The browser will reject the request because the CORS specification forbids combining a wildcard origin with the `Access-Control-Allow-Credentials: true` header. The response must include an explicit origin.
Specify the exact origin, such as `https://example.com`, instead of using `*`. Also ensure the origin matches the requesting page.
Thinking CORS is a server-side security mechanism that prevents unauthorized requests.
CORS is enforced only by the browser. Requests made with tools like cURL, Postman, or server-to-server calls are not affected by CORS at all. A malicious attacker can easily bypass CORS by sending requests from a server.
Implement proper authentication and authorization, such as IAM policies or API keys, on the server side. Use CORS only as a browser-level control, not as the sole protection.
Forgetting to enable CORS on API Gateway after updating the integration.
Even if the backend Lambda function returns the correct CORS headers, API Gateway may strip or override them. The best practice is to enable CORS on the API Gateway resource, which automatically adds the necessary headers in the integration response.
In the API Gateway console, enable CORS for the relevant resource, specify allowed methods and headers, and redeploy the API. Alternatively, configure CORS in the integration response of your API Gateway definition.
Using the same CORS configuration for all environments (development, staging, production).
In development, you might use `http://localhost:3000` as the allowed origin, but if you promote that configuration to production, it will break the production site. Also, using `*` in development might hide real cross-origin issues.
Maintain separate CORS configurations per environment. Use environment variables to inject the correct origin. In development, allow only the localhost origin. In production, allow only the production domain.
Assuming that a successful HTTP request means CORS is not the problem.
The server may process the request and return a 200 OK response, but the browser can still block the response if the CORS headers are missing or incorrect. The error is only visible in the browser console, not in the network tab.
Check the browser developer console for CORS-related error messages. In the Network tab, inspect the response headers of the failing request. Look for `Access-Control-Allow-Origin` and confirm it matches the requesting origin.
Exam Trap — Don't Get Fooled
{"trap":"A question asks: \"A developer sets `Access-Control-Allow-Origin: *` and `Access-Control-Allow-Credentials: true` on an API response. Will the browser accept this?\"","why_learners_choose_it":"Learners may think that the wildcard allows all origins, and credentials are allowed, so the combination should work.
They forget the CORS specification rule that disallows `*` with credentials for security reasons.","how_to_avoid_it":"Remember that `Access-Control-Allow-Origin: *` cannot coexist with `Access-Control-Allow-Credentials: true`. If credentials are needed, the origin must be set explicitly.
The browser will reject the request in this combination. This is a common trick in the AWS Developer Associate exam."
Step-by-Step Breakdown
User visits a web page
The browser loads a page from a specific origin, say `https://myapp.com`. The page includes JavaScript that attempts to make an XMLHttpRequest or fetch to `https://api.example.com/data`.
Browser checks the origin
The browser compares the origin of the requesting page (`https://myapp.com`) with the target URL (`https://api.example.com`). Because the domains, protocols, or ports differ, the browser classifies this as a cross-origin request and begins the CORS process.
Preflight request (if needed)
If the request is not a simple request (e.g., uses PUT, DELETE, or custom headers), the browser sends an HTTP OPTIONS request to the target server. The preflight asks whether the actual request is allowed. The server must respond with headers like `Access-Control-Allow-Methods` and `Access-Control-Allow-Origin`.
Server responds to preflight
The server evaluates the preflight request and returns the appropriate CORS headers. If the server does not respond or responds with insufficient headers, the browser blocks the actual request and shows a CORS error in the console.
Actual request is sent
If the preflight succeeds (or if no preflight was needed), the browser sends the actual request (GET, POST, etc.) to the server. The server processes the request and returns a response, possibly with data.
Browser inspects response headers
After receiving the response, the browser checks the `Access-Control-Allow-Origin` header. If it matches the requesting origin or is `*` (and no credentials are used), the browser allows the JavaScript to read the response. Otherwise, it blocks the response and throws an error.
Request succeeds or is blocked
If all CORS checks pass, the JavaScript receives the data. If any check fails, the browser discards the response and the JavaScript receives an error. The server may have processed the request, but the browser does not expose the result.
Practical Mini-Lesson
CORS is a practical skill you will use almost every day when building web applications with modern frameworks. Let’s walk through a real deployment scenario.
You are building a React application that calls a Node.js REST API running on an EC2 instance. The React app is served by an Nginx reverse proxy on a different domain. When you test locally, everything works because your React dev server proxy bypasses CORS. But once you deploy, users get CORS errors.
First, you need to understand that the API server must include CORS headers in its responses. In your Node.js Express backend, you can use the `cors` npm package. You configure it like this:
```javascript const cors = require('cors'); const express = require('express'); const app = express(); const allowedOrigins = ['https://myapp.com', 'https://www.myapp.com']; app.use(cors({ origin: allowedOrigins, methods: ['GET', 'POST', 'PUT', 'DELETE'], allowedHeaders: ['Content-Type', 'Authorization'] })); ```
This adds the necessary headers to every response. If you need to support credentials (like cookies), you add `credentials: true` but then you cannot use `origin: '*'`.
Now, what about the preflight? The Express `cors` middleware automatically handles OPTIONS requests, so you do not need to write separate code. However, if you are using API Gateway + Lambda, you must explicitly enable CORS on the API Gateway resource. In the API Gateway console, select the resource, click Enable CORS, specify allowed methods, and deploy the API. The console will create an OPTIONS method that returns the proper headers.
What can go wrong? If you use a CloudFront distribution in front of your API, you need to ensure that CloudFront forwards the `Origin` header to the origin. Otherwise, the origin server cannot determine the requesting origin and may respond incorrectly. Also, CloudFront caches responses based on the `Origin` header; if you have multiple origins, set the cache key to include the `Origin` header.
Another pitfall is the `Access-Control-Expose-Headers` header. By default, the browser only exposes a limited set of response headers to JavaScript (like `Cache-Control`, `Content-Type`). If your frontend needs to read a custom header like `X-Request-Id`, you must include it in the `Access-Control-Expose-Headers` list.
For an AWS Developer Associate, you should practice configuring CORS on S3, API Gateway, and CloudFront. Use the AWS Console or CloudFormation. When you get a CORS error, open the browser Network tab, find the failing request, and check the response headers. If you don’t see `Access-Control-Allow-Origin`, the server is not sending it. If you see the header but it does not match your origin, the CORS configuration is wrong.
Finally, remember that CORS is a browser mechanism. For server-to-server communication, you do not need CORS at all. So, if your backend needs to call another API, use environment variables, IAM roles, or API keys, not CORS.
Memory Tip
Think “CORS checks the permission slip before the browser shows you the data.” Permission slip = Access-Control-Allow-Origin header.
Covered in These Exams
Current Exam Context
Current exam versions that test this topic — use these objectives when studying.
Related Glossary Terms
Two-factor authentication (2FA) is a security method that requires two different types of proof before granting access to an account or system.
A/B testing is a controlled experiment that compares two versions of a single variable to determine which one performs better against a predefined metric.
AAA (Authentication, Authorization, and Accounting) is a security framework that controls who can access a network, what they are allowed to do, and tracks what they did.
802.1X is a network access control standard that authenticates devices before they are allowed to connect to a wired or wireless network.
Frequently Asked Questions
Why does the browser send an OPTIONS request before my actual request?
That is the preflight request. The browser sends it to ask the server for permission before sending a non-simple request. It is part of the CORS mechanism to protect against malicious cross-origin requests.
Can I disable CORS in my browser for testing?
Yes, you can use browser extensions or launch the browser with disabled web security, but this is only for local testing. It does not reflect how real users experience your application. Never rely on disabling CORS in production.
What does Access-Control-Allow-Origin: * mean?
It means the server allows any origin to read the response. However, it cannot be used together with credentials. It is a convenient setting for public APIs but not suitable for private data.
Does CORS protect my API from being called by malicious scripts?
Only partially. It prevents the browser from exposing the response to a malicious page, but the request still reaches your server. The malicious script can still trigger actions, especially if the request does not require reading the response (like a POST to delete a record). Always implement server-side authorization.
Why does my S3 static website not load images from another S3 bucket?
Because the browser enforces CORS. You must configure CORS on the source bucket (the one serving the images) to allow the origin of the requesting website. Add a CORS rule with the appropriate AllowedOrigins and AllowedMethods.
What is the difference between CORS and a proxy?
A proxy makes the request appear same-origin, so CORS is not needed. CORS allows direct cross-origin communication by using special headers. Proxies add latency and complexity but can be easier to implement in some architectures.
How do I test CORS configuration?
Use the browser’s developer tools. Make a cross-origin request from a test page or use the Net tab. You can also use online CORS test tools or curl to see if the `Access-Control-Allow-Origin` header is present in the response.
Can I set multiple origins in Access-Control-Allow-Origin?
No. The header only accepts a single origin or `*`. To support multiple origins, you must check the `Origin` header dynamically in your server code and return the matching origin. Some frameworks or API Gateway can handle this with custom logic.
Summary
CORS, or Cross-Origin Resource Sharing, is a browser-based security standard that controls how web pages from one domain can access resources from another domain. It is essential for modern web applications that rely on APIs, cloud storage, and third-party services. The mechanism works through HTTP headers: the server includes `Access-Control-Allow-Origin` in its response, and the browser blocks the response if the header does not match the requesting page’s origin. For non-simple requests, a preflight OPTIONS request is sent first to check permission.
Understanding CORS is crucial for the AWS Certified Developer – Associate exam, where you will encounter questions about configuring S3 buckets, API Gateway, and CloudFront for cross-origin access. Common exam traps include the combination of wildcard origin with credentials, and forgetting to enable CORS on API Gateway. In practice, CORS is often a source of frustration during development, but once you understand the header flow and common misconfigurations, debugging becomes straightforward.
The key takeaway is that CORS is only enforced by browsers, not servers. It is not a replacement for authentication or authorization. As a developer, you must configure both CORS and server-side security to protect your resources. The memory tip “CORS checks the permission slip” can help you remember the core idea. Always test CORS behavior in the browser’s developer tools, and include the necessary headers in your server responses.