DEV Community

Auth By Example
Auth By Example

Posted on

A CORS allowlist is not authorization

A tight Access-Control-Allow-Origin list only controls which browsers may read a cross-origin response. It is not an authorization decision for who may act on which resource.

Browsers enforce CORS. Scripts, mobile apps, curl, and server-to-server callers do not. If your API returns 200 for DELETE /invoices/inv_4821 whenever a valid session cookie or bearer token is present, a CORS allowlist never blocked that delete.

What usually goes wrong:

  1. Teams treat “not allowed by CORS” as “not allowed for this user.”
  2. Object checks are skipped because “only our SPA can call this API.”
  3. List endpoints return every tenant’s rows; the SPA hides what CORS would have blocked anyway.

Patterns that hold up:

  1. Authenticate the caller, then authorize each action on each resource id (ownership, role on that object, or an explicit grant).
  2. Filter list and search results by what the subject may see, on the server.
  3. Re-check on nested ids in batch and GraphQL paths.

Quick check: call the same mutating endpoint with a valid token from curl (no browser). If it succeeds for another user’s resource, CORS was never your authorization layer.

CORS is a browser reading rule. Object authorization belongs on the server.

Top comments (0)