PHPackages                             cube43/slim-jwt-auth - 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. cube43/slim-jwt-auth

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

cube43/slim-jwt-auth
====================

PSR-7 and PSR-15 JWT Authentication Middleware

6.0.0(2y ago)17.2k↑100%MITPHPPHP ~8.1.0 || ~8.2.0 || ~8.3.0CI failing

Since Mar 22Pushed 3mo agoCompare

[ Source](https://github.com/cube43/slim-jwt-auth)[ Packagist](https://packagist.org/packages/cube43/slim-jwt-auth)[ Docs](https://github.com/tuupola/slim-jwt-auth)[ RSS](/packages/cube43-slim-jwt-auth/feed)WikiDiscussions 7.x Synced 1mo ago

READMEChangelog (4)Dependencies (13)Versions (12)Used By (0)

Slim JWT Auth
=============

[](#slim-jwt-auth)

[![Build Status](https://github.com/cube43/slim-jwt-auth/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/cube43/slim-jwt-auth/actions/workflows/continuous-integration.yml)[![Type Coverage](https://camo.githubusercontent.com/6acbd1860fb1496547d96a14753084e8ba29d157b07a852d4d45ce9dbafdd6a5/68747470733a2f2f73686570686572642e6465762f6769746875622f6375626534332f736c696d2d6a77742d617574682f636f7665726167652e737667)](https://shepherd.dev/github/cube43/slim-jwt-auth)[![Type Coverage](https://camo.githubusercontent.com/63fa79b5af7502d32a6242d70ee1d1b476d5239ff7a0f83fa46a5d2dfc3ced78/68747470733a2f2f73686570686572642e6465762f6769746875622f6375626534332f736c696d2d6a77742d617574682f6c6576656c2e737667)](https://shepherd.dev/github/cube43/slim-jwt-auth)[![Latest Stable Version](https://camo.githubusercontent.com/87de57e15420b72414844de0f8bea19a41ec61d32d00f2cc691e15fe7bff7a0d/68747470733a2f2f706f7365722e707567782e6f72672f6375626534332f736c696d2d6a77742d617574682f762f737461626c65)](https://packagist.org/packages/cube43/slim-jwt-auth)[![License](https://camo.githubusercontent.com/95792f519954012d5c519c7803911815b594913ca99313e8387c69c349c98407/68747470733a2f2f706f7365722e707567782e6f72672f6375626534332f736c696d2d6a77742d617574682f6c6963656e7365)](https://packagist.org/packages/cube43/slim-jwt-auth)

PSR-7 and PSR-15 Middleware for JWT Authentication. This is a strict-typed, modern rewrite of the popular JWT middleware, designed for Slim Framework and other PSR-15 compliant frameworks.

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

[](#installation)

Install via Composer:

```
composer require cube43/slim-jwt-auth
```

Usage
-----

[](#usage)

This library splits the JWT logic into two separate middlewares to provide better flexibility:

1. **`JwtAuthentication`**: Parses and validates the token. If valid, it attaches the decoded token to the request tokenAttributeNames. It does **not** block the request if the token is missing (it acts as a hydrator).
2. **`JwtAuthentificationFirewall`**: Checks if the request requires authentication (based on rules). If it does, and no valid token was found by the previous middleware, it returns a 401 Unauthorized response.

### Complete Example

[](#complete-example)

Here is a complete example setup for Slim 4, including custom handlers and rules:

```
use Slim\Factory\AppFactory;
use Tuupola\Middleware\JwtAuthentication;
use Tuupola\Middleware\JwtAuthenticationOption;
use Tuupola\Middleware\JwtAuthentificationFirewall;
use Tuupola\Middleware\JwtAuthentication\FetchTokenFormHeader;
use Tuupola\Middleware\JwtAuthentication\RequestPathRule;
use Tuupola\Middleware\JwtAuthentificationUnAuthorizedHandler;
use Tuupola\Middleware\JwtAuthentificationBeforeHandler;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Token\Plain;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Laminas\Diactoros\Response;
use Throwable;

$app = AppFactory::create();

// 1. Configure Options
$options = JwtAuthenticationOption::create(InMemory::plainText('super-secret-key'))
    ->withTokenAttributeName('jwt')
    ->withAllowedInsecureHosts(['localhost', '127.0.0.1'])
    ->withBeforeHandleRequestWhenTokenAvailable(new class implements JwtAuthentificationBeforeHandler {
        public function __invoke(ServerRequestInterface $request, Plain $token): ServerRequestInterface
        {
            assert($request->getAttribute('jwt') === $token);
            return $request->withAttribute('user_uuid', $token->claims()->get('uuid'));
        }
    });

// 2. Define Rules (e.g. protect /api, but allow /api/login)
$pathRule = new RequestPathRule(
    path: ['/api'],
    ignore: ['/api/login', '/api/token']
);

// 3. Define Unauthorized Handler (JSON response)
$unauthorizedHandler = new class implements JwtAuthentificationUnAuthorizedHandler {
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, Throwable $exception): ResponseInterface
    {
        $response->getBody()->write(json_encode(['status' => 'error', 'message' => 'Unauthorized']));
        return $response->withHeader('Content-Type', 'application/json');
    }
};

// 4. Add Middleware (LIFO: Add Firewall first, then Authentication)

// Firewall: Checks rules and blocks if no token is present when required
// It runs LAST in the stack (executed AFTER Authentication)
$app->add(new JwtAuthentificationFirewall(
    $options,
    new Response(),
    $unauthorizedHandler,
    $pathRule
));

// Authentication: Extracts and decodes token
// It runs FIRST in the stack (executed BEFORE Firewall)
$app->add(JwtAuthentication::create(
    $options,
    new FetchTokenFormHeader()
));

$app->run();
```

> **Important:** In Slim, middleware is executed Last-In-First-Out. You must ensure `JwtAuthentication` runs **before** `JwtAuthentificationFirewall` so the token is available when the firewall checks for it.

### Configuration Options

[](#configuration-options)

The `JwtAuthenticationOption` class uses a fluent interface for configuration.

```
$options = JwtAuthenticationOption::create(InMemory::plainText('secret'))
    ->withTokenAttributeName('jwt')       // Attribute name for the decoded token
    ->withEnforceHttps(true)           // Require HTTPS
    ->withAllowedInsecureHosts(['localhost']); // Allow HTTP on these hosts
```

### Token Extraction

[](#token-extraction)

You define how the token is extracted when creating the `JwtAuthentication` middleware. You can pass multiple extractors.

```
use Tuupola\Middleware\JwtAuthentication\FetchTokenFormHeader;
use Tuupola\Middleware\JwtAuthentication\FetchTokenFormCookie;

$app->add(JwtAuthentication::create(
    $options,
    new FetchTokenFormHeader('Authorization', '/Bearer\s+(.*)$/i'),
    new FetchTokenFormCookie('auth_token')
));
```

### Firewall Rules

[](#firewall-rules)

To define which requests require authentication, pass `RuleInterface` implementations to the `JwtAuthentificationFirewall` constructor.

#### Path Rule

[](#path-rule)

Restrict authentication to specific paths, or ignore specific paths.

```
use Tuupola\Middleware\JwtAuthentication\RequestPathRule;

// Authenticate everything under /api, but ignore /api/login
$pathRule = new RequestPathRule(
    path: ['/api'],
    ignore: ['/api/login']
);

$app->add(new JwtAuthentificationFirewall(
    $options,
    $response,
    new NullUnAuthorizedHandler(), // Default handler
    $pathRule
));
```

#### Method Rule

[](#method-rule)

Ignore specific HTTP methods (e.g., OPTIONS).

```
use Tuupola\Middleware\JwtAuthentication\IgnoreHttpMethodRule;

$methodRule = new IgnoreHttpMethodRule(['OPTIONS']);

$app->add(new JwtAuthentificationFirewall(
    $options,
    $response,
    new NullUnAuthorizedHandler(),
    $pathRule,
    $methodRule
));
```

### Handlers

[](#handlers)

You can customize behavior using handlers.

#### Before Handler

[](#before-handler)

Modify the request after the token is decoded but before the next middleware.

```
use Tuupola\Middleware\JwtAuthentificationBeforeHandler;
use Lcobucci\JWT\Token\Plain;

$options = $options->withBeforeHandleRequestWhenTokenAvailable(new class implements JwtAuthentificationBeforeHandler {
    public function __invoke(ServerRequestInterface $request, Plain $token): ServerRequestInterface
    {
        assert($request->getAttribute('jwt') === $token);
        return $request->withAttribute('user_id', $token->claims()->get('uid'));
    }
});
```

#### After Handler

[](#after-handler)

Modify the response before returning it.

```
use Tuupola\Middleware\JwtAuthentificationAfterHandler;

$options = $options->withAfterHandleRequestWhenTokenAvailable(new class implements JwtAuthentificationAfterHandler {
    public function __invoke(ResponseInterface $response, Plain $token): ResponseInterface
    {
        return $response->withHeader('X-Auth-Success', 'true');
    }
});
```

#### Unauthorized Handler

[](#unauthorized-handler)

Customize the response when authentication fails (used by the Firewall).

```
use Tuupola\Middleware\JwtAuthentificationUnAuthorizedHandler;

$firewall = new JwtAuthentificationFirewall(
    $options,
    $response,
    new class implements JwtAuthentificationUnAuthorizedHandler {
        public function __invoke(ServerRequestInterface $request, ResponseInterface $response, Throwable $exception): ResponseInterface
        {
            $response->getBody()->write(json_encode(['error' => 'Unauthorized']));
            return $response->withHeader('Content-Type', 'application/json');
        }
    }
);
```

Security
--------

[](#security)

By default, the middleware throws a `RuntimeException` if you attempt to use it over HTTP (insecure). To allow HTTP for development, use `withAllowedInsecureHosts`:

```
$options = $options->withAllowedInsecureHosts(['localhost', '127.0.0.1']);
```

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance54

Moderate activity, may be stable

Popularity24

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity67

Established project with proven stability

 Bus Factor1

Top contributor holds 83.2% 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 ~150 days

Recently: every ~216 days

Total

8

Last Release

99d ago

Major Versions

3.x-dev → 4.0.02023-09-27

4.x-dev → 5.0.02023-09-27

5.x-dev → 6.0.02023-11-05

6.0.0 → 7.x-dev2026-02-08

PHP version history (4 changes)3.x-devPHP ^7.2|^8.0

4.0.0PHP ~8.1.0 || ~8.2.0 || ~8.3.0

5.0.0PHP ~8.1.0 || ~8.2.0

7.x-devPHP ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/2aacc30f852e940d49eaf76c0cac6a97f3cfe4d38692ea774a57bc634196bda9?d=identicon)[fezfez](/maintainers/fezfez)

---

Top Contributors

[![tuupola](https://avatars.githubusercontent.com/u/21913?v=4)](https://github.com/tuupola "tuupola (252 commits)")[![fezfez](https://avatars.githubusercontent.com/u/1162307?v=4)](https://github.com/fezfez "fezfez (39 commits)")[![dakujem](https://avatars.githubusercontent.com/u/443067?v=4)](https://github.com/dakujem "dakujem (2 commits)")[![jhmoon2000](https://avatars.githubusercontent.com/u/30658871?v=4)](https://github.com/jhmoon2000 "jhmoon2000 (1 commits)")[![jv-k](https://avatars.githubusercontent.com/u/5808914?v=4)](https://github.com/jv-k "jv-k (1 commits)")[![klarsson](https://avatars.githubusercontent.com/u/17089222?v=4)](https://github.com/klarsson "klarsson (1 commits)")[![orx0r](https://avatars.githubusercontent.com/u/2333215?v=4)](https://github.com/orx0r "orx0r (1 commits)")[![TiMESPLiNTER](https://avatars.githubusercontent.com/u/598854?v=4)](https://github.com/TiMESPLiNTER "TiMESPLiNTER (1 commits)")[![tuefekci](https://avatars.githubusercontent.com/u/2657626?v=4)](https://github.com/tuefekci "tuefekci (1 commits)")[![BafS](https://avatars.githubusercontent.com/u/588205?v=4)](https://github.com/BafS "BafS (1 commits)")[![xu42](https://avatars.githubusercontent.com/u/12060792?v=4)](https://github.com/xu42 "xu42 (1 commits)")[![bezumkin](https://avatars.githubusercontent.com/u/1257284?v=4)](https://github.com/bezumkin "bezumkin (1 commits)")[![byan](https://avatars.githubusercontent.com/u/383327?v=4)](https://github.com/byan "byan (1 commits)")

---

Tags

psr-7jwtjsonmiddlewareauthpsr-15

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Psalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/cube43-slim-jwt-auth/health.svg)

```
[![Health](https://phpackages.com/badges/cube43-slim-jwt-auth/health.svg)](https://phpackages.com/packages/cube43-slim-jwt-auth)
```

###  Alternatives

[jimtools/jwt-auth

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

20142.3k3](/packages/jimtools-jwt-auth)[tuupola/slim-basic-auth

PSR-7 and PSR-15 HTTP Basic Authentication Middleware

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

Authentication, authorization and access control for Slim Framework and other PHP micro-frameworks

11816.4k1](/packages/jasny-auth)[mezzio/mezzio-authentication

Authentication middleware for Mezzio and PSR-7 applications

121.6M26](/packages/mezzio-mezzio-authentication)[middlewares/payload

Middleware to parse the body of the request with support for json, csv and url-encode

32466.8k17](/packages/middlewares-payload)[segrax/open-policy-agent

Open Policy Agent client and PSR-7, PSR-15 Authorization Middleware

212.0k](/packages/segrax-open-policy-agent)

PHPackages © 2026

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