PHPackages                             stevewaffles/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. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. stevewaffles/jwt-auth

ActiveCakephp-plugin[Authentication &amp; Authorization](/categories/authentication)

stevewaffles/jwt-auth
=====================

A JWT authentication plugin for CakePHP.

00PHP

Since Jan 21Pushed 2y agoCompare

[ Source](https://github.com/stevewaffles/jwt-auth)[ Packagist](https://packagist.org/packages/stevewaffles/jwt-auth)[ RSS](/packages/stevewaffles-jwt-auth/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

MixerApi JwtAuth
================

[](#mixerapi-jwtauth)

[![Latest Version on Packagist](https://camo.githubusercontent.com/b40127687878b0d220666aea69b7ed9bb4577b7d4c4a1efd9dcef55559f44f0a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d697865726170692f6a77742d617574682e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/mixerapi/jwt-auth)[![Build](https://github.com/mixerapi/mixerapi-dev/workflows/Build/badge.svg?branch=master)](https://github.com/mixerapi/mixerapi-dev/actions?query=workflow%3ABuild)[![Coverage Status](https://camo.githubusercontent.com/980eb71f87b8f84d118d946d1a90203dbc53bbc8ac87363bc543899b32c0d2a0/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f6d697865726170692f6d697865726170692d6465762f62616467652e7376673f6272616e63683d6d6173746572)](https://coveralls.io/github/mixerapi/mixerapi-dev?branch=master)[![MixerApi](https://camo.githubusercontent.com/bca1ea90642661e0908fc7ad1c1cdbd704cda1063a2cb40801fab9d0ccdbd6af/68747470733a2f2f6d697865726170692e636f6d2f6173736574732f696d672f6d697865722d6170692d7265642e737667)](https://mixerapi.com)[![CakePHP](https://camo.githubusercontent.com/21b7bf61684c39eabf40bb424dd733f6f3a4bd11de430f8accc24ba0445b4b9b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f63616b657068702d253545342e322d7265643f6c6f676f3d63616b65706870)](https://book.cakephp.org/4/en/index.html)[![Minimum PHP Version](https://camo.githubusercontent.com/7f2179949cf3def20f5d08c400d94cf1c6c68c30bdaa05546c78e33eccded56f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e302d3838393242462e7376673f6c6f676f3d706870)](https://php.net/)

A [JWT](https://datatracker.ietf.org/doc/html/rfc7519) authentication library for CakePHP supporting both HMAC (HS256 or HS512) and RSA (RS256 or RS512) with JSON Web Keys. Before starting, you should determine which [signing algorithm](https://stackoverflow.com/questions/39239051/rs256-vs-hs256-whats-the-difference) best fits your needs. It is the goal of this library to make both easy.

- [Installation](#installation)
- [Defining Your JWT](#defining-your-jwt)
- [JSON Web Keys](#json-web-keys)
- [Login Controller](#login-controller)
- [Security](#Security)

For an alternative approach see [admad/cakephp-jwt-auth](https://github.com/ADmad/cakephp-jwt-auth).

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

[](#installation)

You can install this plugin into your CakePHP application using [composer](https://getcomposer.org).

```
composer require mixerapi/jwt-auth
```

And then load the plugin

```
bin/cake plugin load MixerApi/JwtAuth
```

### Configuration

[](#configuration)

Next [create a config file](assets/mixerapi_jwtauth.php) (e.g. `config/mixerapi_jwtauth.php`) and load it into your application.

```
# in config/bootstrap.php
Configure::load('mixerapi_jwtauth');
```

#### alg

[](#alg)

The `alg` string is required and must be either HS256, HS512, RS256, or RS512.

#### secret

[](#secret)

The `secret` string is required when using HMAC. The secret should not be committed to your VCS and be at least 32 characters long. You can generate a strong secret using a tool like openssl or gpg:

```
openssl rand -base64 24
```

```
gpg --armor --gen-random 1 24
```

#### keys

[](#keys)

The `keys` array is required when using RSA. The keys should not be committed to your VCS and be at least 2048 bits long. You can generate a public/private keypair using openssl:

```
openssl genrsa -out config/keys/1/private.pem 2048
openssl rsa -in config/keys/1/private.pem -out config/keys/1/public.pem -pubout
```

### Service Provider

[](#service-provider)

Using the `JwtAuthServiceProvider` is recommended to inject dependencies automatically.

```
# in src/Application.php

public function services(ContainerInterface $container): void
{
    /** @var \League\Container\Container $container */
    $container->addServiceProvider(new \MixerApi\JwtAuth\JwtAuthServiceProvider());
}
```

### Authentication

[](#authentication)

You will need to configure [CakePHP Authentication](https://book.cakephp.org/authentication/2/en/index.html) to use this library. There are several ways to do this documented in the quick start. See the [mixerapi demo](https://github.com/mixerapi/demo) for a complete example.

Be sure to load the [CakePHP Authentication.Component](https://book.cakephp.org/authentication/2/en/authentication-component.html)(generally in your AppController).

Here is an example that supports both HMAC and RSA with form and password based authentication. However way you implement authentication, **it is advised to use** `\MixerApi\JwtAuth\Configuration\Configuration` to pull values from your `MixerApi.JwtAuth` configuration file `config/mixerapi_jwtauth.php`. This will validate your configuration before applying it to your applications authentication.

```
# in src/Application.php

public function getAuthenticationService(ServerRequestInterface $request): \Authentication\AuthenticationServiceInterface
{
    $fields = [
        \Authentication\Identifier\IdentifierInterface::CREDENTIAL_USERNAME => 'email',
        \Authentication\Identifier\IdentifierInterface::CREDENTIAL_PASSWORD => 'password',
    ];

    $config = new \MixerApi\JwtAuth\Configuration\Configuration();
    $service = new \Authentication\AuthenticationService();

    $service->loadAuthenticator('Authentication.Form', [
        'fields' => $fields,
        'loginUrl' => '/admin/auth/login'
    ]);

    $service->loadIdentifier('Authentication.JwtSubject');

    if (str_starts_with(haystack: $config->getAlg(), needle: 'HS')) {
        $service->loadAuthenticator('Authentication.Jwt', [
            'secretKey' => $config->getSecret(),
            'algorithm' => $config->getAlg(),
        ]);
    } else if (str_starts_with(haystack: $config->getAlg(), needle: 'RS')) {
        $jsonKeySet = \Cake\Cache\Cache::remember('jwkset', function() {
            return json_encode((new \MixerApi\JwtAuth\Jwk\JwkSet)->getKeySet());
        });

        /*
         * Caching is optional, you may also set the jwks key to the return value of (new JwkSet)->getKeySet()
         */
        $service->loadAuthenticator('Authentication.Jwt', [
            'jwks' => json_decode($jsonKeySet, true),
            'algorithm' => $config->getAlg(),
        ]);
    }

    $service->loadIdentifier('Authentication.Password', ['fields' => $fields]);

    return $service;
}
```

Defining your JWT
-----------------

[](#defining-your-jwt)

On your User entity implement `JwtEntityInterface`. This will be used to generate the JWT, example:

```
namespace App\Model\Entity;

use Cake\ORM\Entity;
use MixerApi\JwtAuth\Jwt\Jwt;
use MixerApi\JwtAuth\Jwt\JwtEntityInterface;
use MixerApi\JwtAuth\Jwt\JwtInterface;

class User extends Entity implements JwtEntityInterface
{
    /**
     * @inheritDoc
     */
    public function getJwt(): JwtInterface
    {
        return new Jwt(
            exp: time() + 60 * 60 * 24,
            sub: $this->get('id'),
            iss: 'mixerapi',
            aud: 'mixerapi-client',
            nbf: null,
            iat: time(),
            jti: \Cake\Utility\Text::uuid(),
            claims: [
                'user' => [
                    'email' => $this->get('email')
                ]
            ]
        );
    }
}
```

JSON Web Keys
-------------

[](#json-web-keys)

Signing your tokens with RSA uses a public/private key pair. You can skip this section if you are using HMAC.

### Building Keys

[](#building-keys)

We'll store the keys in `config/keys/1/` but you can store these anywhere. Keys should not be stored in version control, example:

```
# in config/mixerapi_jwtauth.php

return [
    'MixerApi.JwtAuth' => [
        'alg' => 'RS256',
        'keys' => [
            [
                'kid' => '1',
                'public' => file_get_contents(CONFIG . 'keys' . DS . '1' . DS . 'public.pem'),
                'private' => file_get_contents(CONFIG . 'keys' . DS . '1' . DS . 'private.pem'),
            ]
        ]
    ]
];
```

### JWK Set Controller

[](#jwk-set-controller)

Read more about [JSON Web Keys here](https://datatracker.ietf.org/doc/html/rfc7517). Let's create an endpoint to expose your JWK Set.

```
use Cake\Controller\Controller;
use Cake\Event\EventInterface;
use MixerApi\JwtAuth\Jwk\JwkSetInterface;

class JwksController extends Controller
{
    public function beforeFilter(EventInterface $event)
    {
        parent::beforeFilter($event);
        $this->Authentication->allowUnauthenticated(['index']);
    }

    public function index(JwkSetInterface $jwkSet)
    {
        $this->set('data', $jwkSet->getKeySet());
        $this->viewBuilder()->setOption('serialize', 'data');
    }
}
```

Add a route to your controller in your `config/routes.php` file.

Example response:

```
{
  "keys": [
    {
      "kty": "RSA",
      "use": "sig",
      "alg": "RS256",
      "kid": "1",
      "n": "wk865HbUKadJU-Mh-Iv2Z_30ZOMclkK1cbuiTVkINy_R9oHoAht2DS788q_Sll38dtTB4bzptd0u6k4cJd6Lj6nVQTe1uRyuAU47tqitiJmEXX_2SHIRv6aj4vygIfqr1FtQMHPlBW7r4q840H5mh_Z-E_a7d27QbtJ3eYNEiFow6LLvl17_7bdaenlwccY0j-PY1GzL7UwG8uHBZ78ZOcvu_GgaYC5suRrJrV_6_Qu6lySXObDaajr6Foz0m-z4Aj7KA8KmAiM_Rw_Yqm_KqPT3YBGj83TxeEiMPkrMYry123hFQYm09EO2Az9lGjr-PQc6SR08SDqZ3zbwe9iam55dzVZ-vQF3ASnZpBHyIDhCI7PFShceFI1Sv0RW7-Tl0uM2jQa1RyEpFle1xc0RxSFZium0aGMnFuE2W9JDERPw47wFZx2kSk1nB6PDK6XPLJLi_db0VrP5m5z2HDWeYVmsuAVFm6-l1PjiGH4G1TpuYfPKP2P8K-kveo1Ddm14IJSWfcACeAF_gx644Ua_IJ8wS98dQqE-R-jzfEv7aLBacP5_thCUbHfCRrAgtM5lBAM_1tfQ4XsOLnFWkl4arm3TzN2wCjjuqxipgwpUtY_SN6SXhJW4MW2qHVKtHtXl9haF5gEDBL7twDsFozYZCc5k0d85EgfJ5Jn7ZSAgwXk",
      "e": "AQAB"
    }
  ]
}
```

You may add/remove keys to your `MixerApi.JwtAuth.keys` config as part of your key rotation strategy.

Note, if you are not using dependency injection:

```
    public function index()
    {
        $this->set('data', (new JwkSet)->getKeySet());
        $this->viewBuilder()->setOption('serialize', 'data');
    }
```

Login Controller
----------------

[](#login-controller)

In the example below we'll authenticate, create the JWT we defined earlier and return it to the requester.

```
use Cake\Controller\Controller;
use MixerApi\JwtAuth\JwtAuthenticatorInterface;

public function LoginController extends Controller
{
    public function beforeFilter(EventInterface $event)
    {
        parent::beforeFilter($event);
        $this->Authentication->allowUnauthenticated(['login']);
    }

    public function login(JwtAuthenticatorInterface $jwtAuth)
    {
        try {
            return $this->response->withStringBody($jwtAuth->authenticate($this->Authentication));
        } catch (UnauthenticatedException $e) {
            return $this->response->withStringBody($e->getMessage())->withStatus(401);
        }
    }
}
```

Add a route to the controller in your `config/routes.php` file.

This will build the JWT we defined earlier in the User Entity.

```
{
  "iss": "mixerapi",
  "sub": "5e28e9ed-f3e1-4eb2-aa88-8d618f4021ee",
  "aud": "api-client",
  "exp": 1651972707,
  "jti": "a1f6f5ec-748d-4a1c-9d0e-f8e19ec7f9b2",
  "user": {
    "email": "test@example.com"
  }
}
```

Note, if you're not using dependency injection:

```
    public function login()
    {
        try {
            return $this->response->withStringBody(
                (new \MixerApi\JwtAuth\JwtAuthenticator)->authenticate($this->Authentication)
            );
        } catch (UnauthenticatedException $e) {
            return $this->response->withStringBody($e->getMessage())->withStatus(401);
        }
    }
```

Or, if you prefer to handle the authentication yourself you may pass an instance of `JwtInterface` instead, example:

```
    public function login(JwtAuthenticatorInterface $jwtAuth)
    {
        try {
            $result = $this->Authentication->getResult();
            if (!$result->isValid()) {
                throw new UnauthenticatedException();
            }
            return $this->response->withStringBody($jwtAuth->authenticate($result->getData()->getJwt()));
        } catch (UnauthenticatedException $e) {
            return $this->response->withStringBody($e->getMessage())->withStatus(401);
        }
    }
```

Security
--------

[](#security)

Some security measures are baked into this library:

#### Weak HMAC secrets

[](#weak-hmac-secrets)

JWT signed with HMAC can be brute forced with a tool like [JWT Tool](https://github.com/ticarpi/jwt_tool). Once cracked the JWT can be altered. This library mitigates this by requiring a minimum secret length of 32 characters though you may want to consider using 64 characters if security is more important than speed and token size. Generating a strong random secret and securing it is up to you.

#### Weak RSA Keys

[](#weak-rsa-keys)

Weak keys can be cracked as well. This library requires a minimum key length of 2048 bits. You may want to consider a key length of 4096 bits depending on your security requirements. Securing your keys is up to you.

#### Alg None Bypass

[](#alg-none-bypass)

The alg=none signature-bypass vulnerability is mitigated by requiring a single valid algorithm. Additional protection exists within the [firebase/php-jwt](https://github.com/firebase/php-jwt) library which should be kept up to date.

#### RS/HS256 public key mismatch vulnerability

[](#rshs256-public-key-mismatch-vulnerability)

Mitigated by requiring a single valid algorithm. Additional protection exists within the [firebase/php-jwt](https://github.com/firebase/php-jwt) library which should be kept up to date.

###  Health Score

12

—

LowBetter than 0% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity0

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity19

Early-stage or recently created project

 Bus Factor1

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

### Community

Maintainers

![](https://www.gravatar.com/avatar/b34c8cf0202a169795242cbf2a7b55588a2ced7942cc7462a3c76a816de8ce6a?d=identicon)[\_waffles](/maintainers/_waffles)

---

Top Contributors

[![cnizzardini](https://avatars.githubusercontent.com/u/171294?v=4)](https://github.com/cnizzardini "cnizzardini (7 commits)")[![stevewaffles](https://avatars.githubusercontent.com/u/2625357?v=4)](https://github.com/stevewaffles "stevewaffles (4 commits)")[![amayer5125](https://avatars.githubusercontent.com/u/3212673?v=4)](https://github.com/amayer5125 "amayer5125 (1 commits)")

### Embed Badge

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

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

###  Alternatives

[namshi/jose

JSON Object Signing and Encryption library for PHP.

1.8k99.6M101](/packages/namshi-jose)[league/oauth1-client

OAuth 1.0 Client Library

99698.8M106](/packages/league-oauth1-client)[bezhansalleh/filament-shield

Filament support for `spatie/laravel-permission`.

2.8k2.9M88](/packages/bezhansalleh-filament-shield)[gesdinet/jwt-refresh-token-bundle

Implements a refresh token system over Json Web Tokens in Symfony

70516.4M35](/packages/gesdinet-jwt-refresh-token-bundle)[league/oauth2-google

Google OAuth 2.0 Client Provider for The PHP League OAuth2-Client

41721.2M118](/packages/league-oauth2-google)[illuminate/auth

The Illuminate Auth package.

9327.3M1.0k](/packages/illuminate-auth)

PHPackages © 2026

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