In order to know if an external origin supports CORS, the server has to send some for the browser to allow the requests.

An origin is the combination of the protocol, domain, and port from which your Ionic app or the external resource is served. For example, apps running in Capacitor have (iOS) or http://localhost (Android) as their origin.

When the origin where your app is served (e.g. with ionic serve) and the origin of the resource being requested (e.g. https://api.example.com) don't match, the browser's takes effect and CORS is required for the request to be made.

CORS errors are common in web apps when a cross-origin request is made but the server doesn't return the required headers in the response (is not CORS-enabled):

By default, when a web app tries to make a cross-origin request the browser sends a preflight request before the actual request. This preflight request is needed in order to know if the external resource supports CORS and if the actual request can be sent safely, since it may impact user data.

A preflight request is sent by the browser if:

  • The method is:
    • PUT
    • DELETE
    • CONNECT
    • OPTIONS
    • TRACE
    • PATCH
  • Or if it has a header other than:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width
  • Or if it has a Content-Type header other than:
    • application/x-www-form-urlencoded
    • multipart/form-data
  • Or if a ReadableStream or event listeners in XMLHttpRequestUpload are used.
    If any of the conditions above are met, a preflight request with the OPTIONS method is sent to the resource URL.

Let's suppose we are making a POST request to a fictional JSON API at https://api.example.com with a Content-Type of application/json. The preflight request would be like this (some default headers omitted for clarity):


If the server is CORS enabled, it will parse the Access-Control-Request-* headers and understand that a POST request is trying to be made from with a custom Content-Type.

The server will then respond to this preflight with which origins, methods, and headers are allowed by using the Access-Control-Allow-* headers:


If the returned origin and method don't match the ones from the actual request, or any of the headers used are not allowed, the request will be blocked by the browser and an error will be shown in the console. Otherwise, the request will be made after the preflight.

Simple requests

Some requests are always considered safe to send and don't need a preflight if they meet all of the following conditions:

  • The method is:
    • GET
    • HEAD
    • POST
  • Have only these headers:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width
  • The Content-Type header is:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain
  • No ReadableStream or event listeners in XMLHttpRequestUpload are used.
    In our example API, GET requests don't need to be preflighted because no JSON data is being sent, and so the app doesn't need to use the header. They will always be simple requests.

Browser Headers (Request)

The browser automatically sends the appropriate headers for CORS in every request to the server, including the preflight requests. Please note that the headers below are for reference only, and should not be set in your app code (the browser will ignore them).

All Requests

HeaderValueDescription
OriginoriginIndicates the origin of the request.

Preflight Requests

The correct and easiest solution is to enable CORS by returning the right response headers from the web server or backend and responding to preflight requests, as it allows to keep using XMLHttpRequest, , or abstractions like HttpClient in Angular.

Ionic apps may be run from different origins, but only one origin can be specified in the Access-Control-Allow-Origin header. Therefore we recommend checking the value of the Origin header from the request and reflecting it in the Access-Control-Allow-Origin header in the response.

Please note that all of the Access-Control-Allow-* headers have to be sent from the server, and don't belong in your app code.

Here are some of the origins your Ionic app may be served from:

Capacitor

PlatformOrigin
iOScapacitor://localhost
Androidhttp://localhost

Replace localhost with your own hostname if you have changed the default in the Capacitor config.

Ionic WebView 3.x plugin on Cordova

Replace localhost with your own hostname if you have changed the default in the plugin config.

Ionic WebView 2.x plugin on Cordova

PlatformOrigin
iOS
Androidhttp://localhost:8080

Replace port 8080 with your own if you have changed the default in the plugin config.

Local development in the browser

Port numbers can be higher if you are serving multiple apps at the same time.

For more information on how to enable CORS in different web and app servers, please check enable-cors.org

CORS can be easily enabled in Express/Connect apps with the middleware:

B. Working around CORS in a server you can't control

Don't leak your keys!

If you are trying to connect to a 3rd-party API, first check in its documentation that is safe to use it directly from the app (client-side) and that it won't leak any secret/private keys or credentials, as it's easy to see them in clear text in Javascript code. Many APIs don't support CORS on purpose, in order to force developers to use them in the server and protect important information or keys.

1. Native-only apps (iOS/Android)

Use the to make the requests natively from outside the webview. Please note that this plugin doesn't work in the browser, so the development and testing of the app must always be done in a device or simulator going forward.

Usage in Ionic Angular 4

2. Native + PWAs

Send the requests through an HTTP/HTTPS proxy that bypasses them to the external resources and adds the necessary CORS headers to the responses. This proxy must be trusted or under your control, as it will be intercepting most traffic made by the app.

Also, keep in mind that the browser or webview will not receive the original HTTPS certificates but the one being sent from the proxy if it's provided. URLs may need to be rewritten in your code in order to use the proxy.

Check cors-anywhere for a Node.js CORS proxy that can be deployed in your own server. Using free hosted CORS proxies in production is not recommended.

Please be aware that CORS exists for a reason (security of user data and to prevent attacks against your app). It's not possible or advisable to try to disable CORS.

If you are developing a PWA or testing in the browser, using the —disable-web-security flag in Google Chrome or an extension to disable CORS is a really bad idea. You will be exposed to all kind of attacks, you can't ask your users to take the risk, and your app won't work once in production.

Sources