Skip to main content

Release Notes Downloads GitHub CI Status License: MIT

fastapi-ipware

A FastAPI/Starlette-native wrapper for python-ipware that eliminates the need for WSGI-style header conversion.

python-ipware expects WSGI-style headers (HTTP_X_FORWARDED_FOR), but FastAPI uses natural header names (X-Forwarded-For). This wrapper handles the conversion automatically so you don't have to.

Also, the default precedence order is optimized for modern cloud deployments. See the default precedence configuration in the source code. This is different from the default ordering ipware which deprioritizes platform-specific headers, which is often the wrong ordering if you are using something like CloudFlare.

Features

  • Zero conversion overhead - Headers converted once at initialization, not on every request
  • FastAPI-native API - Works directly with FastAPI/Starlette Request objects
  • Customizable precedence - Easy to configure header priority for your infrastructure
  • Proxy validation - Supports trusted proxy lists and proxy count validation

Installation

uv add fastapi-ipware

Quick Start

Using FastAPI Dependency Injection

from typing import Annotated
from fastapi import Depends, FastAPI
from fastapi_ipware import ClientIpResult, FastAPIIpWare

app = FastAPI()
ipware = FastAPIIpWare()


@app.get("/")
async def get_ip(client: Annotated[ClientIpResult, Depends(ipware)]):
    # trusted is true only when the request came through the proxies
    # configured with proxy_count or proxy_list
    ip, trusted = client
    return {
        "ip": str(ip) if ip else None,
        "trusted": trusted,
        "is_public": ip.is_global if ip else None,
    }


# Or inject only the IP object or string directly:
@app.get("/ip-string")
async def get_ip_string(ip_str: Annotated[str | None, Depends(ipware.get_ip_str)]):
    return {"ip": ip_str}

Using Request Directly

from fastapi import FastAPI, Request
from fastapi_ipware import FastAPIIpWare

app = FastAPI()
ipware = FastAPIIpWare()


@app.get("/")
async def get_ip(request: Request):
    ip, trusted = ipware.get_client_ip_from_request(request)
    return {"ip": str(ip) if ip else None, "trusted": trusted}

Using ASGI Middleware

Automatically extract the client IP onto request.state for every request:

from fastapi import FastAPI, Request
from fastapi_ipware import IpWareMiddleware

app = FastAPI()
app.add_middleware(IpWareMiddleware)


@app.get("/")
async def get_ip(request: Request):
    return {
        "ip": request.state.client_ip_str,
        "trusted": request.state.ip_trusted,
    }

Pass a configured resolver when you need one. Omit strict to use that resolver's default_strict; pass strict= to override it.

from fastapi_ipware import FastAPIIpWare, IpWareMiddleware

ipware = FastAPIIpWare(proxy_count=1, default_strict=True)
app.add_middleware(IpWareMiddleware, ipware=ipware)

Custom Header Precedence

Customize which headers are checked and in what order:

# Prioritize Cloudflare headers
ipware = FastAPIIpWare(
    precedence=(
        "CF-Connecting-IP",
        "X-Forwarded-For",
        "X-Real-IP",
    )
)

# NGINX configuration
ipware = FastAPIIpWare(
    precedence=(
        "X-Real-IP",
        "X-Forwarded-For",
    )
)

Proxy Count Validation

Validate that requests pass through the expected number of proxies:

# Expect exactly 1 proxy (e.g., AWS ALB).
# proxy_count=N returns the address just left of the N rightmost proxies,
# instead of the first public address, and rejects a shorter chain.
# X-Forwarded-For: 203.0.113.10, 10.0.0.1, 10.0.0.2 returns 203.0.113.10
# with no proxy_count, and 10.0.0.1 with proxy_count=1.
# default_strict applies to Depends(ipware), dependency(), and IpWareMiddleware.
ipware = FastAPIIpWare(proxy_count=1, default_strict=True)

# In strict mode, must be exactly 1 proxy
ip, trusted = ipware.get_client_ip_from_request(request, strict=True)

# In non-strict mode, allow 1 or more proxies
ip, trusted = ipware.get_client_ip_from_request(request, strict=False)

Trusted Proxy List

Validate that requests pass through specific trusted proxies (supports IP prefixes, exact IPs, and CIDR networks):

# Trust specific proxy IP prefixes or CIDR networks
ipware = FastAPIIpWare(
    proxy_list=["10.0.", "10.1.", "100.64.0.0/10"]  # AWS internal IPs and CGNAT CIDR
)

ip, trusted = ipware.get_client_ip_from_request(request)

# trusted=True only if request came through specified proxies

Combined Validation

Use both proxy count and trusted proxy list:

# Expect 1 proxy from a specific IP range
ipware = FastAPIIpWare(proxy_count=1, proxy_list=["10.0."])

Algorithm Engine Selection

Choose between python-ipware 4.x engines (auto / modern / legacy):

# Modern engine (default): enhanced header parsing and RFC 7239 support
ipware = FastAPIIpWare(algorithm="modern")

# Legacy engine: frozen byte-for-byte v3 behavior
ipware = FastAPIIpWare(algorithm="legacy")

IP Address Types

The returned IP address object has useful properties:

ip, _ = ipware.get_client_ip_from_request(request)

if ip:
    print(f"Is public: {ip.is_global}")
    print(f"Is private: {ip.is_private}")
    print(f"Is loopback: {ip.is_loopback}")
    print(f"Is multicast: {ip.is_multicast}")

python-ipware automatically prefers:

  1. Public (global) IPs first
  2. Private IPs second
  3. Loopback IPs last

License

MIT License

Credits


This project was created from iloveitaly/python-package-template

Metadata

Release files for fastapi-ipware 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fastapi-ipware 1.0.0
File Size Uploaded
fastapi_ipware-1.0.0.tar.gz 6.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fastapi-ipware 1.0.0
File Interpreter ABI Platform
fastapi_ipware-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 14.2 kB

Release files / fastapi_ipware-1.0.0.tar.gz

Download URL fastapi_ipware-1.0.0.tar.gz
Size 6.8 kB
Tags Source
SHA-256 checksum
How to use checksums
66e845d88eba958f4e1286278a4f8346239169fe1aa41cc126a4ac5e11f64bf9
BLAKE2b-256 checksum
How to use checksums
54dd29c52a79948f87dc5f8895124c7d997a0f614bc4c51aebd50a1e30bf31b4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.18 {"installer":{"name":"uv","version":"0.12.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / fastapi_ipware-1.0.0-py3-none-any.whl

Download URL fastapi_ipware-1.0.0-py3-none-any.whl
Size 7.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fd9768b89cc38e27a4077d2834669389a67cc46e7d29082145368ffcbd670b8b
BLAKE2b-256 checksum
How to use checksums
86e475d3da0844cfd1d65a31ebaa7f0bab5b84c50b469cd7eefd445546a44754
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.18 {"installer":{"name":"uv","version":"0.12.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page