CORS for APIs
CORS enables controlled access to resources across domain boundaries, but must be configured correctly to avoid security risks.
Quick Overview
CORS stands for Cross-Origin Resource Sharing. It’s a mechanism that allows browsers to request resources from a different domain than the one that served the current webpage. By default, browsers block such cross-origin requests to protect against unauthorized data access. CORS lets servers explicitly specify which origins, methods, and headers are permitted. Proper CORS configuration matters for APIs used by browser-based applications. At the same time, an overly permissive configuration creates a security vulnerability by enabling cross-origin attacks. Key concepts include the Origin header, preflight requests, Access-Control headers, and the distinction between simple and complex requests.
Key Components
Same-Origin Policy
The Same-Origin Policy is a fundamental browser security mechanism. It prevents a webpage from one domain from accessing data on another domain. Origin is determined by protocol, domain, and port. Different subdomains or ports count as different origins.
Origin Header
When a browser makes a cross-origin request, it sends an Origin header indicating the source domain. The server uses this header to decide whether to allow the request, responding with Access-Control-Allow-Origin and other CORS headers.
Access-Control-Allow-Origin
This header specifies which origins may access the resource. It can contain a specific domain like https://app.example.com or a wildcard (*) for all domains. Wildcards should be avoided for APIs with authentication or sensitive data.
Access-Control-Allow-Methods
This header lists the HTTP methods permitted for cross-origin requests, such as GET, POST, PUT, and DELETE. The browser may only use methods explicitly allowed.
Access-Control-Allow-Headers
This header indicates which additional headers the client may send in the request. Standard headers like Content-Type, Accept, or Authorization may need explicit permission if they’re custom headers.
Access-Control-Allow-Credentials
This header allows cookies, HTTP authentication, or client certificates to be sent with cross-origin requests. When set to true, Access-Control-Allow-Origin cannot be a wildcard—it must specify a concrete domain.
Preflight Request
For complex cross-origin requests, the browser first sends an OPTIONS request, known as a preflight. The server responds with permitted methods, headers, and origins. Only then does the browser send the actual request. Preflight requests are triggered for methods like PUT or DELETE, or when custom headers are used.
Simple and Complex Requests
Simple requests use GET, HEAD, or POST with specific content types and standard headers. They require no preflight. Complex requests use other methods, custom headers, or content types and trigger a preflight.
CORS and Security Risks
Incorrect CORS configurations can lead to unauthorized access. Particularly dangerous are Access-Control-Allow-Origin: * on APIs that use credentials, dynamically echoing the Origin header without validation, and allowing unsafe methods. Attackers can exploit such mistakes to steal data from the browser.
CORS in API Configuration
CORS is typically configured at the API gateway, web server, or application level. In Node.js, the cors middleware package is common; Spring Boot offers @CrossOrigin; ASP.NET Core has UseCors. Regardless of technology, configuration should be restrictive and explicit.
Debugging CORS
CORS errors in browsers often lack detailed information. Browser developer tools and network logs help you investigate preflight and main requests. Server-side logs should record Origin headers and responses.
Practical Example
A web application at https://app.example.com accesses an API at https://api.example.com. The API must allow CORS for this origin.
The browser sends the request:
GET /api/v1/profile
Host: api.example.com
Origin: https://app.example.com
Authorization: Bearer TOKEN
The server responds with CORS headers:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
{
"name": "Max Mustermann",
"email": "max@example.com"
}
For a PUT request, the browser first sends a preflight:
OPTIONS /api/v1/profile
Host: api.example.com
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
The server responds to the preflight:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
Only after that does the browser send the actual PUT request. This way, CORS ensures only authorized origins can access the API.
FAQ: CORS for APIs
1. What is CORS?
2. What is the Same-Origin Policy?
3. What is a preflight request?
4. What is Access-Control-Allow-Origin?
5. What is Access-Control-Allow-Credentials?
6. What is the Origin header?
7. Which requests trigger a preflight?
8. Why is Access-Control-Allow-Origin: * dangerous?
9. What is Access-Control-Allow-Methods?
10. What is Access-Control-Allow-Headers?
11. Can CORS prevent server attacks?
12. What is Access-Control-Max-Age?
13. Why does CORS work in Postman but not in the browser?
14. What is dynamic origin mirroring?
15. How do you test CORS correctly?
References
- https://developer.mozilla.org/docs/Web/HTTP/CORS
- https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/07-Testing_Cross_Origin_Resource_Sharing
- https://fetch.spec.whatwg.org/#cors-protocol
Recommended books on web security
If you’d like to dive deeper into CORS, web security, and API security, check out these books:
IT CyberSecurity
Books about IT security, authentication, encryption and security best practices
The Web Application Hacker's Handbook von Dafydd Stuttard, Marcus Pinto
Bei Amazon ansehenAffiliate-Link: Bei einem Kauf erhalten wir möglicherweise eine Provision.




