HTTP Headers: The Complete Developer Reference
HTTP headers are key-value pairs sent with every request and response. They control caching, authentication, content negotiation, security policies, and much more. Understanding them is essential for debugging APIs, fixing CORS issues, and hardening web applications.
Request Headers
These headers are sent by the client (browser or HTTP client) to the server.
Identity and Content
| Header | Purpose | Example |
|---|---|---|
Host |
Target hostname (required in HTTP/1.1) | Host: api.example.com |
User-Agent |
Client software identifier | User-Agent: Mozilla/5.0...Chrome/124 |
Accept |
Media types the client can handle | Accept: application/json, text/html |
Accept-Language |
Preferred response language | Accept-Language: en-US,en;q=0.9 |
Accept-Encoding |
Compression the client supports | Accept-Encoding: gzip, deflate, br |
Content-Type |
Body format for POST/PUT | Content-Type: application/json |
Content-Length |
Body size in bytes | Content-Length: 348 |
Authentication
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Authorization: Basic dXNlcjpwYXNzd29yZA==
Authorization: Digest username="bob", realm="api"...
The Authorization header transmits credentials. Bearer tokens (JWT) are most common in APIs. Basic is base64-encoded user:password — only safe over HTTPS.
Caching Control (Request Side)
Cache-Control: no-cache # Revalidate even if cached
Cache-Control: no-store # Never cache
Cache-Control: max-age=0 # Consider cached copy stale
If-None-Match: "abc123" # Conditional GET by ETag
If-Modified-Since: Tue, 15 Nov 2022 12:45:26 GMT
CORS Preflight
Origin: https://app.example.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: Content-Type, Authorization
Browsers send a preflight OPTIONS request with these headers before cross-origin requests that use methods other than GET/POST or include custom headers.
Response Headers
Content Delivery
| Header | Purpose | Example |
|---|---|---|
Content-Type |
Response body format + charset | Content-Type: application/json; charset=utf-8 |
Content-Length |
Body size | Content-Length: 1024 |
Content-Encoding |
Applied compression | Content-Encoding: gzip |
Transfer-Encoding |
Chunked for streaming | Transfer-Encoding: chunked |
Location |
Redirect target URL | Location: https://example.com/new-path |
Caching
# Public resources (CSS, images): cache 1 year, revalidate on change
Cache-Control: public, max-age=31536000, immutable
# API responses: no caching
Cache-Control: no-store
# HTML pages: revalidate each request
Cache-Control: no-cache
# ETag for conditional requests
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
# Last modification date
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
# Shared cache expiry (legacy, prefer Cache-Control)
Expires: Thu, 01 Dec 2034 16:00:00 GMT
Cache-Control directive cheat sheet:
| Directive | Meaning |
|---|---|
public |
Any cache (CDN, browser) may store |
private |
Browser only, not CDN |
no-cache |
Must revalidate before using cached copy |
no-store |
Never store anywhere |
max-age=N |
Fresh for N seconds |
s-maxage=N |
CDN max-age (overrides max-age for shared caches) |
immutable |
Content won't change; skip revalidation |
stale-while-revalidate=N |
Serve stale while fetching fresh in background |
CORS Headers
Cross-Origin Resource Sharing controls which external origins can access a resource.
Server Response Headers
# Allow specific origin
Access-Control-Allow-Origin: https://app.example.com
# Allow any origin (unsafe for authenticated endpoints)
Access-Control-Allow-Origin: *
# Response to preflight: allowed methods
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH
# Response to preflight: allowed custom headers
Access-Control-Allow-Headers: Content-Type, Authorization, X-Request-ID
# How long to cache preflight result (seconds)
Access-Control-Max-Age: 86400
# Allow credentials (cookies, auth headers)
Access-Control-Allow-Credentials: true
# Which headers the browser can expose to JS
Access-Control-Expose-Headers: X-Total-Count, X-Page
Critical rule: You cannot use Access-Control-Allow-Origin: * together with Access-Control-Allow-Credentials: true. Credentialed requests require a specific origin.
CORS Error Flowchart
- Browser makes cross-origin request → browser adds
Originheader - If request is "simple" (GET/POST + standard headers) → request goes through, browser checks response
Access-Control-Allow-Origin - If request is "complex" (DELETE, PUT, or custom headers) → browser sends OPTIONS preflight first
- If preflight fails → original request is blocked, CORS error in console
Security Headers
These headers are your first line of defense against XSS, clickjacking, and injection attacks.
Content-Security-Policy (CSP)
CSP tells the browser which sources are allowed to load scripts, styles, images, and other resources.
# Strict CSP for SPAs
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-abc123'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://api.example.com; frame-ancestors 'none'
# Report violations without enforcing (testing phase)
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
Common CSP directives:
| Directive | Controls |
|---|---|
default-src |
Fallback for all resource types |
script-src |
JavaScript sources |
style-src |
CSS sources |
img-src |
Image sources |
connect-src |
XHR, fetch, WebSocket targets |
frame-ancestors |
Who can embed this page in iframe |
object-src |
Flash/plugins (set to 'none') |
Strict-Transport-Security (HSTS)
Forces HTTPS for all future visits:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
max-age: Seconds to remember HTTPS requirementincludeSubDomains: Apply to all subdomainspreload: Include in browser's built-in HSTS list (submit at hstspreload.org)
Other Security Headers
# Block MIME sniffing (e.g., loading script disguised as image)
X-Content-Type-Options: nosniff
# Prevent clickjacking (legacy, prefer frame-ancestors CSP)
X-Frame-Options: DENY
# Enable browser XSS filter (legacy, modern browsers ignore)
X-XSS-Protection: 1; mode=block
# Control referrer information
Referrer-Policy: strict-origin-when-cross-origin
# Restrict browser features (camera, microphone, geolocation)
Permissions-Policy: camera=(), microphone=(), geolocation=(self)
Recommended Security Header Stack (2026)
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none'
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: interest-cohort=()
Test your headers at securityheaders.com.
Custom Headers Convention
By convention, custom headers use the X- prefix (though this was deprecated in RFC 6648):
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1699012800
X-Correlation-ID: abc-123
Rate limit headers are increasingly standardized as RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset (without X-).
Debugging Headers
# View request + response headers
curl -v https://api.example.com/users
# View response headers only
curl -I https://example.com
# Send custom headers
curl -H "Authorization: Bearer TOKEN" -H "Accept: application/json" https://api.example.com
# Follow redirects, show final headers
curl -L -D - https://example.com -o /dev/null
In Chrome DevTools → Network tab → click any request → Headers panel shows both request and response headers, with values decoded.
→ Decode JWT tokens in your browser with the JWT Parser. Check HTTP status codes at HTTP Status Codes.