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↓85.7%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 1w 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

24

—

LowBetter than 32% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity18

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity42

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

2398d 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

[league/uri-interfaces

Common tools for parsing and resolving RFC3987/RFC3986 URI

536204.9M23](/packages/league-uri-interfaces)[mezzio/mezzio

PSR-15 Middleware Microframework

3883.6M97](/packages/mezzio-mezzio)[mezzio/mezzio-authentication-oauth2

OAuth2 (server) authentication middleware for Mezzio and PSR-7 applications.

28483.0k2](/packages/mezzio-mezzio-authentication-oauth2)[openswoole/core

Openswoole core library

181.1M32](/packages/openswoole-core)[mezzio/mezzio-authentication

Authentication middleware for Mezzio and PSR-7 applications

121.6M26](/packages/mezzio-mezzio-authentication)[jimtools/jwt-auth

PSR-15 JWT Authentication middleware, A replacement for tuupola/slim-jwt-auth

20142.3k3](/packages/jimtools-jwt-auth)

PHPackages © 2026

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