Every time your browser loads a page or your app calls an API, HTTP request headers are sent along with the request. They carry essential metadata — who you are (Authorization), what format you expect (Accept), what you are sending (Content-Type), and much more. Understanding request headers is fundamental to debugging API issues, implementing authentication, handling CORS, and building secure applications.
This guide explains every common HTTP request header with practical examples in Fetch API, Axios, cURL, and Node.js — giving you a complete reference for everyday development.
What Are HTTP Request Headers?
HTTP request headers are key-value pairs sent by the client to the server at the beginning of every HTTP request. They appear after the request line (method + URL) and before the request body. Each header follows the format: Header-Name: value.
GET /api/users/123 HTTP/1.1 Host: api.example.com Authorization: Bearer eyJhbGciOiJIUzI1NiJ9... Accept: application/json Accept-Language: en-US User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Cache-Control: no-cache Connection: keep-alive
Headers are invisible to users but critical for how the request is processed. The server uses them to authenticate the request, determine the response format, make caching decisions, and enforce security policies.
How HTTP Request Headers Work
1. Client creates request
Browser/app builds the HTTP request with method + URL
2. Headers attached
Auth token, Content-Type, Accept, Cookie, etc.
3. Server reads headers
Authenticates user, determines format, checks cache
4. Response generated
Server returns data in requested format with response headers
Complete HTTP Request Headers Reference
Here are all the commonly used request headers organized by category:
| Header | Purpose | Example |
|---|---|---|
| Host | Target server domain | Host: api.example.com |
| Authorization | Authentication credentials | Authorization: Bearer eyJ... |
| Content-Type | Format of request body | Content-Type: application/json |
| Accept | Desired response format | Accept: application/json |
| Accept-Language | Preferred language | Accept-Language: en-US,en;q=0.9 |
| Accept-Encoding | Supported compression | Accept-Encoding: gzip, br |
| User-Agent | Client identification | User-Agent: Mozilla/5.0... |
| Cookie | Stored cookies for domain | Cookie: session_id=abc123 |
| Origin | Request origin (CORS) | Origin: https://myapp.com |
| Referer | Previous page URL | Referer: https://myapp.com/login |
| Cache-Control | Caching directives | Cache-Control: no-cache |
| If-None-Match | Conditional (ETag) | If-None-Match: "abc123" |
| If-Modified-Since | Conditional (date) | If-Modified-Since: Mon, 01 Jan 2024... |
| Content-Length | Body size in bytes | Content-Length: 256 |
| Connection | Connection management | Connection: keep-alive |
| X-Requested-With | Ajax request identifier | X-Requested-With: XMLHttpRequest |
| Sec-Fetch-Site | Request origin relationship | Sec-Fetch-Site: same-origin |
| Sec-Fetch-Mode | Request mode | Sec-Fetch-Mode: cors |
| Sec-Fetch-Dest | Request destination | Sec-Fetch-Dest: empty |
| DNT | Do Not Track preference | DNT: 1 |
| Range | Partial content request | Range: bytes=0-1023 |
Authentication Headers
The Authorization header is the most critical request header for API development. It carries the credentials that prove who the client is:
Bearer Token (JWT)
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...Most common for modern APIs. The token is a signed JWT containing user identity. Server verifies the signature without a database lookup.
Use case: REST APIs, SPAs, mobile apps
Basic Authentication
Authorization: Basic dXNlcjpwYXNz (base64 of user:pass)Encodes username:password in Base64. Not secure without HTTPS since Base64 is trivially decoded. Simple but limited.
Use case: Internal APIs, legacy systems, CI/CD webhooks
API Key
X-API-Key: abc123def456 (or in query ?apiKey=...)A simple token identifying the application (not the user). No user-level identity — just app identification for rate limiting and access control.
Use case: Public APIs (Google Maps, OpenWeather), server-to-server
Content Negotiation Headers
Content negotiation lets the client tell the server what format, language, and encoding it prefers for the response:
Accept vs Content-Type (commonly confused)
Accept
What format I want the RESPONSE in
Accept: application/jsonContent-Type
What format my REQUEST BODY is in
Content-Type: application/json// Common Content-Type values: application/json → JSON data (most APIs) application/x-www-form-urlencoded → HTML form data multipart/form-data → File uploads text/plain → Plain text text/html → HTML content application/xml → XML data // Accept-Encoding (what compression client supports): Accept-Encoding: gzip, deflate, br // Server can compress response → smaller transfer → faster // Accept-Language (preferred language): Accept-Language: en-US,en;q=0.9,fr;q=0.8 // Server may return localized content based on this
CORS-Related Request Headers
When your frontend (https://myapp.com) calls an API on a different domain (https://api.example.com), the browser enforces CORS (Cross-Origin Resource Sharing). The Origin header is the key player:
// Browser automatically sends Origin for cross-origin requests: Origin: https://myapp.com // For "non-simple" requests (PUT, DELETE, custom headers), // browser sends a preflight OPTIONS request first: OPTIONS /api/users HTTP/1.1 Origin: https://myapp.com Access-Control-Request-Method: DELETE Access-Control-Request-Headers: Authorization, Content-Type // Server must respond with allowed origins: Access-Control-Allow-Origin: https://myapp.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: Authorization, Content-Type
CORS errors ("has been blocked by CORS policy") are one of the most common frontend debugging issues. They happen when the server does not include the correct Access-Control-Allow-Origin header in its response. The fix is always on the server side — you cannot bypass CORS from the browser (by design, for security).
Setting Request Headers in Code
Fetch API (Browser)
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9...",
"Accept": "application/json",
"X-Request-ID": "req_abc123"
},
body: JSON.stringify({ name: "Alice", email: "alice@example.com" })
})Axios
const { data } = await axios.post("https://api.example.com/users",
{ name: "Alice", email: "alice@example.com" },
{
headers: {
"Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9...",
"X-Request-ID": "req_abc123"
}
}
)
// Note: Axios sets Content-Type: application/json automatically for objectscURL
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." \
-H "Accept: application/json" \
-d '{"name": "Alice", "email": "alice@example.com"}'
# Use -v (verbose) to see all request AND response headers:
curl -v https://api.example.com/usersNode.js (native http/https)
const https = require("https")
const options = {
hostname: "api.example.com",
path: "/users",
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9...",
"Accept": "application/json"
}
}
const req = https.request(options, (res) => {
// Handle response
})
req.write(JSON.stringify({ name: "Alice" }))
req.end()Request Headers vs Response Headers
| Aspect | Request Headers | Response Headers |
|---|---|---|
| Direction | Client → Server | Server → Client |
| Purpose | Tell server what client needs | Tell client about the response |
| Set by | Browser/app/developer | Server/backend code |
| Auth example | Authorization: Bearer token | WWW-Authenticate: Bearer |
| Content example | Content-Type (of body sent) | Content-Type (of body received) |
| Caching | Cache-Control, If-None-Match | Cache-Control, ETag, Expires |
| CORS | Origin | Access-Control-Allow-Origin |
| Cookies | Cookie: session_id=abc | Set-Cookie: session_id=abc |
Security Considerations
🔒 Never send Authorization over HTTP
Tokens sent over unencrypted HTTP can be intercepted by anyone on the network. Always use HTTPS in production. Set HSTS headers to force HTTPS.
🔒 Don't log sensitive headers
Server logs that capture Authorization headers expose tokens to anyone with log access. Mask or exclude auth headers from logging.
🔒 Validate Origin for CORS
Don't use Access-Control-Allow-Origin: * for authenticated APIs. Whitelist specific origins to prevent unauthorized cross-origin access.
🔒 Set SameSite on cookies
Without SameSite=Strict, cookies are sent with cross-origin requests — enabling CSRF attacks. Always set SameSite for session cookies.
🔒 Be careful with Referer header
The Referer header can leak sensitive URL parameters (tokens in query strings) to third-party services. Set Referrer-Policy: strict-origin to limit exposure.
Common Developer Mistakes
⚠️ Wrong Content-Type for the body
Sending JSON body with Content-Type: text/plain (or missing entirely) causes the server to fail parsing. Always match Content-Type to your actual body format.
⚠️ Forgetting Authorization header
Getting 401 errors? Check if the Authorization header is actually being sent. Common in Fetch API where headers must be explicitly set (unlike Axios which can use interceptors).
⚠️ Confusing Accept and Content-Type
Accept = what format you want back. Content-Type = what format you're sending. These are different headers with different purposes.
⚠️ Setting headers that browsers forbid
Browsers block setting some headers in fetch/XMLHttpRequest (Host, Cookie, Origin, Referer). These are controlled by the browser for security.
⚠️ Not handling preflight CORS requests
Custom headers trigger a preflight OPTIONS request. If your server doesn't respond to OPTIONS with the correct CORS headers, the actual request is never sent.
Best Practices
Headers including Authorization tokens are visible in plain HTTP. HTTPS encrypts the entire request including headers.
Don't rely on defaults. Always declare Content-Type when sending a body to avoid server-side parsing errors.
Don't send unnecessary custom headers. Each header adds bytes to every request and can trigger preflight CORS checks.
Tell the server what format you expect (application/json). Helps servers that support multiple formats return the right one.
Never trust headers blindly. Validate Authorization tokens, check Content-Type before parsing, and validate Origin for CORS.
Send If-None-Match (ETag) or If-Modified-Since to enable 304 responses — saves bandwidth when data hasn't changed.
Frequently Asked Questions
What are HTTP request headers?
Why are request headers important?
What is the Authorization header?
What is the difference between Accept and Content-Type?
What is the Origin header?
Can I create custom HTTP headers?
Which headers are automatically added by browsers?
How do I inspect HTTP request headers?
Related Articles & Tools
Conclusion
HTTP request headers are the metadata layer of every web interaction. They handle authentication (Authorization), content format (Content-Type, Accept), caching (If-None-Match, Cache-Control), security (Origin, Cookie), and client identification (User-Agent). Understanding these headers gives you the ability to debug API issues, implement proper authentication, handle CORS correctly, and build secure applications.
The most important headers to master: Authorization (for auth), Content-Type (for request bodies), Accept (for response format), Origin (for CORS), and Cache-Control (for performance). With these five, you can handle 90% of header-related tasks in everyday development.
