CORS Configuration
What is CORS?
CORS (Cross-Origin Resource Sharing) is a security mechanism that controls whether your web app running in the WebView can make requests to external servers. When your app tries to fetch data or assets from a different domain, the browser (WebView) enforces the Same-Origin Policy and requires the external server to explicitly allow the request.
When Do You Need CORS?
✅ You need CORS if:
- Your app makes requests to external servers (REST API, GraphQL, CDN assets, etc.)
- Your app fetches data from a backend you control
- Your JavaScript code uses
fetch()orXMLHttpRequestto call external services
❌ You don't need CORS if:
- Your app is completely self-contained (no external requests)
- You only load static resources from CDNs (handled by CSP, not CORS)
- You use native plugins to make HTTP requests (native code bypasses CORS)
Why CORS Exists
CORS prevents malicious websites from stealing your data. Without CORS, any website could make API calls to your bank, email, or social media accounts using your stored credentials.
Example Attack Prevented by CORS
Your App Scenario
How CORS Works in Your App
When your JavaScript code makes an API call, here's what happens:
The Random Port Challenge
Your mobile app's internal server uses a random port that changes every time the app starts:
- First launch:
http://localhost:49152 - Second launch:
http://localhost:51234 - Third launch:
http://localhost:52891
This means you cannot hardcode a specific port in your API server's CORS configuration.
Solution: Allow Any Localhost Port
Configure your API server to dynamically allow any localhost origin. This is secure because:
- ✅ Only your mobile app runs on localhost
- ✅ External websites can't pretend to be localhost
- ✅ Users must have your app installed on their device
- ✅ No network access to localhost from outside the device
Configuring CORS on Your External Server
You must configure CORS on your external server, not in the SaaS dashboard. Below we show a Node.js/Express example, but this works very similarly with other servers and languages like Python (Flask, Django), Go, PHP, Ruby (Rails), Java (Spring), C# (ASP.NET), and more. The key concept is the same: dynamically allow any localhost or 127.0.0.1 origin with any port.
Node.js / Express Example
Option 1: Using the cors package (recommended)
Install the cors package:
Configure dynamic localhost validation:
Option 2: Manual middleware
Required CORS Headers Explained
Access-Control-Allow-Origin
What it does: Specifies which origins can access the resource.
Values:
http://localhost:49152- Specific origin (not useful with random ports)*- Any origin (cannot use with credentials)- Dynamic origin from request (recommended for your app)
Example:
Access-Control-Allow-Methods
What it does: Lists HTTP methods allowed for cross-origin requests.
Example:
Access-Control-Allow-Headers
What it does: Lists headers that can be used in the actual request.
Example:
Access-Control-Allow-Credentials
What it does: Indicates whether credentials (cookies, auth headers) can be sent.
Example:
Important: When using Access-Control-Allow-Credentials: true, you cannot use Access-Control-Allow-Origin: *. You must specify the exact origin.
Preflight Requests
For certain requests (POST, PUT, DELETE, or with custom headers), browsers send a preflight OPTIONS request first to check if the actual request is allowed.
How Preflight Works
Handling Preflight in Your Server
All the code examples above already handle preflight requests by:
- Checking if the request method is
OPTIONS - Returning CORS headers
- Sending a
200 OKstatus code
If you don't handle OPTIONS requests, preflight will fail and your API calls will be blocked.
Testing Your CORS Configuration
Step 1: Test from Your Mobile App
Make an API call from your app's JavaScript:
Step 2: Check Browser Console
Open the WebView console and look for CORS errors:
✅ Success - No errors:
❌ CORS error:
Step 3: Check Network Tab
In the browser developer tools, check the Network tab:
Preflight request (OPTIONS):
- Request Headers:
Origin: http://localhost:49152 - Response Headers should include:
Access-Control-Allow-Origin: http://localhost:49152Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Actual request (GET/POST/etc):
- Request Headers:
Origin: http://localhost:49152 - Response Headers should include:
Access-Control-Allow-Origin: http://localhost:49152
Step 4: Test with curl
Test your CORS configuration from the command line:
Check for Access-Control-Allow-Origin in the response headers.
Common CORS Issues and Solutions
Issue 1: "No 'Access-Control-Allow-Origin' header"
Error:
Cause: Your API server is not sending CORS headers.
Solution: Add CORS middleware to your server (see code examples above).
Issue 2: "Origin is not allowed by Access-Control-Allow-Origin"
Error:
Cause: Your API is allowing a specific port, but your app is using a different port.
Solution: Update your CORS configuration to allow any localhost port (see code examples above).
Issue 3: Credentials Not Working
Error:
Cause: You're using Access-Control-Allow-Origin: * with credentials.
Solution: Use dynamic origin (echo back the request's Origin header):
Issue 4: Preflight Failing
Error:
Cause: Your server is not handling OPTIONS requests properly.
Solution: Add OPTIONS handler that returns CORS headers and 200 status (see code examples above).
Issue 5: Custom Headers Blocked
Error:
Cause: Your custom headers aren't listed in Access-Control-Allow-Headers.
Solution: Add your headers to the allowed list:
Security Best Practices
Do: Validate Localhost Origins
Always check that the origin starts with http://localhost: or http://127.0.0.1::
Don't: Use Wildcards with Credentials
Never use Access-Control-Allow-Origin: * when allowing credentials:
❌ Wrong:
✅ Correct:
Do: Use HTTPS in Production
For production APIs, always use HTTPS to encrypt data in transit:
✅ https://api.yourapp.com
❌ http://api.yourapp.com
Don't: Trust the Origin Header for Authorization
The CORS origin check is done by the browser, not your server. For authorization, always verify tokens or API keys on the server side.
Development vs Production
Development (Permissive)
For development and testing, you can be more permissive:
Production (Strict)
For production, restrict to specific origins:
Quick Reference
Minimum CORS Headers Required
With Credentials
Preflight Response
Summary
Key Points:
- CORS controls whether your app can call external servers (APIs, CDNs, etc.)
- Configure CORS on your API server, not in the SaaS dashboard
- Allow any
localhostor127.0.0.1origin with any port - Handle OPTIONS requests for preflight
- Use HTTPS in production
- Validate origins dynamically
Remember:
- Your app uses a random port - you can't hardcode it
- Allowing any localhost port is secure (only your app uses localhost)
- CORS is enforced by the browser (WebView), not your server
- Use the code examples above for your specific server technology
Next Steps
- Configure CSP for the internal server → Content Security Policy Guide
- Understand the architecture → WebView Architecture Guide