Solving CORS Issues in API Configuration
Cross-Origin Resource Sharing (CORS) problems are among the most common challenges developers face when connecting frontend applications to APIs. These issues arise when the server isn’t properly configured to accept requests from your application’s origin.
Understanding CORS Errors
A typical CORS error looks like:
Access to fetch at 'https://api.example.com' from origin 'https://your-app.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present
on the requested resource.
Common Causes of CORS Issues
- Missing CORS headers on server responses
- Incorrect allowed origins configuration
- Unhandled preflight (OPTIONS) requests
- Missing credentials when using cookies/auth
- Disallowed HTTP methods or headers
Server-Side Solutions
1. Express.js Configuration
const express = require('express');
const cors = require('cors');
const app = express();
// Basic CORS for all routes
app.use(cors());
// Or with configuration
app.use(cors({
origin: 'https://your-frontend.com',
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true // If using cookies/auth
}));
2. ASP.NET Core Configuration
// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("AllowSpecificOrigin",
builder => builder.WithOrigins("https://your-frontend.com")
.AllowAnyMethod()
.AllowAnyHeader());
});
}
public void Configure(IApplicationBuilder app)
{
app.UseCors("AllowSpecificOrigin");
}
3. Nginx Configuration
server {
listen 80;
server_name api.example.com;
location / {
# CORS headers
add_header 'Access-Control-Allow-Origin' 'https://your-frontend.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
# Handle preflight requests
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
proxy_pass http://localhost:3000;
}
}
Client-Side Workarounds
When you don’t control the server:
1. Proxy Server
// Next.js API route example
export default async function handler(req, res) {
const response = await fetch('https://target-api.com/endpoint', {
headers: {
'Authorization': req.headers.authorization || ''
}
});
const data = await response.json();
res.status(200).json(data);
}
2. CORS Anywhere (Development Only)
// Prefix your API URL with a CORS proxy
fetch('https://cors-anywhere.herokuapp.com/https://target-api.com/data')
.then(response => response.json())
Best Practices
- Environment-Specific Configuration:
- Allow all origins in development
- Restrict to specific domains in production
- Proper Preflight Handling:
- Respond to OPTIONS requests
- Include
Access-Control-Max-Age
for caching
- Security Considerations:
- Never use
Access-Control-Allow-Origin: *
with credentials - Whitelist specific headers and methods
- Testing:
- Verify with different origins
- Test all HTTP methods
Common CORS Headers
Header | Purpose | Example |
---|---|---|
Access-Control-Allow-Origin | Specifies allowed origins | https://your-app.com |
Access-Control-Allow-Methods | Allowed HTTP methods | GET, POST, PUT |
Access-Control-Allow-Headers | Allowed request headers | Content-Type, Authorization |
Access-Control-Allow-Credentials | Whether to allow credentials | true |
Access-Control-Expose-Headers | Headers accessible to JS | X-Custom-Header |
Debugging CORS Issues
- Check the Network tab in DevTools:
- Look for OPTIONS requests
- Examine response headers
- Verify the Origin header matches:
- Your frontend’s exact domain
- Including protocol (http/https)
- Test with curl:
curl -H "Origin: https://your-app.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: Content-Type" \
-X OPTIONS --verbose https://api.example.com/endpoint
Remember: CORS is a browser security feature, not an API limitation. Proper server configuration is the correct long-term solution, while client-side workarounds should only be temporary fixes during development.