Definition
OPTIONS is an HTTP method that requests information about the communication options available for a resource or server. It returns which HTTP methods are supported (GET, POST, PUT, DELETE, etc.) and other capabilities without performing any action on the resource itself. OPTIONS is a safe method - it doesn’t modify server state.
The primary use of OPTIONS is CORS preflight requests: when a browser makes a cross-origin request with custom headers or methods other than GET/POST, it first sends an OPTIONS request to check if the actual request is allowed. The server responds with CORS headers indicating what’s permitted.
OPTIONS is essential for API discoverability and CORS security. It helps clients understand what operations they can perform on a resource before attempting them, and browsers use it automatically to enforce same-origin policy exceptions.
Example
Discover Allowed Methods:
OPTIONS /api/users/123 HTTP/1.1
Host: api.example.com
// Response shows allowed methods
HTTP/1.1 200 OK
Allow: GET, PUT, PATCH, DELETE, OPTIONS
CORS Preflight - Before PUT Request:
OPTIONS /api/posts/456 HTTP/1.1
Origin: https://myapp.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
// Server responds with CORS headers
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://myapp.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
Server-Wide Capabilities:
OPTIONS * HTTP/1.1
Host: api.example.com
// Response shows server capabilities
HTTP/1.1 200 OK
Allow: GET, POST, OPTIONS
Analogy
Restaurant Menu Inquiry: Before ordering, you ask “What dishes do you serve? What cooking methods do you use?” OPTIONS is like asking a restaurant what they can make before you place your order. They tell you their capabilities without cooking anything.
Phone Call Screening: Think of OPTIONS like when you call a business and an automated system tells you “Press 1 for sales, 2 for support, 3 for billing.” It’s telling you what operations are available before you choose one.
Permission Check: Like asking a bouncer “Can I bring my friend? Can we wear sneakers?” before entering a club. The bouncer tells you the rules (OPTIONS response) without actually letting you in yet.
Code Example
// OPTIONS - Discover resource capabilities
OPTIONS /api/users/789 HTTP/1.1
Host: api.example.com
// Response - Allowed methods
HTTP/1.1 200 OK
Allow: GET, PUT, PATCH, DELETE, OPTIONS
Content-Type: application/json
Content-Length: 0
// OPTIONS - CORS preflight (browser automatic)
OPTIONS /api/posts HTTP/1.1
Host: api.example.com
Origin: https://myapp.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, X-Custom-Header
// Response - CORS headers
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://myapp.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, X-Custom-Header, Authorization
Access-Control-Max-Age: 86400
Access-Control-Allow-Credentials: true
Vary: Origin
// After successful preflight, browser sends actual request:
POST /api/posts HTTP/1.1
Host: api.example.com
Origin: https://myapp.example.com
Content-Type: application/json
X-Custom-Header: value
{"title": "New Post", "content": "..."}
// OPTIONS - Server-wide capabilities
OPTIONS * HTTP/1.1
Host: api.example.com
// Response
HTTP/1.1 200 OK
Allow: GET, HEAD, POST, OPTIONS
Server: nginx/1.25.0
Content-Length: 0
// OPTIONS - API documentation endpoint
OPTIONS /api/products HTTP/1.1
Host: api.example.com
Accept: application/json
// Response - Detailed capabilities
HTTP/1.1 200 OK
Allow: GET, POST, OPTIONS
Content-Type: application/json
{
"methods": {
"GET": {
"description": "List all products",
"parameters": ["page", "limit", "category"],
"authentication": false
},
"POST": {
"description": "Create new product",
"authentication": true,
"requiredRole": "admin",
"contentType": "application/json"
}
},
"endpoints": [
"/api/products",
"/api/products/{id}"
]
}
// OPTIONS - CORS preflight rejection
OPTIONS /api/admin/users HTTP/1.1
Origin: https://untrusted.com
Access-Control-Request-Method: DELETE
// Response - CORS blocked
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"error": "cors_not_allowed",
"message": "Origin not permitted"
}
// OPTIONS - Method not allowed
OPTIONS /api/readonly-resource HTTP/1.1
// Response
HTTP/1.1 200 OK
Allow: GET, HEAD, OPTIONS
Diagram
sequenceDiagram
participant Browser
participant Server
participant Backend
Note over Browser: User triggers cross-origin POST
Browser->>Server: OPTIONS /api/posts (preflight)
Note over Browser,Server: Check CORS permissions
Server->>Backend: Check CORS policy
Backend-->>Server: Policy rules
Server-->>Browser: 204 No Content + CORS headers
Note over Server,Browser: Access-Control-Allow-*
Note over Browser: Preflight passed!
Browser->>Server: POST /api/posts (actual request)
Note over Browser,Server: With custom headers
Server->>Backend: Process POST request
Backend-->>Server: Created resource
Server-->>Browser: 201 Created
Note over Server,Browser: Actual response
Note over Browser: Alternative: Preflight Failed
Browser->>Server: OPTIONS /api/admin (preflight)
Server-->>Browser: 403 Forbidden
Note over Browser: Browser blocks actual request
Note over Browser: Error in console
Best Practices
- Implement for all resources: Support OPTIONS on every endpoint
- Return 200 OK or 204 No Content: Standard successful responses
- Include Allow header: List supported HTTP methods
- Handle CORS preflight: Respond with Access-Control-* headers
- Cache preflight responses: Use Access-Control-Max-Age header
- Keep it lightweight: OPTIONS should be fast, no heavy computation
- Document capabilities: Optionally return detailed API info in body
- Support asterisk: OPTIONS * for server-wide capabilities
- No authentication required: OPTIONS should work without auth
- Validate origin: Check Origin header for CORS security
Common Mistakes
Not implementing OPTIONS at all, causing CORS failures. Requiring authentication for OPTIONS requests (breaks CORS preflight). Returning 405 Method Not Allowed instead of implementing OPTIONS. Not including Allow header in response. Forgetting Access-Control-Allow-Headers in CORS preflight response. Setting Access-Control-Max-Age too low, causing excessive preflight requests. Not handling wildcard OPTIONS * for server capabilities. Including response body when 204 No Content should be used. Not varying response by Origin header (cache issues). Hardcoding allowed methods instead of dynamically determining them. Not supporting OPTIONS for all endpoints consistently.