---
term: 'Cross-Origin Resource Sharing (CORS)'
seoTitle: 'What is CORS? Errors, Preflight & Fixes Explained'
headline: 'What is CORS (Cross-Origin Resource Sharing)?'
slug: cors-cross-origin-resource-sharing
category: api-realtime
shortDefinition: 'CORS is a browser mechanism that lets a server declare which other origins may call it, relaxing the same-origin policy on purpose.'
relatedTerms:
  - api-key-security
  - api-gateway-architecture
  - cross-site-scripting-xss-prevention
contrastsWith:
  - cross-site-scripting-xss-prevention
faq:
  - question: 'What is CORS in simple terms?'
    answer: 'The browser''s permission system for cross-site API calls. By default, scripts on one origin cannot read responses from another — the same-origin policy. CORS is how a server opts in: response headers declaring which origins, methods, and headers it accepts. The browser enforces; the server declares; your frontend code is just the messenger.'
  - question: 'What is an origin, exactly?'
    answer: 'The triplet of scheme, host, and port. https://app.example.com and https://api.example.com are different origins (host differs); so are http and https versions of one site (scheme differs), and :3000 vs :8080 in development (port differs). Every CORS decision compares these three parts — nothing else about the URL matters.'
  - question: 'What causes the classic CORS error?'
    answer: 'The browser called a different origin, and the response lacked an Access-Control-Allow-Origin header matching yours — so the browser blocked your script from reading it. The request often reached the server fine; the block is client-side, on the read. That is why the fix is always server configuration, never frontend code.'
  - question: 'What is a preflight request?'
    answer: 'The browser''s advance permission check for non-simple requests: before sending a PUT, a DELETE, or anything with custom headers like an authorization token, it sends an OPTIONS request asking "may I?" The server''s headers answer which methods, headers, and origins are allowed; only then does the real request fly. Preflights are cacheable via Access-Control-Max-Age.'
  - question: 'Why does my request work in curl but fail in the browser?'
    answer: 'Because CORS is browser enforcement, not server rejection. Tools like curl and native mobile apps have no same-origin policy, so they read the response happily. The browser applies the policy on behalf of its user — the difference you are seeing is the enforcement point, and it is also the proof that CORS is not access control.'
  - question: 'Is Access-Control-Allow-Origin: * safe?'
    answer: 'For genuinely public, credential-free APIs, yes. The wildcard is forbidden in credentialed mode — browsers refuse cookies against it by design — and reflecting arbitrary origins while allowing credentials is the classic misconfiguration that turns CORS from a shield into a hole. Private APIs list origins explicitly.'
  - question: 'Can I just disable CORS to fix the error?'
    answer: 'Only in the sense that removing a smoke alarm fixes a fire. Browser flags and permissive proxies mask the symptom on your machine while shipping the breakage to every user. The correct fix takes minutes: configure the server (or platform dashboard) to allow the origins that should call it.'
  - question: 'What is the difference between CORS, CSRF, and CSP?'
    answer: 'Three different jobs. CORS governs which origins may read responses from a server. CSRF is an attack — riding a user''s cookies to forge requests — countered by tokens and SameSite cookies, not by CORS. CSP is a page''s own policy restricting what it may load and execute, the anti-XSS tool. Adjacent acronyms, orthogonal mechanisms.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'CORS — MDN Web Docs'
    url: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS'
  - name: 'Fetch Standard — CORS protocol (WHATWG)'
    url: 'https://fetch.spec.whatwg.org/#http-cors-protocol'
  - name: 'Same-origin policy — MDN Web Docs'
    url: 'https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy'
  - name: 'Back4app documentation'
    url: 'https://www.back4app.com/docs'
  - name: 'Cross-origin resource sharing — Wikipedia'
    url: 'https://en.wikipedia.org/wiki/Cross-origin_resource_sharing'
cta:
  title: 'Cross-origin that just works'
  text: 'Back4app APIs answer preflights and send correct CORS headers out of the box — your web app calls the backend from any origin you allow, while native apps skip the ceremony entirely. No proxy hacks, ever.'
  linkText: 'Start Free'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-07-27'
translationKey: cors-cross-origin-resource-sharing
---

**CORS is a browser mechanism that lets a server declare which other origins may call it, relaxing the same-origin policy on purpose.** Two reframes dissolve most of the confusion: the *browser* enforces it (not the server, which is why curl works), and the *server* fixes it (not your frontend, which is why no amount of JavaScript helps). Everything else is headers.

## Key takeaways

| Question | Answer |
| --- | --- |
| The foundation | Same-origin policy: scripts can't read other origins' responses by default |
| An origin | scheme + host + port — all three must match |
| CORS | Server headers opting specific origins in; browser enforces |
| Preflight | OPTIONS "may I?" before non-simple requests |
| The eternal truth | CORS errors are fixed on the server, full stop |

## The whole protocol, on the wire

```text
# Preflight: the browser asks before a PUT with an auth header
OPTIONS /classes/Product HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: x-parse-session-token

# The server's permission slip
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com   ← this origin may read
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: x-parse-session-token
Access-Control-Max-Age: 86400        ← cache this answer; skip tomorrow's preflight

# Then, and only then, the real request flies.
```

What it looks like from application code — and the platform truth the tabs teach: CORS is a *browser* concern, which native apps never meet:

**JavaScript:**

