Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/php-code-analyzing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ jobs:
container:
image: ubuntu:latest

strategy:
fail-fast: false
matrix:
laravel: [ '12', '13' ]

name: PHPStan / Laravel ${{ matrix.laravel }}

steps:
- name: Checkout code (git)
uses: actions/checkout@v3
Expand All @@ -20,7 +27,9 @@ jobs:
tools: composer

- name: Install dependencies with composer
run: composer install --no-progress
run: >
composer update --with-all-dependencies --no-progress
--with "laravel/framework:^${{ matrix.laravel }}.0"

- name: Run PHPStan
run: ./vendor/bin/phpstan analyze --memory-limit 2G
16 changes: 14 additions & 2 deletions .github/workflows/php-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,30 @@ jobs:
container:
image: ubuntu:latest

strategy:
fail-fast: false
matrix:
php-version: [ '8.3', '8.4' ]
laravel: [ '12', '13' ]
php-jwt: [ '6', '7' ]

name: PHP ${{ matrix.php-version }} / Laravel ${{ matrix.laravel }} / php-jwt ${{ matrix.php-jwt }}

steps:
- name: Checkout code (git)
uses: actions/checkout@v3

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
php-version: ${{ matrix.php-version }}
tools: composer

- name: Install dependencies with composer
run: composer install --no-progress
run: >
composer update --with-all-dependencies --no-progress
--with "laravel/framework:^${{ matrix.laravel }}.0"
--with "firebase/php-jwt:^${{ matrix.php-jwt }}.0"

- name: Run PHPUnit
run: ./vendor/bin/phpunit
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@
This package provides a simple way to use JWT (JSON Web Tokens) as an authentication guard in a Laravel
application.

## Requirements

| Package | Supported versions |
|---------------------|--------------------|
| PHP | 8.2+ (8.3+ on Laravel 13) |
| `laravel/framework` | 12, 13 |
| `firebase/php-jwt` | 6.8+, 7 |

> **`firebase/php-jwt` 7 enforces a minimum signing key size.** With HMAC algorithms
> (`HS256`/`HS384`/`HS512`) a key shorter than 32 bytes makes token issuing fail with
> `DomainException: Provided key is too short`. Laravel's `APP_KEY` is long enough; a custom
> `LARAVEL_JWT_ENCODE_KEY` may not be. Check your keys before upgrading `firebase/php-jwt`
> from 6 to 7, or pin `firebase/php-jwt` to `^6.8` until the keys are rotated.

## Installation

Require package `zendrop/laravel-jwt`
Expand Down Expand Up @@ -108,4 +122,4 @@ For stateful JWT:
],
]

```
```
14 changes: 8 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"name": "zendrop/laravel-jwt",
"type": "library",
"require": {
"firebase/php-jwt": "^6.8",
"laravel/framework": "^11|^12"
"firebase/php-jwt": "^6.8|^7.0",
"laravel/framework": "^12|^13"
},
"license": "MIT",
"autoload": {
Expand All @@ -30,20 +30,22 @@
}
},
"require-dev": {
"phpstan/phpstan": "^1.10",
"phpstan/phpstan": "^2.2",
"laravel/pint": "^1.13",
"squizlabs/php_codesniffer": "^3.7",
"slevomat/coding-standard": "^8.14",
"orchestra/testbench": "^9.5|^10.0",
"phpunit/phpunit": "^11.3"
"orchestra/testbench": "^10.0|^11.0",
"phpunit/phpunit": "^11.3|^12.0"
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
},
"policy": {
"advisories": {
"ignore-id": ["PKSA-y2cr-5h3j-g3ys"]
"ignore-id": [
"PKSA-y2cr-5h3j-g3ys"
]
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ parameters:
maximumNumberOfProcesses: 4
jobSize: 20

checkGenericClassInNonGenericObjectType: false
ignoreErrors:
# HasJwt is a trait for consuming applications, so it has no usage inside src/.
- identifier: trait.unused
2 changes: 1 addition & 1 deletion src/Exceptions/NonAuthenticatableModelException.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class NonAuthenticatableModelException extends LaravelJwtException
public function __construct(
string $message = 'The model must implement the Authenticatable interface to use JWT.',
int $code = 0,
\Throwable $previous = null
?\Throwable $previous = null
) {
if ($message) {
parent::__construct($message, $code, $previous);
Expand Down
19 changes: 13 additions & 6 deletions src/LaravelJwtServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,19 @@ protected function bindDependencies(): void
*/
protected function configureGuardDrivers(): void
{
// Laravel 13 rebinds the extend() callback to the AuthManager instance
// (Illuminate\Support\RebindsCallbacksToSelf), which changes both $this and the
// closure scope. First-class callables keep their own $this and scope, so guard
// creation keeps working on Laravel 11, 12 and 13.
$createStatelessGuard = $this->createStatelessGuard(...);
$createStatefulGuard = $this->createStatefulGuard(...);

// laravel-jwt
Auth::resolved(function (AuthManager $auth) {
Auth::resolved(function (AuthManager $auth) use ($createStatelessGuard) {
$auth->extend(
driver: static::GUARD_DRIVER_STATELESS,
callback: function ($app, $name, array $config) use ($auth) {
$guard = $this->createStatelessGuard($auth, $config);
callback: function ($app, $name, array $config) use ($auth, $createStatelessGuard) {
$guard = $createStatelessGuard($auth, $config);
$app->refresh('request', $guard, 'setRequest');

return $guard;
Expand All @@ -113,11 +120,11 @@ protected function configureGuardDrivers(): void
});

// laravel-jwt-stateful
Auth::resolved(function (AuthManager $auth) {
Auth::resolved(function (AuthManager $auth) use ($createStatefulGuard) {
$auth->extend(
driver: static::GUARD_DRIVER_STATEFUL,
callback: function ($app, $name, array $config) use ($auth) {
$guard = $this->createStatefulGuard($auth, $name, $config);
callback: function ($app, $name, array $config) use ($auth, $createStatefulGuard) {
$guard = $createStatefulGuard($auth, $name, $config);
$app->refresh('request', $guard, 'setRequest');

return $guard;
Expand Down
6 changes: 6 additions & 0 deletions src/Payload.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use Illuminate\Contracts\Support\Arrayable;

/**
* @implements Arrayable<string, mixed>
*/
class Payload implements Arrayable
{
public function __construct(
Expand All @@ -15,6 +18,9 @@ public function __construct(
) {
}

/**
* @return array<string, mixed>
*/
public function toArray(): array
{
$reflectionClass = new \ReflectionClass($this);
Expand Down
2 changes: 1 addition & 1 deletion src/StatefulGuard.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public function __construct(
BlacklistDriverInterface $blacklist,
UserProvider $provider,
EventDispatcher $eventDispatcher,
Timebox $timebox = null,
?Timebox $timebox = null,
) {
$this->name = $name;
$this->request = $request;
Expand Down
26 changes: 26 additions & 0 deletions tests/Fixtures/GuardTestUser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Zendrop\LaravelJwt\Tests\Fixtures;

use Illuminate\Foundation\Auth\User;
use Zendrop\LaravelJwt\HasJwt;

class GuardTestUser extends User
{
use HasJwt;

/**
* @var string
*/
protected $table = 'users';

/**
* @var bool
*/
public $timestamps = false;

/**
* @var array<int, string>
*/
protected $fillable = ['email', 'password'];
}
Loading
Loading