- Home
- HTTP Headers
- X-Forwarded-Proto
Header
X-Forwarded-Proto
Learn how the X-Forwarded-Proto header identifies the original protocol (HTTP/HTTPS) used by clients connecting through proxies or load balancers.
TL;DR:
X-Forwarded-Prototells your app whether the user originally arrived over HTTP or HTTPS before a proxy stripped TLS and forwarded the request internally.
Why This Header Exists
Many deployments terminate TLS at the edge:
Browser --HTTPS--> Load balancer --HTTP--> App server
From the app server’s perspective, the incoming connection is plain HTTP even though the user really connected over HTTPS. X-Forwarded-Proto exists to preserve that original fact.
Typical value:
X-Forwarded-Proto: https
The Real Problem It Solves
If your app does not know the original scheme, it can make bad decisions:
- redirect HTTPS traffic back to HTTPS again and create loops
- fail to mark cookies as secure
- generate
http://absolute URLs in emails or redirects - misreport whether a request was secure in logs or middleware
That is why this header matters even though it looks trivial.
The Classic Redirect Loop
This is the bug many teams hit first:
- user visits
https://app.example.com - load balancer terminates TLS
- app receives plain HTTP from the load balancer
- app thinks the request is insecure and redirects to HTTPS
- repeat forever
Once the app trusts X-Forwarded-Proto: https, it can tell the difference between internal transport and the user-facing connection.
Framework Handling
In Express, the usual fix is to trust the proxy so req.secure reflects X-Forwarded-Proto:
app.set('trust proxy', 1)
app.use((req, res, next) => {
if (!req.secure) {
return res.redirect(301, `https://${req.headers.host}${req.originalUrl}`)
}
next()
})
Other frameworks have equivalent settings. The important part is not the header lookup itself. The important part is declaring which proxy layers are allowed to speak for the original request.
Security Rule: Trust Boundaries Matter
Clients can forge X-Forwarded-Proto if they can reach your origin directly. That is why this header is only safe when:
- the origin is behind a trusted proxy or load balancer
- the proxy overwrites the header instead of passing through user input
- the app only trusts forwarded headers from known internal hops
If any of those are missing, treat the header as untrusted input.
Standard Alternative
The standard Forwarded header can express the same idea with proto=https, but X-Forwarded-Proto is still the more common field in real deployments.
Related Headers
Frequently Asked Questions
What is X-Forwarded-Proto?
X-Forwarded-Proto tells an origin app whether the original client connected to the edge over HTTP or HTTPS before a proxy forwarded the request inward.
Why is X-Forwarded-Proto important?
Without it, an app behind TLS termination may think every request is plain HTTP. That affects redirects, secure cookies, absolute URL generation, and security behavior.
How do I use X-Forwarded-Proto?
Use it only through trusted proxy configuration. Most frameworks can translate it into a secure-request signal once you declare which proxies to trust.
Can X-Forwarded-Proto be spoofed?
Yes. Never trust it from arbitrary clients. Only trust it when your proxy overwrites it and your app accepts it only from known proxy layers.