```javascript
// Browser JavaScript — Back4app JS SDK
// A cross-origin call that just works: the platform answers the
// preflight and sends the CORS headers, so the browser lets it through
Parse.initialize('APP_ID', 'JS_KEY');
Parse.serverURL = 'https://parseapi.back4app.com'; // different origin than your site

const products = await new Parse.Query('Product').find();
// No proxy hacks, no "disable CORS" — the server side is configured correctly.
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// Native apps have no same-origin policy — CORS is a browser concern.
// Flutter Web, however, DOES enforce it: same browser rules apply there.
final query = QueryBuilder<ParseObject>(ParseObject('Product'));
final response = await query.query();
// Works identically on mobile and web because the server sends CORS headers.
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// No browser, no same-origin policy: CORS never applies to native iOS.
// The same backend serves browsers (with CORS headers) and apps alike.
let query = Product.query()
query.find { result in
  if case .success(let products) = result { render(products) }
}
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// No browser, no same-origin policy: CORS never applies to native Android.
// The same backend serves browsers (with CORS headers) and apps alike.
val query = ParseQuery.getQuery<ParseObject>("Product")
query.findInBackground { products, e ->
  if (e == null) render(products)
}
```

## The flow, decided

```mermaid
flowchart TB
  accTitle: How a browser decides a cross-origin request
  accDescr: Same-origin requests proceed directly; simple cross-origin requests are sent and their response checked for an allow-origin header; non-simple requests trigger an OPTIONS preflight first, and any missing or mismatched header causes the browser to block the response from the page.
  R["Script makes a request"] --> S{"Same origin?"}
  S -- yes --> OK["Proceeds, no CORS involved"]
  S -- no --> T{"Simple request?<br/>(GET/HEAD/POST, safelisted headers)"}
  T -- yes --> D["Send; check response for<br/>Access-Control-Allow-Origin"]
  T -- no --> P["OPTIONS preflight first"]
  P --> D
  D -->|"header matches origin"| OK2["Response readable"]
  D -->|"missing / mismatch"| B["Blocked by the browser<br/>(the console error)"]
```

Two details carry most debugging sessions: a **simple request** (GET/HEAD/POST with safelisted headers and plain content types) skips the preflight — which is why adding an `Authorization` header suddenly "breaks" an endpoint that worked; and **credentialed requests** tighten everything — cookies flow only with `Access-Control-Allow-Credentials: true` *plus* an exact origin, never the wildcard, per [the spec](https://fetch.spec.whatwg.org/#http-cors-protocol).

## How to fix common CORS errors (error → cause → fix)

| Console says | Actually happened | Fix (always server-side) |
| --- | --- | --- |
| No 'Access-Control-Allow-Origin' header | Server never opted your origin in | Add your origin to the allowed list |
| Origin not allowed by Access-Control-Allow-Origin | Allow-list exists; you're not on it | Add the exact scheme+host+port |
| Response to preflight… doesn't pass | OPTIONS unhandled or headers incomplete | Answer OPTIONS with methods/headers |
| Wildcard '*' cannot be used with credentials | Cookies + `*` — forbidden combination | List origins explicitly |
| Request header not allowed | Custom header missing from allow-list | Add it to Access-Control-Allow-Headers |

And the anti-fix worth naming: browser-flag disabling and permissive dev proxies make the error invisible *on your machine only* — the deploy still breaks for users. The real fix is a server configuration measured in minutes.

## Common use cases

- **SPA + API on different origins** — app.example.com calling api.example.com: the everyday case CORS exists for.
- **Local development** — localhost:3000 against a real backend; allow the dev origin, don't disable the shield.
- **Public APIs** — wildcard origin, no credentials: correct and safe for genuinely public data.
- **Multi-frontend platforms** — several apps, one backend, an explicit origin list per environment.
- **BaaS backends** — the platform answers preflights and sends the headers; your job reduces to declaring allowed origins.

## Wildcard vs. explicit origins: a decision matrix

| Configuration | Right when… | Never when… |
| --- | --- | --- |
| Wildcard `*` | Public, credential-free API | Cookies or user sessions exist |
| Explicit origin list | Private APIs, credentialed apps | — (this is the default answer) |
| Reflecting request origins | Almost never | Combined with credentials — the classic hole |
| Per-environment lists | Dev/staging/prod hygiene | Prod inheriting dev's localhost entries |

One security reframe closes the matrix: CORS is **not access control** — native apps and servers ignore it entirely, so it protects *browser users* from malicious sites, not your API from callers. Authentication and [data-layer permissions](/glossary/data-layer-vs-application-layer-security/) do that job; CORS just decides which websites' scripts may read the answers.

## Limitations and trade-offs

- **It only governs browsers.** Anything non-browser walks past it — never mistake an origin list for authorization.
- **Preflights cost a round trip** on non-simple requests; `Access-Control-Max-Age` caching is the cheap, forgotten fix.
- **Misconfiguration fails closed and loud** — good for safety, brutal for debugging without the error→fix table above.
- **Origin lists are environment state.** Staging origins leak into production configs; audit the list like any credential.
- **CORS ≠ CSRF ≠ CSP.** Neighboring acronyms, separate defenses — cookies still need SameSite/token protection, and pages still need a content policy, with CORS handling only the cross-origin read.

## CORS on Back4app

Back4app is an open-source Backend-as-a-Service (BaaS) platform that combines a managed database, auto-generated REST and GraphQL APIs, authentication, file storage, and Cloud Code serverless functions. The CORS chore ships handled: platform APIs answer preflights and send correct headers, so browser apps call the backend from allowed origins without proxy hacks — the JavaScript tab above is the entire experience — while the Flutter, Swift, and Kotlin tabs demonstrate the quieter truth that native clients never meet the ceremony at all. Real security stays where it belongs: sessions, ACLs, and class-level permissions enforced server-side on every request, from every origin.
