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—a browser mechanism that allows requests for resources from a different domain than the one serving the current webpage. By default, browsers block cross-origin requests to prevent unauthorized data access. CORS lets servers explicitly specify which origins, methods, and headers are permitted. Proper configuration is essential for APIs consumed by browser-based applications, yet overly permissive settings create security vulnerabilities that attackers can exploit. Key concepts include the Origin header, preflight requests, Access-Control headers, and the distinction between simple and complex requests.
Core Concepts
Same-Origin Policy
The Same-Origin Policy is a fundamental browser security mechanism that prevents a webpage from accessing data belonging to another domain. Origin is determined by protocol, domain, and port. Different subdomains or ports are treated as different origins.
Origin Header
The browser includes an Origin header when making cross-origin requests, specifying the source domain. The server uses this header to decide whether to allow the request and responds with Access-Control-Allow-Origin and other CORS headers.
Access-Control-Allow-Origin
This header specifies which origins may access the resource. It can name a specific domain like https://app.example.com or use * to allow 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. Only explicitly allowed methods may be used by the browser.
Access-Control-Allow-Headers
This header indicates which additional headers the client may include in its request. Standard headers like Content-Type, Accept, or Authorization must sometimes be explicitly allowed if they’re custom.
Access-Control-Allow-Credentials
This header permits cookies, HTTP authentication, or client certificates to be sent with cross-origin requests. When set to true, Access-Control-Allow-Origin cannot be * but must specify a concrete domain.
Preflight Request
For complex cross-origin requests, the browser first sends an OPTIONS request—a preflight check. The server responds with allowed methods, headers, and origins. Only after this exchange does the browser send the actual request. Preflight requests are triggered for methods like PUT, DELETE, or custom headers.
Simple and Complex Requests
Simple requests use GET, HEAD, or POST with specific content types and standard headers; they skip preflight. Complex requests use other methods, custom headers, or non-standard content types and trigger a preflight check.
CORS and Security Risks
Misconfigured CORS can lead to unauthorized access. Particularly dangerous are Access-Control-Allow-Origin: * paired with credentials, dynamically mirroring the Origin header without validation, and permitting unsafe methods. Attackers can exploit these oversights to steal data in the browser.
CORS in API Configuration
CORS is typically configured at the API gateway, web server, or application layer. Node.js commonly uses the cors middleware package; Spring Boot offers @CrossOrigin; ASP.NET Core has UseCors. Whatever the technology, configuration should be restrictive and explicit.
Debugging CORS
CORS errors in the browser often lack detail. Browser developer tools and network logs help inspect preflight and main requests. Server-side logging should record Origin headers and responses.
Practical Example
A web application at https://app.example.com calls an API at https://api.example.com. The API must allow CORS for that 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 then does the browser send the actual PUT request. This ensures that 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 properly?
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 Reading on Web Security
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.




