PHPackages                             jasny/forwarded-middleware - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. jasny/forwarded-middleware

ActiveLibrary[HTTP &amp; Networking](/categories/http)

jasny/forwarded-middleware
==========================

Server middleware to handle Forwarded header for PSR-7 requests

v0.1.0(6y ago)14.1k↓87.5%MITPHPPHP &gt;=7.2.0

Since Oct 24Pushed 5y ago1 watchersCompare

[ Source](https://github.com/jasny/forwarded-middleware)[ Packagist](https://packagist.org/packages/jasny/forwarded-middleware)[ RSS](/packages/jasny-forwarded-middleware/feed)WikiDiscussions master Synced 3w ago

READMEChangelog (1)Dependencies (3)Versions (2)Used By (0)

Forwarded Middleware
====================

[](#forwarded-middleware)

[![Build Status](https://camo.githubusercontent.com/8065ad94692ced6b8030f161c624be8f207d4d9714aa7dc4a033efb89b8c4b9e/68747470733a2f2f7472617669732d63692e6f72672f6a61736e792f666f727761726465642d6d6964646c65776172652e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/jasny/forwarded-middleware)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/0fa2f646771e64bedc40f5a2688737e048cbf45377671501f72510056e7832ea/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6a61736e792f666f727761726465642d6d6964646c65776172652f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/jasny/forwarded-middleware/?branch=master)[![Code Coverage](https://camo.githubusercontent.com/0d26ddcafc3d61457001b53684d0ceb503e401530a1884a04e17763c9d5485ec/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6a61736e792f666f727761726465642d6d6964646c65776172652f6261646765732f636f7665726167652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/jasny/forwarded-middleware/?branch=master)[![Packagist Stable Version](https://camo.githubusercontent.com/cd1b1082fdceabdf4707f02e573bc18346313deb1b6ae4913907d5c5dadaab16/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6a61736e792f666f727761726465642d6d6964646c65776172652e737667)](https://packagist.org/packages/jasny/forwarded-middleware)[![Packagist License](https://camo.githubusercontent.com/76b56ac73a515e5141af9d49c666d9bc44a68e5a44f47228417638e605f90372/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6a61736e792f666f727761726465642d6d6964646c65776172652e737667)](https://packagist.org/packages/jasny/forwarded-middleware)

Server middleware to process the `Forwarded` header for PSR-7 requests. Works both as PSR-15 and double pass middleware.

The middleware set the `client_ip` and `original_url` attributes for the server request. Also supports non-standard `X-Forwarded-*` and other custom headers.

Installation
------------

[](#installation)

```
composer require jasny/forwarded-middleware

```

Usage
-----

[](#usage)

```
use Wikimedia\IPSet;
use Jasny\Forwarded;
use Zend\Stratigility\MiddlewarePipe;
use Zend\Diactoros\ResponseFactory;

$trustIps = new IPSet(['208.80.154.0/26', '2620:0:861:1::/64', '10.64.0.0/22']);

$middleware = new Forwarded\Middleware(function (string $ip, array $forward) use ($trustedIps) {
    return $trustedIps->match($ip);
});

$app = new MiddlewarePipe();
$app->pipe($middleware);
```

#### Trusted proxies

[](#trusted-proxies)

The constructor takes a callback as only argument, which is called for each forward (separated by a comma) in the `Forwarded` header. Each forward should have a `for` directive and may have other directives like `port` and `proto`.

The first argument of the callback is the ip of the proxy server. The second argument contains the directives of this forward as associative array.

The initial value of the ip is taken from the `REMOTE_ADDR` server parameter. For each subsequent call gives the value of the `for` directive from the previous trusted forward.

> **Example**
>
> ```
> Forwarded: for=75.84.3.2,for=92.53.34.1,for=32.5.86.102,for=10.64.0.23
> Client IP (REMOTE_ADDR) is 208.80.154.8
>
> ```
>
>
>
> This results in the following calls
>
> ```
> fn("208.80.154.8", ['for' => "10.64.0.23"]);  // true
> fn("10.64.0.23", ['for' => "32.5.86.102"]);   // true
> fn("32.5.86.102", ['for' => "92.53.34.1"]);   // false
> ```
>
>
>
> The `client_id` is set to `"32.5.86.102"`. Note that the `for=75.84.3.2` forward isn't considered.

It's not required to trust based on IP. Alternatively you can check if the proxy has set a secret.

```
$middleware = new Forwarded\Middleware(function (string $ip, array $forward) {
    return $forward['secret'] === getenv('PROXY_SECRET');
});
```

#### Original uri

[](#original-uri)

Besides `client_ip`, the middleware will also set the `original_uri` attribute. This attribute is a PSR-7 URI object based on the URI of the request.

The `proto` and `host`, as well as the non-standard `path` and `port` directives are applied to create the original uri. If the `port` is the standard port for the `proto` (80 for "http" and 443 for https), it's omitted.

Only the directives of the last trusted proxy are used;

> **Example**
>
> ```
> HTTP/1.1 GET /foo
> Host: x9.example.com
> Forwarded: for=92.53.34.1, for=32.5.86.102;proto=https;port=443;host=example.com;path=/x/foo, for=10.64.0.23;proto=http;port=8080
>
> ```
>
>
>
> The `original_uri` attribute will be ""

The uri of the server request is not altered.

### Non-standard headers

[](#non-standard-headers)

Use `CompatMiddleware` in case your proxy sets `X-Forwarded-*` headers. This middleware will convert these headers to a `Forwarded` header.

```
use Wikimedia\IPSet;
use Jasny\Forwarded;
use Zend\Stratigility\MiddlewarePipe;
use Zend\Diactoros\ResponseFactory;

$trustIps = new IPSet(['208.80.154.0/26', '2620:0:861:1::/64', '10.64.0.0/22']);

$compatMiddleware = new Forwarded\CompatMiddleware();
$middleware = new Forwarded\Middleware(function (string $ip, array $forward) use ($trustedIps) {
    return $trustedIps->match($ip);
});

$app = new MiddlewarePipe();
$app->pipe($compatMiddleware);
$app->pipe($middleware);
```

By default the compat middleware uses the following headers

- `X-Forwared-For`
- `X-Forwarded-Proto`
- `X-Forwarded-Host`

#### Custom headers

[](#custom-headers)

If your proxy uses other headers, you can pass custom mapping to constructor

```
$compatMiddleware = new Forwarded\CompatMiddleware([
    'X-Client-IP' => 'for,
    'X-Forwarded-For' => 'for',
    'X-Forwarded-Proto' => 'proto',
    'X-Forwarded-Port' => 'port',
]);
```

If there are multiple headers for the same directive, the first header that's found is used. In the example above, if there is an `X-Client-IP`, the `X-Forwarded-For` header is not used.

The compat middleware supports multiple entries for any header that maps to the `for` directive. All other directives are applied to the first entry. This may not work as expected if `X-Forwarded-For` contains entries for both trusted and untrusted proxies.

The compat middleware will always replace or remove an existing `Forwarded` header. Typically a proxy either sets the `Forwarded` header or uses non-standard headers. Allowing both can lead to a security issue.

### Double pass middleware

[](#double-pass-middleware)

Some PHP libraries support double pass middleware instead of PSR-15 and a callable with the following signature;

```
fn(ServerRequestInterface $request, ResponseInterface $response, callable $next): ResponseInterface
```

To get a callback to be used by libraries as [Jasny Router](https://github.com/jasny/router) and [Relay v1](http://relayphp.com/), use the `asDoublePass()` method.

```
use Jasny\Forwarded;
use Relay\RelayBuilder;

$middleware = new Forwarded\Middleware(function ($ip, $forward) { /* ... */ });

$relayBuilder = new RelayBuilder($resolver);
$relay = $relayBuilder->newInstance([
    $middleware->asDoublePass(),
]);

$response = $relay($request, $baseResponse);
```

`CompatMiddleware` also has an `asDoublePass()` method.

###  Health Score

25

—

LowBetter than 35% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity21

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

2444d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/3379a93d51305df325df9045e1a8b205d195e4e8c01312dff53a000ee79002eb?d=identicon)[jasny](/maintainers/jasny)

---

Top Contributors

[![jasny](https://avatars.githubusercontent.com/u/100821?v=4)](https://github.com/jasny "jasny (6 commits)")

### Embed Badge

![Health badge](/badges/jasny-forwarded-middleware/health.svg)

```
[![Health](https://phpackages.com/badges/jasny-forwarded-middleware/health.svg)](https://phpackages.com/packages/jasny-forwarded-middleware)
```

###  Alternatives

[guzzlehttp/psr7

PSR-7 message implementation that also provides common utility methods

8.0k1.1B4.0k](/packages/guzzlehttp-psr7)[mezzio/mezzio

PSR-15 Middleware Microframework

3923.8M125](/packages/mezzio-mezzio)[neuron-core/neuron-ai

The PHP Agentic Framework.

2.0k656.1k38](/packages/neuron-core-neuron-ai)[hyperf/hyperf

A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.

6.9k3.3k2](/packages/hyperf-hyperf)[sunrise/http-router

A powerful solution as the foundation of your project.

17451.6k10](/packages/sunrise-http-router)[telnyx/telnyx-php

Official Telnyx PHP SDK — APIs for Voice, SMS, MMS, WhatsApp, Fax, SIP Trunking, Wireless IoT, Call Control, and more. Build global communications on Telnyx's private carrier-grade network.

35789.4k2](/packages/telnyx-telnyx-php)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
