PHPackages                             tuupola/cors-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. tuupola/cors-middleware

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

tuupola/cors-middleware
=======================

PSR-7 and PSR-15 CORS middleware

1.5.0(1y ago)1331.8M—1.3%20[6 issues](https://github.com/tuupola/cors-middleware/issues)[2 PRs](https://github.com/tuupola/cors-middleware/pulls)20MITPHPPHP ^7.2|^8.0CI passing

Since Apr 25Pushed 5mo ago5 watchersCompare

[ Source](https://github.com/tuupola/cors-middleware)[ Packagist](https://packagist.org/packages/tuupola/cors-middleware)[ Docs](https://github.com/tuupola/cors-middleware)[ RSS](/packages/tuupola-cors-middleware/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (13)Versions (26)Used By (20)

PSR-7 and PSR-15 CORS Middleware
================================

[](#psr-7-and-psr-15-cors-middleware)

This middleware implements [Cross-origin resource sharing](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing). It supports both PSR-7 style doublepass and PSR-15 middleware standards. It has been tested with [Slim Framework](http://www.slimframework.com/) and [Zend Expressive](https://zendframework.github.io/zend-expressive/). Internally the middleware uses [neomerx/cors-psr7](https://github.com/neomerx/cors-psr7) library for heavy lifting.

[![Latest Version](https://camo.githubusercontent.com/8b0d2eef00abeffb2456407f3a8b3fd8ad6f7b16b315a6867c98adfd6635e584/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f747575706f6c612f636f72732d6d6964646c65776172652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/tuupola/cors-middleware)[![Packagist](https://camo.githubusercontent.com/c09708b387c553581ce92a94c51612dbefc6647b461237094364e38a3512e8cf/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646d2f747575706f6c612f636f72732d6d6964646c65776172652e737667)](https://packagist.org/packages/tuupola/cors-middleware)[![Software License](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE)[![Build Status](https://camo.githubusercontent.com/27b0c5cd25ad659548eec11cbbc2a4f84d91368ec4286219ebcdc997c561e484/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f747575706f6c612f636f72732d6d6964646c65776172652f74657374732e796d6c3f6272616e63683d6d6173746572267374796c653d666c61742d737175617265)](https://github.com/tuupola/cors-middleware/actions)[![Coverage](https://camo.githubusercontent.com/0955b81de802cf5d5dd645b6d8c5de9eaaaf7d0308db42365dc5061881fd696a/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f747575706f6c612f636f72732d6d6964646c65776172652e7376673f7374796c653d666c61742d737175617265)](https://codecov.io/github/tuupola/cors-middleware)

Install
-------

[](#install)

Install using [composer](https://getcomposer.org/).

```
$ composer require tuupola/cors-middleware
```

Usage
-----

[](#usage)

Documentation assumes you have working knowledge of CORS. There are no mandatory parameters. If you are using Zend Expressive skeleton middlewares are added to file called `config/pipeline.php`. Note that you must disable the default `ImplicitOptionsMiddleware` for this middleware to work.

```
use Tuupola\Middleware\CorsMiddleware;

#$app->pipe(ImplicitOptionsMiddleware::class);
$app->pipe(CorsMiddleware::class);
```

Slim Framework does not have specified config files. Otherwise adding the middleware is similar with previous.

```
$app->add(new Tuupola\Middleware\CorsMiddleware);
```

Rest of the examples use Slim Framework.

If called without any parameters the following defaults are used.

```
$app->add(new Tuupola\Middleware\CorsMiddleware([
    "origin" => ["*"],
    "methods" => ["GET", "POST", "PUT", "PATCH", "DELETE"],
    "headers.allow" => [],
    "headers.expose" => [],
    "credentials" => false,
    "cache" => 0,
]));
```

```
$ curl "https://api.example.com/" \
    --request OPTIONS \
    --include
    --header "Access-Control-Request-Method: PUT" \
    --header "Origin: http://www.example.com"

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.example.com
Vary: Origin
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE
```

However, you most likely want to change some of the defaults. For example if developing a REST API which supports caching and conditional requests you could use the following.

```
$app->add(new Tuupola\Middleware\CorsMiddleware([
    "origin" => ["*"],
    "methods" => ["GET", "POST", "PUT", "PATCH", "DELETE"],
    "headers.allow" => ["Authorization", "If-Match", "If-Unmodified-Since"],
    "headers.expose" => ["Etag"],
    "credentials" => true,
    "cache" => 86400
]));
```

```
$ curl "https://api.example.com/foo" \
    --request OPTIONS \
    --include \
    --header "Origin: http://www.example.com" \
    --header "Access-Control-Request-Method: PUT" \
    --header "Access-Control-Request-Headers: Authorization, If-Match"

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.example.com
Access-Control-Allow-Credentials: true
Vary: Origin
Access-Control-Max-Age: 86400
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE
Access-Control-Allow-Headers: authorization, if-match, if-unmodified-since
```

```
$ curl "https://api.example.com/foo" \
    --request PUT \
    --include \
    --header "Origin: http://www.example.com"

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.example.com
Access-Control-Allow-Credentials: true
Vary: Origin
Access-Control-Expose-Headers: Etag
```

Parameters
----------

[](#parameters)

### Origin

[](#origin)

By default all origins are allowed. You can limit allowed origins by passing them as an array.

```
$app->add(new Tuupola\Middleware\CorsMiddleware([
    "origin" => ["app-1.example.com", "app-2.example.com"]
]));
```

You can also use wildcards to define multiple origins at once. Wildcards are matched by using the [fnmatch()](https://www.php.net/manual/en/function.fnmatch.php) function.

```
$app->add(new Tuupola\Middleware\CorsMiddleware([
    "origin" => ["*.example.com"]
]));
```

### Methods

[](#methods)

Methods can be passed either as an array or a callable which returns an array. Below example is for Zend Expressive where value of `methods` is dynamic depending on the requested route.

```
use Tuupola\Middleware\CorsMiddleware;
use Zend\Expressive\Router\RouteResult;

$app->pipe(new CorsMiddleware([
    "origin" => ["*"],
    "methods" => function($request) {
        $result = $request->getAttribute(RouteResult::class);
        $route = $result->getMatchedRoute();
        return $route->getAllowedMethods();
    }
]));
```

Same thing for Slim 3. This assumes you have **not** defined the `OPTIONS` route.

```
use Fastroute\Dispatcher;
use Tuupola\Middleware\CorsMiddleware;

$app->add(
    new CorsMiddleware([
        "origin" => ["*"],
        "methods" => function($request) use ($app) {
            $container = $app->getContainer();
            $dispatch = $container["router"]->dispatch($request);
            if (Dispatcher::METHOD_NOT_ALLOWED === $dispatch[0]) {
                return $dispatch[1];
            }
        }
    ])
);
```

### Logger

[](#logger)

The optional `logger` parameter allows you to pass in a PSR-3 compatible logger to help with debugging or other application logging needs.

```
$logger = Monolog\Logger("slim");
$rotating = new RotatingFileHandler(__DIR__ . "/logs/slim.log", 0, Logger::DEBUG);
$logger->pushHandler($rotating);

$app->add(new Tuupola\Middleware\CorsMiddleware([
    "logger" => $logger,
]));
```

### Error

[](#error)

Error is called when CORS request fails. It receives last error message in arguments. This can be used for example to create `application/json` responses when CORS request fails.

```
$app->add(new Tuupola\Middleware\CorsMiddleware([
    "methods" => ["GET", "POST", "PUT"],
    "error" => function ($request, $response, $arguments) {
        $data["status"] = "error";
        $data["message"] = $arguments["message"];
        return $response
            ->withHeader("Content-Type", "application/json")
            ->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
    }
]));
```

```
$ curl https://api.example.com/foo \
    --request OPTIONS \
    --include \
    --header "Access-Control-Request-Method: PATCH" \
    --header "Origin: http://www.example.com"

HTTP/1.1 401 Unauthorized
Content-Type: application/json
Content-Length: 83

{
    "status": "error",
    "message": "CORS requested method is not supported."
}

```

### Server origin

[](#server-origin)

If your same-origin requests contain an unnecessary `Origin` header, they might get blocked in case the server origin is not among the allowed origins already. In this case you can use the optional `origin.server` parameter to specify the origin of the server.

```
$app->add(new Tuupola\Middleware\CorsMiddleware([
    "origin.server" => "https://example.com"
]));
```

```
$ curl https://example.com/api \
    --request POST \
    --include \
    --header "Origin: https://example.com"

HTTP/1.1 200 OK

```

Testing
-------

[](#testing)

You can run tests either manually or automatically on every code change. Automatic tests require [entr](http://entrproject.org/) to work.

```
$ make test
```

```
$ brew install entr
$ make watch
```

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Security
--------

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE) for more information.

###  Health Score

60

—

FairBetter than 99% of packages

Maintenance58

Moderate activity, may be stable

Popularity56

Moderate usage in the ecosystem

Community32

Small or concentrated contributor base

Maturity78

Established project with proven stability

 Bus Factor1

Top contributor holds 92.1% 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

Every ~153 days

Recently: every ~215 days

Total

22

Last Release

459d ago

Major Versions

0.9.4 → 1.0.02019-06-04

PHP version history (6 changes)0.5.0PHP &gt;=5.4.0

0.5.1PHP &gt;=5.5.0

0.5.2PHP ^5.5 || ^7.0

0.6.0PHP ^7.1

1.2.0PHP ^7.1|^8.0

1.4.0PHP ^7.2|^8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/3325405a7d8a43bc40dd0e760a4b7f268fba32a7150cf0327f64f13d1661df0b?d=identicon)[tuupola](/maintainers/tuupola)

---

Top Contributors

[![tuupola](https://avatars.githubusercontent.com/u/21913?v=4)](https://github.com/tuupola "tuupola (129 commits)")[![usox](https://avatars.githubusercontent.com/u/5184763?v=4)](https://github.com/usox "usox (3 commits)")[![jankonas](https://avatars.githubusercontent.com/u/7345659?v=4)](https://github.com/jankonas "jankonas (3 commits)")[![mikhailidi](https://avatars.githubusercontent.com/u/12273645?v=4)](https://github.com/mikhailidi "mikhailidi (2 commits)")[![Pnoexz](https://avatars.githubusercontent.com/u/3297901?v=4)](https://github.com/Pnoexz "Pnoexz (1 commits)")[![dakujem](https://avatars.githubusercontent.com/u/443067?v=4)](https://github.com/dakujem "dakujem (1 commits)")[![fabacino](https://avatars.githubusercontent.com/u/14901115?v=4)](https://github.com/fabacino "fabacino (1 commits)")

---

Tags

psr-7middlewarecorspsr-15

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Code StyleECS

Type Coverage Yes

### Embed Badge

![Health badge](/badges/tuupola-cors-middleware/health.svg)

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

###  Alternatives

[tuupola/slim-basic-auth

PSR-7 and PSR-15 HTTP Basic Authentication Middleware

4442.0M26](/packages/tuupola-slim-basic-auth)[mezzio/mezzio

PSR-15 Middleware Microframework

3883.6M97](/packages/mezzio-mezzio)[relay/relay

A PSR-15 server request handler.

3302.1M86](/packages/relay-relay)[hkarlstrom/openapi-validation-middleware

PSR-7 and PSR-15 OpenAPI Validation Middleware

95198.8k1](/packages/hkarlstrom-openapi-validation-middleware)[laminas/laminas-stratigility

PSR-7 middleware foundation for building and dispatching middleware pipelines

586.6M81](/packages/laminas-laminas-stratigility)[mezzio/mezzio-authentication

Authentication middleware for Mezzio and PSR-7 applications

121.6M26](/packages/mezzio-mezzio-authentication)

PHPackages © 2026

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