How to Implement a Basic Auth HTTP Proxy for Applications Without Authentication Support


2 views

Many legacy applications or lightweight clients lack support for HTTP Basic Authentication, while modern APIs frequently require it. Here's a solution using Node.js that creates a middleware proxy to inject credentials transparently.

We'll build this using Node.js with Express and http-proxy-middleware for several advantages:

  • Cross-platform support (Windows/Linux/macOS)
  • Minimal dependencies
  • Easy credential configuration

First install required packages:

npm install express http-proxy-middleware dotenv

Here's the complete proxy server implementation (save as proxy-auth.js):

require('dotenv').config();
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');

const app = express();
const PORT = process.env.PORT || 3000;
const TARGET = process.env.TARGET_URL;
const AUTH = Buffer.from(${process.env.AUTH_USER}:${process.env.AUTH_PASS}).toString('base64');

app.use('/', createProxyMiddleware({
  target: TARGET,
  changeOrigin: true,
  onProxyReq: (proxyReq) => {
    proxyReq.setHeader('Authorization', Basic ${AUTH});
  },
  logger: console
}));

app.listen(PORT, () => {
  console.log(Auth proxy running on http://localhost:${PORT});
  console.log(Proxying requests to ${TARGET} with Basic Auth);
});

Create a .env file:

TARGET_URL=https://api.secured-service.com
AUTH_USER=service_account
AUTH_PASS=complex_password_123
PORT=8080

For non-Node.js environments, consider these options:

Nginx Reverse Proxy

server {
    listen 80;
    location / {
        proxy_pass https://target-service.com;
        proxy_set_header Authorization "Basic [base64-encoded-credentials]";
    }
}

Python with Requests

from flask import Flask
import requests

app = Flask(__name__)
AUTH = ('username', 'password')

@app.route('/<path:subpath>')
def proxy(subpath):
    resp = requests.get(f'https://remote/{subpath}', auth=AUTH)
    return resp.content, resp.status_code
  • Never hardcode credentials in source files
  • Use environment variables or secret management systems
  • Consider adding IP whitelisting for the proxy endpoint
  • Enable HTTPS for the proxy connection

Verify with curl:

curl http://localhost:8080/api/resource

Should return the same response as:

curl -u user:pass https://api.secured-service.com/api/resource

Many legacy applications lack built-in HTTP authentication support, while modern APIs increasingly require Basic Auth. This creates integration challenges when you need to connect auth-less clients to protected resources. A lightweight proxy solution can bridge this gap by injecting credentials transparently.

We'll implement a reverse proxy that:

  • Accepts unauthenticated requests from your application
  • Adds Basic Authentication headers
  • Forwards requests to the target server
  • Returns responses unchanged to the client

Here's a complete proxy implementation using Python Flask:


from flask import Flask, request, abort
import requests
from base64 import b64encode

app = Flask(__name__)

PROXY_USER = 'your_username'
PROXY_PASS = 'your_password'
TARGET_SERVER = 'https://protected-api.example.com'

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE'])
def proxy(path):
    # Construct target URL
    target_url = f"{TARGET_SERVER}/{path}"
    
    # Prepare auth header
    credentials = f"{PROXY_USER}:{PROXY_PASS}"
    encoded_credentials = b64encode(credentials.encode()).decode()
    headers = {
        "Authorization": f"Basic {encoded_credentials}",
        **dict(request.headers)
    }
    
    # Forward request
    try:
        resp = requests.request(
            method=request.method,
            url=target_url,
            headers=headers,
            data=request.get_data(),
            cookies=request.cookies,
            allow_redirects=False
        )
    except requests.exceptions.RequestException as e:
        abort(502, str(e))
    
    # Return response
    return (resp.content, resp.status_code, resp.headers.items())

if __name__ == '__main__':
    app.run(port=8080)

For production environments, you can configure Nginx as a proxy:


server {
    listen 80;
    server_name proxy.example.com;

    location / {
        proxy_pass https://protected-api.example.com;
        proxy_set_header Authorization "Basic $(echo -n 'username:password' | base64)";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Verify the proxy works by making direct HTTP requests:


curl http://localhost:8080/api/resource

Compare the response with direct authenticated access:


curl -u username:password https://protected-api.example.com/api/resource
  • Always use HTTPS for both client-proxy and proxy-server communication
  • Store credentials securely (environment variables or secret manager)
  • Implement rate limiting to prevent abuse
  • Consider adding IP whitelisting if applicable

For high-traffic scenarios:

  • Enable connection pooling in your proxy
  • Implement caching for GET requests
  • Consider using a compiled language (Go, Rust) for the proxy
  • Add health checks for the target server