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

trusted is true only when the request came through the proxies configured with proxy_count or proxy_list.

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.

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)]):
    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).
# 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

Release files for fastapi-ipware 0.2.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 0.2.0
File Size Uploaded
fastapi_ipware-0.2.0.tar.gz 6.6 kB Details

Built distribution (wheel)

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

Total release size: 13.9 kB

Release files / fastapi_ipware-0.2.0.tar.gz

Download URL fastapi_ipware-0.2.0.tar.gz
Size 6.6 kB
Tags Source
SHA-256 checksum
How to use checksums
0d0e4df5081bd687390112647bf6bc4c5fc6f4bfb14e182fe3dd5f7fbab96183
BLAKE2b-256 checksum
How to use checksums
6dde40fef655885cddba11088877982c0811c5d631739934137127994c083b66
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-0.2.0-py3-none-any.whl

Download URL fastapi_ipware-0.2.0-py3-none-any.whl
Size 7.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6ae335acc7560b801b04c5ddfa0c741f468df75f0887cf1558f512ce6c175a03
BLAKE2b-256 checksum
How to use checksums
fe23a7669256e73c209d0fa3f33e5170ed5219410f6d08f59441e9051faa65e9
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

0.2.0 This release

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