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

ActiveLibrary

apigopro/slim-cors-middleware
=============================

PSR-15 CORS middleware for Slim Framework 4, spiritual successor to tuupola/cors-middleware.

v1.0.1(1mo ago)02MITPHPPHP ^8.5

Since Jul 14Pushed 1mo agoCompare

[ Source](https://github.com/apigopro/slim-cors-middleware)[ Packagist](https://packagist.org/packages/apigopro/slim-cors-middleware)[ RSS](/packages/apigopro-slim-cors-middleware/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (5)Versions (3)Used By (0)

apigopro/slim-cors-middleware
=============================

[](#apigoproslim-cors-middleware)

A PSR-15 CORS middleware for **Slim Framework 4**, requiring **PHP 8.5**.

Spiritual successor to [`tuupola/cors-middleware`](https://github.com/tuupola/cors-middleware)(unmaintained) — same array-based options and behavior, rebuilt as a small, dependency-free PSR-15 middleware with no legacy baggage.

Install
-------

[](#install)

Published on Packagist.

```
composer require apigopro/slim-cors-middleware
```

Basic usage
-----------

[](#basic-usage)

```
use SlimCors\CorsMiddleware;

$app->add(new CorsMiddleware([
    'origin'         => ['https://app.example.com', 'https://*.example.com'],
    'methods'        => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
    'headers.allow'  => ['Authorization', 'Content-Type'],
    'headers.expose' => ['X-Request-Id'],
    'credentials'    => true,
    'cache'          => 86400,
]));
```

Add this **before** (outer to) your auth middleware, so preflight `OPTIONS` requests get answered without ever reaching auth checks or route handlers — browsers send preflight requests without credentials or custom auth headers, so they'd otherwise fail auth for no reason.

```
$app->add(new CorsMiddleware([/* ... */]));   // outermost
$app->add(new JwtAuthMiddleware([/* ... */])); // runs after CORS
```

How it works
------------

[](#how-it-works)

- **No `Origin` header** → not a cross-origin request, passed through untouched.
- **`Origin` present, not preflight** → the wrapped handler runs as normal, then `Access-Control-Allow-Origin` (and friends) get added to the response.
- **Preflight** (`OPTIONS` + `Access-Control-Request-Method` header present) → answered directly with a `204`, without calling the rest of the middleware stack or your route handler at all.
- **Preflight requesting a method not in `methods`** → rejected with `405` and an `Allow` header listing what *is* allowed (or your custom `error` response).
- **Origin not in the allow-list** → rejected with `401` (or your custom `error` response).

Options
-------

[](#options)

OptionDefaultNotes`origin``['*']`Allowed origins. Exact strings, or patterns with a `*` wildcard, e.g. `'https://*.example.com'`.`methods``['GET', 'POST', 'PUT', 'PATCH', 'DELETE']`Sent as `Access-Control-Allow-Methods` on preflight responses. A preflight requesting a method outside this list gets rejected with `405` instead. Use `['*']` to allow any method.`headers.allow``[]`Sent as `Access-Control-Allow-Headers` on preflight responses. If empty, whatever the browser asked for via `Access-Control-Request-Headers` is reflected back.`headers.expose``[]`Sent as `Access-Control-Expose-Headers` on actual (non-preflight) responses.`credentials``false`Sends `Access-Control-Allow-Credentials: true` when enabled. Also makes a configured `origin => ['*']` reflect the actual request origin instead of a literal `*`, since browsers reject the literal wildcard combined with credentials.`cache``0`Seconds for `Access-Control-Max-Age` on preflight responses. `0` omits the header.`error``null``function($request, $response, array $arguments): ?ResponseInterface`. Called when the origin isn't allowed (`$arguments` has `message`, `origin`) or when a preflight's requested method isn't allowed (`$arguments` has `message`, `method`, `allowed_methods`). Return a response to override the default `401`/`405`.`response_factory`*(auto-detects `slim/psr7`)*Any PSR-17 `ResponseFactoryInterface`.Wildcard origin patterns
------------------------

[](#wildcard-origin-patterns)

```
new CorsMiddleware([
    'origin' => [
        'https://app.example.com',
        'https://*.staging.example.com', // any staging subdomain
    ],
]);
```

`*` matches any sequence of characters within a single pattern; it isn't a full glob/regex language, just a simple prefix/suffix/subdomain wildcard.

Migrating from tuupola/cors-middleware
--------------------------------------

[](#migrating-from-tuupolacors-middleware)

- **Namespace**: `Tuupola\Middleware\CorsMiddleware` → `SlimCors\CorsMiddleware`.
- **`logger` option removed.** Wire up your own logging in the `error` callback if you need it.
- **`error` callback signature is unchanged**: `($request, $response, array $arguments)`.
- Everything else — `origin`, `methods`, `headers.allow`, `headers.expose`, `credentials`, `cache`— behaves the same way.

Testing
-------

[](#testing)

```
composer install
composer test
```

Covers: pass-through for non-CORS requests, allowed/disallowed origins, wildcard origin patterns (including the credentials + `*` interaction), preflight short-circuiting, method validation (`405` for disallowed methods, wildcard `*` methods, case-insensitive matching), configured vs. reflected `Access-Control-Allow-Headers`, `Access-Control-Expose-Headers`, and custom `error`callbacks for both origin and method rejections.

License
-------

[](#license)

MIT.

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance90

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity52

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

Every ~0 days

Total

2

Last Release

47d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/52b826a6fec331f780189b1319e7be4fedadf89d17a6087b09fbe7dee0308df9?d=identicon)[vuckoo81](/maintainers/vuckoo81)

---

Top Contributors

[![apigopro](https://avatars.githubusercontent.com/u/10329971?v=4)](https://github.com/apigopro "apigopro (7 commits)")

---

Tags

middlewarecorsslimpsr-15

###  Code Quality

TestsPHPUnit

### Embed Badge

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

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

###  Alternatives

[cakephp/cakephp

The CakePHP framework

8.9k20.4M1.9k](/packages/cakephp-cakephp)[typo3/cms

TYPO3 CMS is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.

1.2k1.9M122](/packages/typo3-cms)[typo3/cms-core

TYPO3 CMS Core

3714.0M5.8k](/packages/typo3-cms-core)[mcp/sdk

Model Context Protocol SDK for Client and Server applications in PHP

1.6k3.0M157](/packages/mcp-sdk)[cakephp/authentication

Authentication plugin for CakePHP

1184.6M126](/packages/cakephp-authentication)[typo3/cms-adminpanel

TYPO3 CMS Admin Panel - The Admin Panel displays information about your site in the frontend and contains a range of metrics including debug and caching information.

115.9M74](/packages/typo3-cms-adminpanel)

PHPackages © 2026

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