Reverse Proxy with Authentication and Timeouts
Reverse proxy built on net/http/httputil that forwards requests, adds simple bearer authentication, and enforces timeouts.
main.go
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
package main
import (
"crypto/subtle"
"fmt"
"log"
"net"
"net/http"
"net/http/httputil"
"net/url"
"time"
)
func main() {
target, err := url.Parse("http://127.0.0.1:8081")
if err != nil {
log.Fatalf("parse target: %v", err)
}
proxy := httputil.NewSingleHostReverseProxy(target)
proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
http.Error(w, fmt.Sprintf("upstream error: %v", err), http.StatusBadGateway)
}
proxy.Transport = &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 5 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
const expectedToken = "dev-secret"
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
want := "Bearer " + expectedToken
if subtle.ConstantTimeCompare([]byte(token), []byte(want)) != 1 {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
r.Header.Del("Connection")
r.Header.Set("X-Forwarded-Host", r.Host)
proxy.ServeHTTP(w, r)
})
srv := &http.Server{
Addr: ":8080",
Handler: handler,
ReadHeaderTimeout: 5 * time.Second,
}
log.Printf("proxy listening on http://localhost%v -> %s", srv.Addr, target.String())
if err := srv.ListenAndServe(); err != nil {
log.Fatalf("proxy failed: %v", err)
}
}How It Works
Reverse proxy built on net/http/httputil that forwards requests, adds simple bearer authentication, and enforces timeouts.
Configures an HTTP transport with dial and response timeouts, wraps ReverseProxy director to inject authentication and header logic, handles errors via a custom error handler, and starts a server exposing the proxy endpoint.
Key Concepts
- 1Custom director rewrites target host or scheme and headers.
- 2Bearer-token check rejects unauthorized requests early.
- 3Transport timeouts and error handling guard against hanging upstreams.
When to Use This Pattern
- Gateway for internal services with lightweight authentication.
- Local development proxying to remote APIs securely.
- Adding cross-cutting concerns such as headers or logging in one place.
Best Practices
- Do not log sensitive authorization headers.
- Set sane idle and response timeouts to avoid resource exhaustion.
- Validate upstream URLs and restrict where requests can be sent.
Go Version1.18+
Difficultyadvanced
Production ReadyYes
Lines of Code61