HTTP Request Headers Explained

Complete guide to HTTP request headers — what they are, how they work, and when to use each

HTTP & APIsJune 25, 202614 min readBy Keyur Patel

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:

HeaderPurposeExample
HostTarget server domainHost: api.example.com
AuthorizationAuthentication credentialsAuthorization: Bearer eyJ...
Content-TypeFormat of request bodyContent-Type: application/json
AcceptDesired response formatAccept: application/json
Accept-LanguagePreferred languageAccept-Language: en-US,en;q=0.9
Accept-EncodingSupported compressionAccept-Encoding: gzip, br
User-AgentClient identificationUser-Agent: Mozilla/5.0...
CookieStored cookies for domainCookie: session_id=abc123
OriginRequest origin (CORS)Origin: https://myapp.com
RefererPrevious page URLReferer: https://myapp.com/login
Cache-ControlCaching directivesCache-Control: no-cache
If-None-MatchConditional (ETag)If-None-Match: "abc123"
If-Modified-SinceConditional (date)If-Modified-Since: Mon, 01 Jan 2024...
Content-LengthBody size in bytesContent-Length: 256
ConnectionConnection managementConnection: keep-alive
X-Requested-WithAjax request identifierX-Requested-With: XMLHttpRequest
Sec-Fetch-SiteRequest origin relationshipSec-Fetch-Site: same-origin
Sec-Fetch-ModeRequest modeSec-Fetch-Mode: cors
Sec-Fetch-DestRequest destinationSec-Fetch-Dest: empty
DNTDo Not Track preferenceDNT: 1
RangePartial content requestRange: 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/json

Content-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 objects

cURL

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/users

Node.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

AspectRequest HeadersResponse Headers
DirectionClient → ServerServer → Client
PurposeTell server what client needsTell client about the response
Set byBrowser/app/developerServer/backend code
Auth exampleAuthorization: Bearer tokenWWW-Authenticate: Bearer
Content exampleContent-Type (of body sent)Content-Type (of body received)
CachingCache-Control, If-None-MatchCache-Control, ETag, Expires
CORSOriginAccess-Control-Allow-Origin
CookiesCookie: session_id=abcSet-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

Always use HTTPS

Headers including Authorization tokens are visible in plain HTTP. HTTPS encrypts the entire request including headers.

Set Content-Type explicitly

Don't rely on defaults. Always declare Content-Type when sending a body to avoid server-side parsing errors.

Keep headers minimal

Don't send unnecessary custom headers. Each header adds bytes to every request and can trigger preflight CORS checks.

Use Accept for content negotiation

Tell the server what format you expect (application/json). Helps servers that support multiple formats return the right one.

Validate headers on the server

Never trust headers blindly. Validate Authorization tokens, check Content-Type before parsing, and validate Origin for CORS.

Use conditional headers for caching

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?
HTTP request headers are key-value pairs sent by the client (browser or app) to the server along with every HTTP request. They provide metadata about the request — authentication credentials, content format, caching preferences, browser information, and more.
Why are request headers important?
Request headers enable authentication (Authorization), content negotiation (Accept, Content-Type), caching (If-None-Match), CORS (Origin), and security controls. Without headers, servers cannot identify users, parse request bodies, or make caching decisions.
What is the Authorization header?
The Authorization header sends credentials to authenticate the request. Common formats include 'Bearer <token>' for JWT authentication, 'Basic <base64>' for username:password authentication, and 'ApiKey <key>' for API key authentication.
What is the difference between Accept and Content-Type?
Accept tells the server what format you want the RESPONSE in (e.g., 'I accept JSON'). Content-Type tells the server what format the REQUEST BODY is in (e.g., 'I'm sending JSON'). Accept is for responses; Content-Type is for the request body.
What is the Origin header?
The Origin header indicates where the request originated from (domain). It is sent automatically by browsers for cross-origin requests and is used by servers for CORS (Cross-Origin Resource Sharing) validation to decide whether to allow the request.
Can I create custom HTTP headers?
Yes. Custom headers traditionally used the X- prefix (X-Request-ID, X-Correlation-ID) but this convention is deprecated. You can use any name that doesn't conflict with standard headers. Custom headers are commonly used for request tracing, API versioning, and feature flags.
Which headers are automatically added by browsers?
Browsers automatically add: Host, User-Agent, Accept, Accept-Language, Accept-Encoding, Connection, Cookie (if set), Origin (for cross-origin), Referer, Sec-Fetch-Site, Sec-Fetch-Mode, and Sec-Fetch-Dest. You cannot override some of these (called forbidden headers).
How do I inspect HTTP request headers?
Open browser DevTools (F12) → Network tab → click any request → Headers section shows both request and response headers. You can also use curl -v to see headers in the terminal, or tools like Postman which display headers clearly.

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.