puff / jwt
JWT authentication pipeline for Puff
Requires
- php: ^8.2
- miladrahimi/php-jwt: ^3.4
- psr/http-message: ^2.0
- puff/config: dev-main
- puff/di: dev-main
- puff/http: dev-main
Requires (Dev)
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-16 17:09:48 UTC
README
JWT access-token authentication for Puff API pipelines, built on miladrahimi/php-jwt. Requires PHP 8.2+. The initial implementation uses a fixed HS256 signer.
Install and configure
composer require puff/jwt
Composer provider discovery registers Puff\Jwt\Jwt. Puff's configuration
publisher publishes config/jwt.php; applications must have the standard
Puff\Config\ConfigPublisher::publish Composer install/update scripts enabled.
Installing the component does not automatically protect routes.
return [ 'secret' => '', // Required: 32–6144 bytes; use a random secret. 'ttl' => 3600, // Access-token lifetime in seconds. 'issuer' => '', // When set, included and required during verification. 'audience' => '', // When set, included and required during verification. ];
Generate a secret with php -r 'echo bin2hex(random_bytes(32)), PHP_EOL;'.
Store it in your deployment secret configuration, not source control. An empty
or short secret fails explicitly when the JWT service is resolved.
With Puff Config's environment overrides, set JWT__SECRET, JWT__TTL,
JWT__ISSUER, and JWT__AUDIENCE in the project .env or process environment.
For example, JWT__TTL=3600 maps to jwt.ttl.
Issue an access token
Inject Jwt into your login controller. Verify the user's credentials first,
then issue a token with the authenticated user's ID:
$token = $jwt->issue((string) $userId, ['role' => 'member']); return response()->json(['access_token' => $token, 'token_type' => 'Bearer']);
issue() generates sub, iat, nbf, exp, and a random jti.
Caller claims cannot override these fields or a configured issuer/audience.
Tokens are signed, not encrypted: never put passwords or secrets in claims.
Protect an API
Add Puff\Jwt\Pipeline::class to the route or group's pipeline list.
Alternatively, add it to the HTTP item's pipeline in config/server.php for an entirely protected API:
'pipeline' => [ Puff\Jwt\Pipeline::class, ],
Keep login/public routes outside protected groups. The client sends:
Router::post('/login', 'Auth@login'); Router::group([ 'prefix' => '/api', 'pipeline' => [Puff\Jwt\Pipeline::class], ], static function (): void { Router::get('/profile', 'Profile@index'); });
Authorization: Bearer <access-token>
Only the Authorization header is accepted. Duplicate headers, invalid signatures, expired/missing expiration claims, invalid subjects, future timestamps, and issuer/audience mismatches return HTTP 401 with a Bearer challenge:
{"error":"unauthorized"}
Validated claims are attached to the immutable request:
public function profile(\Puff\Http\Request $request): mixed { $claims = $request->getAttribute('jwt'); return ['user_id' => $claims['sub']]; }
The singleton service holds only signing configuration, never current claims. Concurrent Fibers receive independent request attributes. Verification reads the current time on every call. Application exceptions propagate normally.
For non-HTTP usage, $jwt->verify($token) returns validated claims or throws
Puff\Jwt\Exception\InvalidToken. Configuration failures are not converted to 401.
Scope and security
Use HTTPS. Authenticate credentials and check account status in business code. Role/permission checks belong in a subsequent authorization pipeline (403). Revocation, refresh tokens, key rotation, and RSA/ECDSA configuration are not implemented in this version. Logout on the client does not invalidate an issued token; use short lifetimes or implement server-side revocation where required. Changing the shared secret invalidates all outstanding tokens.
Validation
composer test
composer analyse
composer validate --strict
Tests cover token round trips, reserved claims, tampering/algorithm rejection, expiry, issuer/audience, malformed Bearer headers, Fiber isolation, provider registration, and propagation of downstream exceptions.