add projet
This commit is contained in:
+162
@@ -0,0 +1,162 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
You can find and compare releases at the [GitHub release page](https://github.com/PHP-Open-Source-Saver/jwt-auth/releases).
|
||||
|
||||
## [Unreleased]
|
||||
### Fixed
|
||||
- Fixed the return type of getMinutesUntilExpired in BlackList, which returned a float instead of an int when using Carbon v2.
|
||||
- Fixed PHPStan issue in JWTGenerateSecretCommand by ensuring displayKey($key); is called before returning, avoiding returning a void method.
|
||||
- Fixed missing return true; statements in validatePayload() and validateRefresh() methods of Expiration.php, IssuedAt.php, and NotBefore.php to resolve PHPStan errors.
|
||||
- Fixed PHPStan error related to new static() by refactoring hasAllClaims method in Collection class.
|
||||
|
||||
|
||||
## [2.8.0] 2025-02-11
|
||||
Please see (https://github.com/PHP-Open-Source-Saver/jwt-auth/releases/tag/2.8.0)
|
||||
|
||||
### Added
|
||||
- #268 Implement config variable to allow iat to remain unchanged claim when refreshing a token
|
||||
- Adds support for Laravel 12
|
||||
- Adds CI testing for PHP 8.4
|
||||
- Don't show jwt secret if show option is false even if the key is updated
|
||||
- Casts config ints to int by default in new config file publishes
|
||||
- Override "id" method in JWTGuard
|
||||
|
||||
### Removed
|
||||
|
||||
- Dropping support for PHP 8.1, if you are still on this version, please update your PHP version in order to use the latest version of this package.
|
||||
|
||||
## [2.7.2] 2024-09-28
|
||||
|
||||
### Added
|
||||
- Add `cookie_key_name` config to customize cookie name for authentication
|
||||
- Delegate `Auth::id()` calls to the newly added `getUserId` method
|
||||
|
||||
## [2.7.0] 2024-07-24
|
||||
|
||||
### Fixed
|
||||
- Support for Carbon 3 alongside Carbon 2
|
||||
|
||||
## [2.6.0] 2024-07-11
|
||||
|
||||
### Added
|
||||
- New `getUserId` method
|
||||
|
||||
## [2.5.0] 2024-07-03
|
||||
|
||||
### Added
|
||||
- Refresh iat claim when refreshing a token
|
||||
|
||||
## [2.4.0] 2024-05-27
|
||||
|
||||
### Added
|
||||
- Support for lcobucci/jwt^5.0 (and dropped support for ^4.0)
|
||||
- SetSecret regenerates config with new secret in the Lcobucci provider
|
||||
|
||||
## [2.3.0] 2024-05-09
|
||||
|
||||
### Added
|
||||
- Support for Carbon 3 (and drop Carbon 1, but it was unused anyway)
|
||||
|
||||
### Removed
|
||||
- Dropped support for Laravel < 10 and PHP < 8.1
|
||||
|
||||
### Fixed
|
||||
- Use `id` claim for identify user if `sub` doesn't exists.
|
||||
|
||||
## [2.2.0] 2024-03-12
|
||||
|
||||
### Added
|
||||
- Different TTL configurations for each guard
|
||||
- lcobucci/jwt: add array support for `aud` claim
|
||||
- Laravel 11 support
|
||||
|
||||
## [2.1.0] 2023-02-17
|
||||
|
||||
### Added
|
||||
- Laravel 10 support
|
||||
|
||||
## [2.0.0] 2022-09-08
|
||||
- No changes to 2.0.0-RC1
|
||||
|
||||
### Added
|
||||
- Arabic translation for docs by hawkiq
|
||||
|
||||
## [2.0.0-RC1] 2022-08-25
|
||||
|
||||
### Added
|
||||
- Adds Octane Compatibility
|
||||
- Added `ask-passphrase` parameter to generating certs command
|
||||
- Support autocomplete guard
|
||||
|
||||
### Fixed
|
||||
- Default config value for `show_black_list_exception` changed to true
|
||||
- Auth header not ignoring other auth schemes
|
||||
- Fixed replacing of values using regex
|
||||
|
||||
## [1.4.2] 2022-04-22
|
||||
|
||||
### Added
|
||||
- Added exception if secret key or private/public key are missing
|
||||
|
||||
### Fixed
|
||||
- Add command for generating certs
|
||||
|
||||
## [1.4.1] - 2022-01-24
|
||||
|
||||
### Fixed
|
||||
- Add more ReturnTypeWillChange for PHP 8.1 compatibility
|
||||
|
||||
## [1.4.0] - 2022-01-18
|
||||
|
||||
### Added
|
||||
|
||||
### Fixed
|
||||
- Fixes #101 - Secret is not nullable but should be according to the library config boilerplate
|
||||
- Fixes #99 - Steps for migrating from tymons package
|
||||
|
||||
## [1.3.0] - 2022-01-13
|
||||
|
||||
### Added
|
||||
- PHP 8.1 support (#58, #77, #87)
|
||||
- Typed variables (#52)
|
||||
|
||||
### Fixed
|
||||
- Compatability with Laravel 6 versions below 6.15
|
||||
|
||||
## [1.2.0] - 2021-11-16
|
||||
|
||||
### Added
|
||||
- Dispatch Auth Events by @okaufmann in #45
|
||||
|
||||
## [1.1.1] - 2021-10-21
|
||||
|
||||
### Changed
|
||||
- Blacklisted token exception no more thrown by default by @Messhias in #32
|
||||
|
||||
### Fixed
|
||||
- ECDSA signers by @josecl in #31
|
||||
|
||||
## [1.1.0] - 2021-11-11
|
||||
|
||||
### Added
|
||||
- PHP 8.0 and `lcobucci/jwt` version 4 compatability by @eschricker in #14
|
||||
- Option to hide Blacklisted Token exception by @Messhias in #7
|
||||
- Throw exception for invalid encrypted cookies by @eschricker in #22
|
||||
|
||||
### Fixed
|
||||
- Typo in tests by @eschricker in #23
|
||||
|
||||
[Unreleased]: https://github.com/PHP-Open-Source-Saver/jwt-auth/compare/2.0.0...HEAD
|
||||
[2.0.0]: https://github.com/PHP-Open-Source-Saver/jwt-auth/compare/1.4.2...2.0.0
|
||||
[2.0.0-RC1]: https://github.com/PHP-Open-Source-Saver/jwt-auth/compare/1.4.2...2.0.0-RC1
|
||||
[1.4.2]: https://github.com/PHP-Open-Source-Saver/jwt-auth/compare/1.4.1...1.4.2
|
||||
[1.4.1]: https://github.com/PHP-Open-Source-Saver/jwt-auth/compare/1.4.0...1.4.1
|
||||
[1.4.0]: https://github.com/PHP-Open-Source-Saver/jwt-auth/compare/1.3.0...1.4.0
|
||||
[1.3.0]: https://github.com/PHP-Open-Source-Saver/jwt-auth/compare/1.2.0...1.3.0
|
||||
[1.2.0]: https://github.com/PHP-Open-Source-Saver/jwt-auth/compare/1.1.1...1.2.0
|
||||
[1.1.1]: https://github.com/PHP-Open-Source-Saver/jwt-auth/compare/1.1.0...1.1.1
|
||||
[1.1.0]: https://github.com/PHP-Open-Source-Saver/jwt-auth/compare/1.0.2...1.1.0
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2021 Sean Tymon
|
||||
Copyright (c) 2021 PHP Open Source Saver
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,46 @@
|
||||
<div dir="rtl" align="right">
|
||||
## الحقوق
|
||||
<p dir='rtl' align='right'>
|
||||
ان هذا المشروع منسوخ من
|
||||
|
||||
[tymonsdesigns/jwt-auth](https://github.com/tymondesigns/jwt-auth/wiki)
|
||||
</br> لقد قررنا نسخه بسبب ان صاحب المشروع الاصلي لم يحدثه منذ زمن طويل.
|
||||
</p>
|
||||
|
||||
|
||||
## <div dir="rtl" align="right">للتحديث الى المستودع الحالي من [`tymondesigns/jwt-auth`](https://github.com/tymondesigns/jwt-auth)</div>
|
||||
|
||||
<div dir="rtl" align="right">
|
||||
|
||||
ان هذا المشروع يستخدم نيم سبيس مختلف عن, `tymondesigns/jwt-auth`, ولكن يستخدم نفس الخصائص فلا داعي للقلق:
|
||||
|
||||
1) استخدم ايعاز `composer remove tymon/jwt-auth`
|
||||
> **ملاحظة** قد تظهر بعض الاخطاء يمكنك تجاهلها.
|
||||
2) قم باستبدال `Tymon\JWTAuth` ب `PHPOpenSourceSaver\JWTAuth`.
|
||||
> **نصيحة**: يمكن استخدام الاختصارات بمحرر النصوص لديك مثلا. <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>R</kbd>
|
||||
3) نفذ `composer require php-open-source-saver/jwt-auth`
|
||||
|
||||
### ملاحظات
|
||||
|
||||
بسبب بعض الاضافات في مشروعنا قد تواجه مشاكل بالتوافقية. _ولكن هذا لن يؤثر على مشروعك بشكل عام_, الا اذا كنت [implicitly disabled autodiscovery](https://laravel.com/docs/8.x/packages#opting-out-of-package-discovery) للبكج الاصلي.
|
||||
|
||||
العناصر الغير متوافقة حاليا:
|
||||
- [`JWTGuard`](src/JWTGuard.php) يحتوي على متغير جديد في دالة الانشاء [`$eventDispatcher`](src/Providers/AbstractServiceProvider.php#L97)
|
||||
</div>
|
||||
|
||||
## الوثائق
|
||||
|
||||
جميع الشروحات متوفرة على [laravel-jwt-auth.readthedocs.io](https://laravel-jwt-auth.readthedocs.io/)
|
||||
|
||||
-----------------------------------
|
||||
|
||||
## الأمان
|
||||
|
||||
اذا وجدت اي ثغرة يمكنك اتباع [بوليصة الامان](https://github.com/PHP-Open-Source-Saver/jwt-auth/security/policy)
|
||||
|
||||
## الرخصة
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,6 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you discover any security related issues, please email messhias@gmail.com or
|
||||
eric.schricker@adiutabyte.de instead of using the issue tracker.
|
||||
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"name": "php-open-source-saver/jwt-auth",
|
||||
"description": "JSON Web Token Authentication for Laravel and Lumen",
|
||||
"keywords": [
|
||||
"auth",
|
||||
"authentication",
|
||||
"json web token",
|
||||
"jwt",
|
||||
"laravel"
|
||||
],
|
||||
"homepage": "https://github.com/PHP-Open-Source-Saver/jwt-auth",
|
||||
"support": {
|
||||
"issues": "https://github.com/PHP-Open-Source-Saver/jwt-auth/issues",
|
||||
"source": "https://github.com/PHP-Open-Source-Saver/jwt-auth"
|
||||
},
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sean Tymon",
|
||||
"email": "tymon148@gmail.com",
|
||||
"homepage": "https://tymon.xyz",
|
||||
"role": "Forked package creator | Developer"
|
||||
},
|
||||
{
|
||||
"name": "Eric Schricker",
|
||||
"email": "eric.schricker@adiutabyte.de",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Fabio William Conceição",
|
||||
"email": "messhias@gmail.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Max Snow",
|
||||
"email": "contact@maxsnow.me",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"ext-json": "*",
|
||||
"illuminate/auth": "^10|^11|^12",
|
||||
"illuminate/contracts": "^10|^11|^12",
|
||||
"illuminate/http": "^10|^11|^12",
|
||||
"illuminate/support": "^10|^11|^12",
|
||||
"lcobucci/jwt": "^5.4",
|
||||
"namshi/jose": "^7.0",
|
||||
"nesbot/carbon": "^2.0|^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3",
|
||||
"illuminate/console": "^10|^11|^12",
|
||||
"illuminate/routing": "^10|^11|^12",
|
||||
"orchestra/testbench": "^8|^9|^10",
|
||||
"mockery/mockery": "^1.6",
|
||||
"phpstan/phpstan": "^2",
|
||||
"phpunit/phpunit": "^10.5|^11"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PHPOpenSourceSaver\\JWTAuth\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"PHPOpenSourceSaver\\JWTAuth\\Test\\": "tests/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-develop": "2.0-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"JWTAuth": "PHPOpenSourceSaver\\JWTAuth\\Facades\\JWTAuth",
|
||||
"JWTFactory": "PHPOpenSourceSaver\\JWTAuth\\Facades\\JWTFactory"
|
||||
},
|
||||
"providers": [
|
||||
"PHPOpenSourceSaver\\JWTAuth\\Providers\\LaravelServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"funding": [],
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"minimum-stability": "dev",
|
||||
"scripts": {
|
||||
"php-cs-fixer": "php-cs-fixer fix --diff",
|
||||
"test": "phpunit --colors=always",
|
||||
"test:ci": "composer test -- --coverage-text --coverage-clover=coverage.xml",
|
||||
"phpstan": "phpstan analyse --memory-limit=256M",
|
||||
"phpstan-baseline": "phpstan analyse --generate-baseline --memory-limit=256M"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| JWT Authentication Secret
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Don't forget to set this in your .env file, as it will be used to sign
|
||||
| your tokens. A helper command is provided for this:
|
||||
| `php artisan jwt:secret`
|
||||
|
|
||||
| Note: This will be used for Symmetric algorithms only (HMAC),
|
||||
| since RSA and ECDSA use a private/public key combo (See below).
|
||||
|
|
||||
*/
|
||||
|
||||
'secret' => env('JWT_SECRET'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| JWT Authentication Keys
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The algorithm you are using, will determine whether your tokens are
|
||||
| signed with a random string (defined in `JWT_SECRET`) or using the
|
||||
| following public & private keys.
|
||||
|
|
||||
| Symmetric Algorithms:
|
||||
| HS256, HS384 & HS512 will use `JWT_SECRET`.
|
||||
|
|
||||
| Asymmetric Algorithms:
|
||||
| RS256, RS384 & RS512 / ES256, ES384 & ES512 will use the keys below.
|
||||
|
|
||||
*/
|
||||
|
||||
'keys' => [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Public Key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| A path or resource to your public key.
|
||||
|
|
||||
| E.g. 'file://path/to/public/key'
|
||||
|
|
||||
*/
|
||||
|
||||
'public' => env('JWT_PUBLIC_KEY'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Private Key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| A path or resource to your private key.
|
||||
|
|
||||
| E.g. 'file://path/to/private/key'
|
||||
|
|
||||
*/
|
||||
|
||||
'private' => env('JWT_PRIVATE_KEY'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Passphrase
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The passphrase for your private key. Can be null if none set.
|
||||
|
|
||||
*/
|
||||
|
||||
'passphrase' => env('JWT_PASSPHRASE'),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| JWT time to live
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the length of time (in minutes) that the token will be valid for.
|
||||
| Defaults to 1 hour.
|
||||
|
|
||||
| You can also set this to null, to yield a never expiring token.
|
||||
| Some people may want this behaviour for e.g. a mobile app.
|
||||
| This is not particularly recommended, so make sure you have appropriate
|
||||
| systems in place to revoke the token if necessary.
|
||||
| Notice: If you set this to null you should remove 'exp' element from 'required_claims' list.
|
||||
|
|
||||
*/
|
||||
|
||||
'ttl' => (int) env('JWT_TTL', 60),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Refresh time to live
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the length of time (in minutes) that the token can be refreshed within.
|
||||
| This defines the refresh window, during which the user can refresh their token
|
||||
| before re-authentication is required.
|
||||
|
|
||||
| By default, a refresh will NOT issue a new "iat" (issued at) timestamp. If changed
|
||||
| to true, each refresh will issue a new "iat" timestamp, extending the refresh
|
||||
| period from the most recent refresh. This results in a rolling refresh
|
||||
|
|
||||
| To retain a fluid refresh window from the last refresh action (i.e., the behavior between
|
||||
| version 2.5.0 and 2.8.2), set "refresh_iat" to true. With this setting, the refresh
|
||||
| window will renew with each subsequent refresh.
|
||||
|
|
||||
| The refresh ttl defaults to 2 weeks.
|
||||
|
|
||||
| You can also set this to null, to yield an infinite refresh time.
|
||||
| Some may want this instead of never expiring tokens for e.g. a mobile app.
|
||||
| This is not particularly recommended, so make sure you have appropriate
|
||||
| systems in place to revoke the token if necessary.
|
||||
|
|
||||
*/
|
||||
|
||||
'refresh_iat' => env('JWT_REFRESH_IAT', false),
|
||||
'refresh_ttl' => (int) env('JWT_REFRESH_TTL', 20160),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| JWT hashing algorithm
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the hashing algorithm that will be used to sign the token.
|
||||
|
|
||||
| See here: https://github.com/namshi/jose/tree/master/src/Namshi/JOSE/Signer/OpenSSL
|
||||
| for possible values.
|
||||
|
|
||||
*/
|
||||
|
||||
'algo' => env('JWT_ALGO', 'HS256'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Required Claims
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the required claims that must exist in any token.
|
||||
| A TokenInvalidException will be thrown if any of these claims are not
|
||||
| present in the payload.
|
||||
|
|
||||
*/
|
||||
|
||||
'required_claims' => [
|
||||
'iss',
|
||||
'iat',
|
||||
'exp',
|
||||
'nbf',
|
||||
'sub',
|
||||
'jti',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Persistent Claims
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the claim keys to be persisted when refreshing a token.
|
||||
| `sub` and `iat` will automatically be persisted, in
|
||||
| addition to the these claims.
|
||||
|
|
||||
| Note: If a claim does not exist then it will be ignored.
|
||||
|
|
||||
*/
|
||||
|
||||
'persistent_claims' => [
|
||||
// 'foo',
|
||||
// 'bar',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Lock Subject
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This will determine whether a `prv` claim is automatically added to
|
||||
| the token. The purpose of this is to ensure that if you have multiple
|
||||
| authentication models e.g. `App\User` & `App\OtherPerson`, then we
|
||||
| should prevent one authentication request from impersonating another,
|
||||
| if 2 tokens happen to have the same id across the 2 different models.
|
||||
|
|
||||
| Under specific circumstances, you may want to disable this behaviour
|
||||
| e.g. if you only have one authentication model, then you would save
|
||||
| a little on token size.
|
||||
|
|
||||
*/
|
||||
|
||||
'lock_subject' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Leeway
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This property gives the jwt timestamp claims some "leeway".
|
||||
| Meaning that if you have any unavoidable slight clock skew on
|
||||
| any of your servers then this will afford you some level of cushioning.
|
||||
|
|
||||
| This applies to the claims `iat`, `nbf` and `exp`.
|
||||
|
|
||||
| Specify in seconds - only if you know you need it.
|
||||
|
|
||||
*/
|
||||
|
||||
'leeway' => (int) env('JWT_LEEWAY', 0),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Blacklist Enabled
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| In order to invalidate tokens, you must have the blacklist enabled.
|
||||
| If you do not want or need this functionality, then set this to false.
|
||||
|
|
||||
*/
|
||||
|
||||
'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true),
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------------
|
||||
| Blacklist Grace Period
|
||||
| -------------------------------------------------------------------------
|
||||
|
|
||||
| When multiple concurrent requests are made with the same JWT,
|
||||
| it is possible that some of them fail, due to token regeneration
|
||||
| on every request.
|
||||
|
|
||||
| Set grace period in seconds to prevent parallel request failure.
|
||||
|
|
||||
*/
|
||||
|
||||
'blacklist_grace_period' => (int) env('JWT_BLACKLIST_GRACE_PERIOD', 0),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Show blacklisted token option
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify if you want to show black listed token exception on the laravel logs.
|
||||
|
|
||||
*/
|
||||
|
||||
'show_black_list_exception' => env('JWT_SHOW_BLACKLIST_EXCEPTION', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cookies encryption
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default Laravel encrypt cookies for security reason.
|
||||
| If you decide to not decrypt cookies, you will have to configure Laravel
|
||||
| to not encrypt your cookie token by adding its name into the $except
|
||||
| array available in the middleware "EncryptCookies" provided by Laravel.
|
||||
| see https://laravel.com/docs/master/responses#cookies-and-encryption
|
||||
| for details.
|
||||
|
|
||||
| Set it to true if you want to decrypt cookies.
|
||||
|
|
||||
*/
|
||||
|
||||
'decrypt_cookies' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cookie key name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the cookie key name that you would like to use for the cookie token.
|
||||
|
|
||||
*/
|
||||
|
||||
'cookie_key_name' => 'token',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Providers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the various providers used throughout the package.
|
||||
|
|
||||
*/
|
||||
|
||||
'providers' => [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| JWT Provider
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the provider that is used to create and decode the tokens.
|
||||
|
|
||||
*/
|
||||
|
||||
'jwt' => PHPOpenSourceSaver\JWTAuth\Providers\JWT\Lcobucci::class,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Provider
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the provider that is used to authenticate users.
|
||||
|
|
||||
*/
|
||||
|
||||
'auth' => PHPOpenSourceSaver\JWTAuth\Providers\Auth\Illuminate::class,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Storage Provider
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the provider that is used to store tokens in the blacklist.
|
||||
|
|
||||
*/
|
||||
|
||||
'storage' => PHPOpenSourceSaver\JWTAuth\Providers\Storage\Illuminate::class,
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,240 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Providers\Storage;
|
||||
use PHPOpenSourceSaver\JWTAuth\Support\Utils;
|
||||
|
||||
class Blacklist
|
||||
{
|
||||
/**
|
||||
* The storage.
|
||||
*
|
||||
* @var Storage
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* The grace period when a token is blacklisted. In seconds.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $gracePeriod = 0;
|
||||
|
||||
/**
|
||||
* Number of minutes from issue date in which a JWT can be refreshed.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $refreshTTL = 20160;
|
||||
|
||||
/**
|
||||
* The unique key held within the blacklist.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $key = 'jti';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Storage $storage)
|
||||
{
|
||||
$this->storage = $storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the token (jti claim) to the blacklist.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function add(Payload $payload)
|
||||
{
|
||||
// if there is no exp claim then add the jwt to
|
||||
// the blacklist indefinitely
|
||||
if (!$payload->hasKey('exp')) {
|
||||
return $this->addForever($payload);
|
||||
}
|
||||
|
||||
// if we have already added this token to the blacklist
|
||||
if (!empty($this->storage->get($this->getKey($payload)))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->storage->add(
|
||||
$this->getKey($payload),
|
||||
['valid_until' => $this->getGraceTimestamp()],
|
||||
$this->getMinutesUntilExpired($payload)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of minutes until the token expiry.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getMinutesUntilExpired(Payload $payload)
|
||||
{
|
||||
$exp = Utils::timestamp($payload['exp']);
|
||||
$iat = Utils::timestamp($payload['iat']);
|
||||
|
||||
// get the latter of the two expiration dates and find
|
||||
// the number of minutes until the expiration date,
|
||||
// plus 1 minute to avoid overlap
|
||||
$intermediateResult = $exp->max($iat->addMinutes($this->refreshTTL))->addMinute();
|
||||
|
||||
// Handle Carbon 2 vs 3 deprecation of "Real" diff functions, see https://github.com/PHP-Open-Source-Saver/jwt-auth/issues/260
|
||||
if (method_exists($intermediateResult, 'diffInRealMinutes')) {
|
||||
return (int) round($intermediateResult->diffInRealMinutes(null, true));
|
||||
} else {
|
||||
return (int) round($intermediateResult->diffInMinutes(null, true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the token (jti claim) to the blacklist indefinitely.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function addForever(Payload $payload)
|
||||
{
|
||||
$this->storage->forever($this->getKey($payload), 'forever');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the token has been blacklisted.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has(Payload $payload)
|
||||
{
|
||||
$val = $this->storage->get($this->getKey($payload));
|
||||
|
||||
// exit early if the token was blacklisted forever,
|
||||
if ('forever' === $val) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check whether the expiry + grace has past
|
||||
return !empty($val) && !Utils::isFuture($val['valid_until']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the token (jti claim) from the blacklist.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function remove(Payload $payload)
|
||||
{
|
||||
return $this->storage->destroy($this->getKey($payload));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all tokens from the blacklist.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->storage->flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp when the blacklist comes into effect
|
||||
* This defaults to immediate (0 seconds).
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getGraceTimestamp()
|
||||
{
|
||||
return Utils::now()->addSeconds($this->gracePeriod)->getTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the grace period.
|
||||
*
|
||||
* @param int $gracePeriod
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setGracePeriod($gracePeriod)
|
||||
{
|
||||
$this->gracePeriod = (int) $gracePeriod;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the grace period.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getGracePeriod()
|
||||
{
|
||||
return $this->gracePeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unique key held within the blacklist.
|
||||
*/
|
||||
public function getKey(Payload $payload)
|
||||
{
|
||||
return $payload($this->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the unique key held within the blacklist.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setKey($key)
|
||||
{
|
||||
$this->key = value($key);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the refresh time limit.
|
||||
*
|
||||
* @param int $ttl
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRefreshTTL($ttl)
|
||||
{
|
||||
$this->refreshTTL = (int) $ttl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the refresh time limit.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getRefreshTTL()
|
||||
{
|
||||
return $this->refreshTTL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Claims;
|
||||
|
||||
class Audience extends Claim
|
||||
{
|
||||
protected $name = 'aud';
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Claims;
|
||||
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Contracts\Support\Jsonable;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Claim as ClaimContract;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\InvalidClaimException;
|
||||
|
||||
abstract class Claim implements Arrayable, ClaimContract, Jsonable, \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* The claim name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The claim value.
|
||||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidClaimException
|
||||
*/
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->setValue($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the claim value, and call a validate method.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidClaimException
|
||||
*/
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = $this->validateCreate($value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the claim value.
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the claim name.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the claim name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the claim in a standalone Claim context.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validateCreate($value)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the Claim within a Payload context.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validatePayload()
|
||||
{
|
||||
return $this->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the Claim within a refresh context.
|
||||
*
|
||||
* @param int $refreshTTL
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validateRefresh($refreshTTL)
|
||||
{
|
||||
return $this->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value matches the claim.
|
||||
*
|
||||
* @param bool $strict
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function matches($value, $strict = true)
|
||||
{
|
||||
return $strict ? $this->value === $value : $this->value == $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the object into something JSON serializable.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a key value array comprising of the claim name and value.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return [$this->getName() => $this->getValue()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the claim as JSON.
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toJson($options = JSON_UNESCAPED_SLASHES)
|
||||
{
|
||||
return json_encode($this->toArray(), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the payload as a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->toJson();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Claims;
|
||||
|
||||
use Illuminate\Support\Collection as IlluminateCollection;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Collection extends IlluminateCollection
|
||||
{
|
||||
/**
|
||||
* Create a new collection.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($items = [])
|
||||
{
|
||||
parent::__construct($this->getArrayableItems($items));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Claim instance by it's unique name.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Claim
|
||||
*/
|
||||
public function getByClaimName($name, ?callable $callback = null, $default = null)
|
||||
{
|
||||
return $this->filter(function (Claim $claim) use ($name) {
|
||||
return $claim->getName() === $name;
|
||||
})->first($callback, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate each claim under a given context.
|
||||
*
|
||||
* @param string $context
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function validate($context = 'payload')
|
||||
{
|
||||
$args = func_get_args();
|
||||
array_shift($args);
|
||||
|
||||
$this->each(function ($claim) use ($context, $args) {
|
||||
call_user_func_array(
|
||||
[$claim, 'validate'.Str::ucfirst($context)],
|
||||
$args
|
||||
);
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the Collection contains all of the given keys.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasAllClaims($claims)
|
||||
{
|
||||
if (!count($claims)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($claims as $claim) {
|
||||
if (!$this->has($claim)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the claims as key/val array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toPlainArray()
|
||||
{
|
||||
return $this->map(function (Claim $claim) {
|
||||
return $claim->getValue();
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
protected function getArrayableItems($items)
|
||||
{
|
||||
return $this->sanitizeClaims($items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the given claims array is keyed by the claim name.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function sanitizeClaims($items)
|
||||
{
|
||||
$claims = [];
|
||||
foreach ($items as $key => $value) {
|
||||
if (!is_string($key) && $value instanceof Claim) {
|
||||
$key = $value->getName();
|
||||
}
|
||||
|
||||
$claims[$key] = $value;
|
||||
}
|
||||
|
||||
return $claims;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Claims;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\InvalidClaimException;
|
||||
|
||||
class Custom extends Claim
|
||||
{
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidClaimException
|
||||
*/
|
||||
public function __construct($name, $value)
|
||||
{
|
||||
parent::__construct($value);
|
||||
$this->setName($name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Claims;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\InvalidClaimException;
|
||||
use PHPOpenSourceSaver\JWTAuth\Support\Utils;
|
||||
|
||||
trait DatetimeTrait
|
||||
{
|
||||
/**
|
||||
* Time leeway in seconds.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $leeway = 0;
|
||||
|
||||
/**
|
||||
* Set the claim value, and call a validate method.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidClaimException
|
||||
*/
|
||||
public function setValue($value)
|
||||
{
|
||||
if ($value instanceof \DateInterval) {
|
||||
$value = Utils::now()->add($value);
|
||||
}
|
||||
|
||||
if ($value instanceof \DateTimeInterface) {
|
||||
$value = $value->getTimestamp();
|
||||
}
|
||||
|
||||
return parent::setValue($value);
|
||||
}
|
||||
|
||||
public function validateCreate($value)
|
||||
{
|
||||
if (!is_numeric($value)) {
|
||||
throw new InvalidClaimException($this);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the value is in the future.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isFuture($value)
|
||||
{
|
||||
return Utils::isFuture($value, $this->leeway);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the value is in the past.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isPast($value)
|
||||
{
|
||||
return Utils::isPast($value, $this->leeway);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the leeway in seconds.
|
||||
*
|
||||
* @param int $leeway
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setLeeway($leeway)
|
||||
{
|
||||
$this->leeway = $leeway;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Claims;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\TokenExpiredException;
|
||||
|
||||
class Expiration extends Claim
|
||||
{
|
||||
use DatetimeTrait;
|
||||
|
||||
protected $name = 'exp';
|
||||
|
||||
public function validatePayload()
|
||||
{
|
||||
if ($this->isPast($this->getValue())) {
|
||||
throw new TokenExpiredException('Token has expired');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Claims;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\InvalidClaimException;
|
||||
use PHPOpenSourceSaver\JWTAuth\Support\Utils;
|
||||
|
||||
class Factory
|
||||
{
|
||||
/**
|
||||
* The request.
|
||||
*
|
||||
* @var Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* The TTL.
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
protected $ttl = 60;
|
||||
|
||||
/**
|
||||
* Time leeway in seconds.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $leeway = 0;
|
||||
|
||||
/**
|
||||
* The classes map.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $classMap = [
|
||||
'aud' => Audience::class,
|
||||
'exp' => Expiration::class,
|
||||
'iat' => IssuedAt::class,
|
||||
'iss' => Issuer::class,
|
||||
'jti' => JwtId::class,
|
||||
'nbf' => NotBefore::class,
|
||||
'sub' => Subject::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the instance of the claim when passing the name and value.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Claim
|
||||
*
|
||||
* @throws InvalidClaimException
|
||||
*/
|
||||
public function get($name, $value)
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
$claim = new $this->classMap[$name]($value);
|
||||
|
||||
return method_exists($claim, 'setLeeway') ?
|
||||
$claim->setLeeway($this->leeway) :
|
||||
$claim;
|
||||
}
|
||||
|
||||
return new Custom($name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the claim exists.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return array_key_exists($name, $this->classMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the initial value and return the Claim instance.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Claim
|
||||
*
|
||||
* @throws InvalidClaimException
|
||||
*/
|
||||
public function make($name)
|
||||
{
|
||||
return $this->get($name, $this->$name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Issuer (iss) claim.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function iss()
|
||||
{
|
||||
return $this->request->url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Issued At (iat) claim.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function iat()
|
||||
{
|
||||
return Utils::now()->getTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Expiration (exp) claim.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function exp()
|
||||
{
|
||||
return Utils::now()->addMinutes($this->ttl)->getTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Not Before (nbf) claim.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function nbf()
|
||||
{
|
||||
return Utils::now()->getTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JWT Id (jti) claim.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function jti()
|
||||
{
|
||||
return Str::random();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new claim mapping.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $classPath
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function extend($name, $classPath)
|
||||
{
|
||||
$this->classMap[$name] = $classPath;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the request instance.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRequest(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the token ttl (in minutes).
|
||||
*
|
||||
* @param int|null $ttl
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTTL($ttl)
|
||||
{
|
||||
$this->ttl = $ttl ? (int) $ttl : $ttl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token ttl.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getTTL()
|
||||
{
|
||||
return $this->ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the leeway in seconds.
|
||||
*
|
||||
* @param int $leeway
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setLeeway($leeway)
|
||||
{
|
||||
$this->leeway = $leeway;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Claims;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\InvalidClaimException;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\TokenExpiredException;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\TokenInvalidException;
|
||||
|
||||
class IssuedAt extends Claim
|
||||
{
|
||||
use DatetimeTrait {
|
||||
validateCreate as commonValidateCreate;
|
||||
}
|
||||
|
||||
protected $name = 'iat';
|
||||
|
||||
public function validateCreate($value)
|
||||
{
|
||||
$this->commonValidateCreate($value);
|
||||
|
||||
if ($this->isFuture($value)) {
|
||||
throw new InvalidClaimException($this);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function validatePayload()
|
||||
{
|
||||
if ($this->isFuture($this->getValue())) {
|
||||
throw new TokenInvalidException('Issued At (iat) timestamp cannot be in the future');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function validateRefresh($refreshTTL)
|
||||
{
|
||||
if ($this->isPast($this->getValue() + $refreshTTL * 60)) {
|
||||
throw new TokenExpiredException('Token has expired and can no longer be refreshed');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Claims;
|
||||
|
||||
class Issuer extends Claim
|
||||
{
|
||||
protected $name = 'iss';
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Claims;
|
||||
|
||||
class JwtId extends Claim
|
||||
{
|
||||
protected $name = 'jti';
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Claims;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\TokenInvalidException;
|
||||
|
||||
class NotBefore extends Claim
|
||||
{
|
||||
use DatetimeTrait;
|
||||
|
||||
protected $name = 'nbf';
|
||||
|
||||
/**
|
||||
* @throws TokenInvalidException
|
||||
*/
|
||||
public function validatePayload()
|
||||
{
|
||||
if ($this->isFuture($this->getValue())) {
|
||||
throw new TokenInvalidException('Not Before (nbf) timestamp cannot be in the future');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Claims;
|
||||
|
||||
class Subject extends Claim
|
||||
{
|
||||
protected $name = 'sub';
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Console;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
trait EnvHelperTrait
|
||||
{
|
||||
/**
|
||||
* Checks if the env file exists.
|
||||
*/
|
||||
protected function envFileExists(): bool
|
||||
{
|
||||
return file_exists($this->envPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an env-file entry.
|
||||
*
|
||||
* @param string|int $value
|
||||
*/
|
||||
public function updateEnvEntry(string $key, $value, ?\Closure $confirmOnExisting = null): bool
|
||||
{
|
||||
$filepath = $this->envPath();
|
||||
|
||||
$filecontents = $this->getFileContents($filepath);
|
||||
|
||||
if (false === Str::contains($filecontents, $key)) {
|
||||
// create new entry
|
||||
$this->putFileContents(
|
||||
$filepath,
|
||||
$filecontents.PHP_EOL."{$key}={$value}".PHP_EOL
|
||||
);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
if (is_null($confirmOnExisting) || $confirmOnExisting()) {
|
||||
// update existing entry
|
||||
$this->putFileContents(
|
||||
$filepath,
|
||||
preg_replace(
|
||||
"/{$key}=.*/",
|
||||
"{$key}={$value}",
|
||||
$filecontents
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function getFileContents(string $filepath): string
|
||||
{
|
||||
return file_get_contents($filepath);
|
||||
}
|
||||
|
||||
protected function putFileContents(string $filepath, string $data): void
|
||||
{
|
||||
file_put_contents($filepath, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the .env file path.
|
||||
*/
|
||||
protected function envPath(): string
|
||||
{
|
||||
if (method_exists($this->laravel, 'environmentFilePath')) {
|
||||
return $this->laravel->environmentFilePath();
|
||||
}
|
||||
|
||||
return $this->laravel->basePath('.env');
|
||||
}
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class JWTGenerateCertCommand extends Command
|
||||
{
|
||||
use EnvHelperTrait;
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'jwt:generate-certs
|
||||
{--force : Override certificates if existing}
|
||||
{--algo= : Algorithm (rsa/ec)}
|
||||
{--bits= : RSA-Key length (1024,2048,4096,8192}
|
||||
{--sha= : SHA-variant (1,224,256,384,512)}
|
||||
{--dir= : Directory where the certificates should be placed}
|
||||
{--curve= : EC-Curvename (e.g. secp384r1, prime256v1 )}
|
||||
{--passphrase= : Passphrase}
|
||||
{--ask-passphrase : Enter passphrase instead passing as argument}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Generates a new cert pair';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$force = $this->option('force');
|
||||
$directory = $this->option('dir') ? $this->option('dir') : 'storage/certs';
|
||||
$algo = $this->option('algo') ? $this->option('algo') : 'rsa';
|
||||
$bits = $this->option('bits') ? intval($this->option('bits')) : 4096;
|
||||
$shaVariant = $this->option('sha') ? intval($this->option('sha')) : 512;
|
||||
$curve = $this->option('curve') ? $this->option('curve') : 'prime256v1';
|
||||
|
||||
if ($this->option('ask-passphrase')) {
|
||||
$passphrase = $this->secret('Passphrase');
|
||||
} else {
|
||||
$passphrase = $this->option('passphrase') ? $this->option('passphrase') : null;
|
||||
}
|
||||
|
||||
$filenamePublic = sprintf('%s/jwt-%s-%d-public.pem', $directory, $algo, $bits);
|
||||
$filenamePrivate = sprintf('%s/jwt-%s-%d-private.pem', $directory, $algo, $bits);
|
||||
|
||||
if (true === file_exists($filenamePrivate)) {
|
||||
$this->warn('Private cert already exists');
|
||||
|
||||
if (!$force) {
|
||||
$this->warn('Aborting');
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (true === file_exists($filenamePublic)) {
|
||||
$this->warn('Public cert already exists');
|
||||
|
||||
if (!$force) {
|
||||
$this->warn('Aborting');
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($algo) {
|
||||
case 'rsa':
|
||||
$keyType = OPENSSL_KEYTYPE_RSA;
|
||||
$algoIdentifier = sprintf('RS%d', $shaVariant);
|
||||
break;
|
||||
|
||||
case 'ec':
|
||||
$keyType = OPENSSL_KEYTYPE_EC;
|
||||
$algoIdentifier = sprintf('ES%d', $shaVariant);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->error('Unknown algorithm');
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create the private and public key
|
||||
$res = openssl_pkey_new([
|
||||
'digest_alg' => sprintf('sha%d', $shaVariant),
|
||||
'private_key_bits' => $bits,
|
||||
'private_key_type' => $keyType,
|
||||
'curve_name' => $curve,
|
||||
]);
|
||||
|
||||
// Extract the private key from $res to $privKey
|
||||
openssl_pkey_export($res, $privKey, $passphrase);
|
||||
|
||||
// Extract the public key from $res to $pubKey
|
||||
$pubKey = openssl_pkey_get_details($res);
|
||||
$pubKey = $pubKey['key'];
|
||||
|
||||
// save certificates to disk
|
||||
if (false === is_dir($directory)) {
|
||||
mkdir($directory, 0777, true);
|
||||
}
|
||||
|
||||
file_put_contents($filenamePrivate, $privKey);
|
||||
file_put_contents($filenamePublic, $pubKey);
|
||||
|
||||
// Updated .env-file
|
||||
if (!$this->envFileExists()) {
|
||||
$this->error('.env file missing');
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
$this->updateEnvEntry('JWT_ALGO', $algoIdentifier);
|
||||
$this->updateEnvEntry('JWT_PRIVATE_KEY', sprintf('file://../%s', $filenamePrivate));
|
||||
$this->updateEnvEntry('JWT_PUBLIC_KEY', sprintf('file://../%s', $filenamePublic));
|
||||
$this->updateEnvEntry('JWT_PASSPHRASE', $passphrase ?? '');
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class JWTGenerateSecretCommand extends Command
|
||||
{
|
||||
use EnvHelperTrait;
|
||||
|
||||
/**
|
||||
* The console command signature.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'jwt:secret
|
||||
{--s|show : Display the key instead of modifying files.}
|
||||
{--always-no : Skip generating key if it already exists.}
|
||||
{--f|force : Skip confirmation when overwriting an existing key.}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Set the JWTAuth secret key used to sign the tokens';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$key = Str::random(64);
|
||||
|
||||
if ($this->option('show')) {
|
||||
$this->comment($key);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->envFileExists()) {
|
||||
$this->displayKey($key);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$updated = $this->updateEnvEntry('JWT_SECRET', $key, function () {
|
||||
if ($this->option('always-no')) {
|
||||
$this->comment('Secret key already exists. Skipping...');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (false === $this->isConfirmed()) {
|
||||
$this->comment('Phew... No changes were made to your secret key.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if ($updated) {
|
||||
$this->updateEnvEntry('JWT_ALGO', 'HS256');
|
||||
$this->info('jwt-auth secret set successfully.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the key.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function displayKey($key)
|
||||
{
|
||||
$this->laravel['config']['jwt.secret'] = $key;
|
||||
|
||||
$this->info("jwt-auth secret [$key] set successfully.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the modification is confirmed.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isConfirmed()
|
||||
{
|
||||
return $this->option('force') ? true : $this->confirm(
|
||||
'This will invalidate all existing tokens. Are you sure you want to override the secret key?'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Contracts;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\InvalidClaimException;
|
||||
|
||||
interface Claim
|
||||
{
|
||||
/**
|
||||
* Set the claim value, and call a validate method.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidClaimException
|
||||
*/
|
||||
public function setValue($value);
|
||||
|
||||
/**
|
||||
* Get the claim value.
|
||||
*/
|
||||
public function getValue();
|
||||
|
||||
/**
|
||||
* Set the claim name.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($name);
|
||||
|
||||
/**
|
||||
* Get the claim name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Validate the Claim value.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validateCreate($value);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Contracts\Http;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
interface Parser
|
||||
{
|
||||
/**
|
||||
* Parse the request.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function parse(Request $request);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Contracts;
|
||||
|
||||
interface JWTSubject
|
||||
{
|
||||
/**
|
||||
* Get the identifier that will be stored in the subject claim of the JWT.
|
||||
*/
|
||||
public function getJWTIdentifier();
|
||||
|
||||
/**
|
||||
* Return a key value array, containing any custom claims to be added to the JWT.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJWTCustomClaims();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Contracts\Providers;
|
||||
|
||||
interface Auth
|
||||
{
|
||||
/**
|
||||
* Check a user's credentials.
|
||||
*/
|
||||
public function byCredentials(array $credentials);
|
||||
|
||||
/**
|
||||
* Authenticate a user via the id.
|
||||
*/
|
||||
public function byId($id);
|
||||
|
||||
/**
|
||||
* Get the currently authenticated user.
|
||||
*/
|
||||
public function user();
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Contracts\Providers;
|
||||
|
||||
interface JWT
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function encode(array $payload);
|
||||
|
||||
/**
|
||||
* @param string $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function decode($token);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Contracts\Providers;
|
||||
|
||||
interface Storage
|
||||
{
|
||||
/**
|
||||
* @param string $key
|
||||
* @param int $minutes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($key, $value, $minutes);
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function forever($key, $value);
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*/
|
||||
public function get($key);
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy($key);
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function flush();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Contracts;
|
||||
|
||||
interface Validator
|
||||
{
|
||||
/**
|
||||
* Perform some checks on the value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function check($value);
|
||||
|
||||
/**
|
||||
* Helper function to return a boolean.
|
||||
*
|
||||
* @param array $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($value);
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Exceptions;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Claims\Claim;
|
||||
|
||||
class InvalidClaimException extends JWTException
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param int $code
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Claim $claim, $code = 0, ?\Exception $previous = null)
|
||||
{
|
||||
parent::__construct('Invalid value provided for claim ['.$claim->getName().']', $code, $previous);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Exceptions;
|
||||
|
||||
class JWTException extends \Exception
|
||||
{
|
||||
protected $message = 'An error occurred';
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Exceptions;
|
||||
|
||||
class PayloadException extends JWTException
|
||||
{
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Exceptions;
|
||||
|
||||
class SecretMissingException extends JWTException
|
||||
{
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Exceptions;
|
||||
|
||||
class TokenBlacklistedException extends TokenInvalidException
|
||||
{
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Exceptions;
|
||||
|
||||
class TokenExpiredException extends JWTException
|
||||
{
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Exceptions;
|
||||
|
||||
class TokenInvalidException extends JWTException
|
||||
{
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Exceptions;
|
||||
|
||||
class UserNotDefinedException extends JWTException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Facades;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
class JWTAuth extends Facade
|
||||
{
|
||||
/**
|
||||
* Get the registered name of the component.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getFacadeAccessor()
|
||||
{
|
||||
return 'tymon.jwt.auth';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Facades;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
class JWTFactory extends Facade
|
||||
{
|
||||
/**
|
||||
* Get the registered name of the component.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getFacadeAccessor()
|
||||
{
|
||||
return 'tymon.jwt.payload.factory';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Facades;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
class JWTProvider extends Facade
|
||||
{
|
||||
/**
|
||||
* Get the registered name of the component.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getFacadeAccessor()
|
||||
{
|
||||
return 'tymon.jwt.provider.jwt';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Claims\Claim;
|
||||
use PHPOpenSourceSaver\JWTAuth\Claims\Collection;
|
||||
use PHPOpenSourceSaver\JWTAuth\Claims\Factory as ClaimFactory;
|
||||
use PHPOpenSourceSaver\JWTAuth\Support\CustomClaims;
|
||||
use PHPOpenSourceSaver\JWTAuth\Support\RefreshFlow;
|
||||
use PHPOpenSourceSaver\JWTAuth\Validators\PayloadValidator;
|
||||
|
||||
class Factory
|
||||
{
|
||||
use CustomClaims;
|
||||
use RefreshFlow;
|
||||
|
||||
/**
|
||||
* The claim factory.
|
||||
*
|
||||
* @var ClaimFactory
|
||||
*/
|
||||
protected $claimFactory;
|
||||
|
||||
/**
|
||||
* The validator.
|
||||
*
|
||||
* @var PayloadValidator
|
||||
*/
|
||||
protected $validator;
|
||||
|
||||
/**
|
||||
* The default claims.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $defaultClaims = [
|
||||
'iss',
|
||||
'iat',
|
||||
'exp',
|
||||
'nbf',
|
||||
'jti',
|
||||
];
|
||||
|
||||
/**
|
||||
* The claims collection.
|
||||
*
|
||||
* @var Collection
|
||||
*/
|
||||
protected $claims;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ClaimFactory $claimFactory, PayloadValidator $validator)
|
||||
{
|
||||
$this->claimFactory = $claimFactory;
|
||||
$this->validator = $validator;
|
||||
$this->claims = new Collection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the Payload instance.
|
||||
*
|
||||
* @param bool $resetClaims
|
||||
*
|
||||
* @return Payload
|
||||
*/
|
||||
public function make($resetClaims = false)
|
||||
{
|
||||
if ($resetClaims) {
|
||||
$this->emptyClaims();
|
||||
}
|
||||
|
||||
return $this->withClaims($this->buildClaimsCollection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty the claims collection.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function emptyClaims()
|
||||
{
|
||||
$this->claims = new Collection();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an array of claims to the Payload.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function addClaims(array $claims)
|
||||
{
|
||||
foreach ($claims as $name => $value) {
|
||||
$this->addClaim($name, $value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a claim to the Payload.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function addClaim($name, $value)
|
||||
{
|
||||
$this->claims->put($name, $value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the default claims.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function buildClaims()
|
||||
{
|
||||
// remove the exp claim if it exists and the ttl is null
|
||||
if (null === $this->claimFactory->getTTL() && $key = array_search('exp', $this->defaultClaims)) {
|
||||
unset($this->defaultClaims[$key]);
|
||||
}
|
||||
|
||||
// add the default claims
|
||||
foreach ($this->defaultClaims as $claim) {
|
||||
$this->addClaim($claim, $this->claimFactory->make($claim));
|
||||
}
|
||||
|
||||
// add custom claims on top, allowing them to overwrite defaults
|
||||
return $this->addClaims($this->getCustomClaims());
|
||||
}
|
||||
|
||||
/**
|
||||
* Build out the Claim DTO's.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
protected function resolveClaims()
|
||||
{
|
||||
return $this->claims->map(function ($value, $name) {
|
||||
return $value instanceof Claim ? $value : $this->claimFactory->get($name, $value);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and get the Claims Collection.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function buildClaimsCollection()
|
||||
{
|
||||
return $this->buildClaims()->resolveClaims();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Payload instance with a claims collection.
|
||||
*
|
||||
* @return Payload
|
||||
*/
|
||||
public function withClaims(Collection $claims)
|
||||
{
|
||||
return new Payload($claims, $this->validator, $this->refreshFlow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default claims to be added to the Payload.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDefaultClaims(array $claims)
|
||||
{
|
||||
$this->defaultClaims = $claims;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to set the ttl.
|
||||
*
|
||||
* @param int|null $ttl
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTTL($ttl)
|
||||
{
|
||||
$this->claimFactory->setTTL($ttl);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get the ttl.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getTTL()
|
||||
{
|
||||
return $this->claimFactory->getTTL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default claims.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDefaultClaims()
|
||||
{
|
||||
return $this->defaultClaims;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PayloadValidator instance.
|
||||
*
|
||||
* @return PayloadValidator
|
||||
*/
|
||||
public function validator()
|
||||
{
|
||||
return $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magically add a claim.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
$this->addClaim($method, $parameters[0]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
||||
|
||||
class Authenticate extends BaseMiddleware
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @throws UnauthorizedHttpException
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
$this->authenticate($request);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
||||
|
||||
class AuthenticateAndRenew extends BaseMiddleware
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @throws UnauthorizedHttpException
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
$this->authenticate($request);
|
||||
|
||||
$response = $next($request);
|
||||
|
||||
// Send the refreshed token back to the client.
|
||||
return $this->setAuthenticationHeader($response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\JWTException;
|
||||
use PHPOpenSourceSaver\JWTAuth\JWTAuth;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
||||
|
||||
abstract class BaseMiddleware
|
||||
{
|
||||
/**
|
||||
* The JWT Authenticator.
|
||||
*/
|
||||
protected JWTAuth $auth;
|
||||
|
||||
/**
|
||||
* Create a new BaseMiddleware instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(JWTAuth $auth)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the request for the presence of a token.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws BadRequestHttpException
|
||||
*/
|
||||
public function checkForToken(Request $request)
|
||||
{
|
||||
if (!$this->auth->parser()->setRequest($request)->hasToken()) {
|
||||
throw new UnauthorizedHttpException('jwt-auth', 'Token not provided');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to authenticate a user via the token in the request.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws UnauthorizedHttpException
|
||||
*/
|
||||
public function authenticate(Request $request)
|
||||
{
|
||||
$this->checkForToken($request);
|
||||
|
||||
try {
|
||||
if (!$this->auth->parseToken()->authenticate()) {
|
||||
throw new UnauthorizedHttpException('jwt-auth', 'User not found');
|
||||
}
|
||||
} catch (JWTException $e) {
|
||||
throw new UnauthorizedHttpException('jwt-auth', $e->getMessage(), $e, $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the authentication header.
|
||||
*
|
||||
* @param Response|JsonResponse $response
|
||||
* @param string|null $token
|
||||
*
|
||||
* @return Response|JsonResponse
|
||||
*/
|
||||
protected function setAuthenticationHeader($response, $token = null)
|
||||
{
|
||||
$token = $token ?: $this->auth->refresh();
|
||||
$response->headers->set('Authorization', 'Bearer '.$token);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class Check extends BaseMiddleware
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request $request
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
if ($this->auth->parser()->setRequest($request)->hasToken()) {
|
||||
try {
|
||||
$this->auth->parseToken()->authenticate();
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\JWTException;
|
||||
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
||||
|
||||
class RefreshToken extends BaseMiddleware
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @throws UnauthorizedHttpException
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
$this->checkForToken($request);
|
||||
|
||||
try {
|
||||
$token = $this->auth->parseToken()->refresh();
|
||||
} catch (JWTException $e) {
|
||||
throw new UnauthorizedHttpException('jwt-auth', $e->getMessage(), $e, $e->getCode());
|
||||
}
|
||||
|
||||
$response = $next($request);
|
||||
|
||||
// Send the refreshed token back to the client.
|
||||
return $this->setAuthenticationHeader($response, $token);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Http\Parser;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Http\Parser as ParserContract;
|
||||
|
||||
class AuthHeaders implements ParserContract
|
||||
{
|
||||
/**
|
||||
* The header name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $header = 'authorization';
|
||||
|
||||
/**
|
||||
* The header prefix.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $prefix = 'bearer';
|
||||
|
||||
/**
|
||||
* Attempt to parse the token from some other possible headers.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function fromAltHeaders(Request $request)
|
||||
{
|
||||
return $request->server->get('HTTP_AUTHORIZATION') ?: $request->server->get('REDIRECT_HTTP_AUTHORIZATION');
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to parse the token from the request header.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function parse(Request $request)
|
||||
{
|
||||
$header = $request->headers->get($this->header) ?: $this->fromAltHeaders($request);
|
||||
|
||||
if (null !== $header) {
|
||||
$position = strripos($header, $this->prefix);
|
||||
|
||||
if (false !== $position) {
|
||||
$header = substr($header, $position + strlen($this->prefix));
|
||||
|
||||
return trim(
|
||||
false !== strpos($header, ',') ? strstr($header, ',', true) : $header
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the header name.
|
||||
*
|
||||
* @param string $headerName
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setHeaderName($headerName)
|
||||
{
|
||||
$this->header = $headerName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the header prefix.
|
||||
*
|
||||
* @param string $headerPrefix
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setHeaderPrefix($headerPrefix)
|
||||
{
|
||||
$this->prefix = $headerPrefix;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Http\Parser;
|
||||
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Http\Parser as ParserContract;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\TokenInvalidException;
|
||||
|
||||
class Cookies implements ParserContract
|
||||
{
|
||||
use KeyTrait;
|
||||
|
||||
/**
|
||||
* Decrypt or not the cookie while parsing.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $decrypt;
|
||||
|
||||
public function __construct($decrypt = true)
|
||||
{
|
||||
$this->decrypt = $decrypt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to parse the token from the request cookies.
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* @throws TokenInvalidException
|
||||
*/
|
||||
public function parse(Request $request)
|
||||
{
|
||||
if ($this->decrypt && $request->hasCookie($this->key)) {
|
||||
try {
|
||||
return Crypt::decrypt($request->cookie($this->key));
|
||||
} catch (DecryptException $ex) {
|
||||
throw new TokenInvalidException('Token has not decrypted successfully.');
|
||||
}
|
||||
}
|
||||
|
||||
return $request->cookie($this->key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Http\Parser;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Http\Parser as ParserContract;
|
||||
|
||||
class InputSource implements ParserContract
|
||||
{
|
||||
use KeyTrait;
|
||||
|
||||
/**
|
||||
* Try to parse the token from the request input source.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function parse(Request $request)
|
||||
{
|
||||
return $request->input($this->key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Http\Parser;
|
||||
|
||||
trait KeyTrait
|
||||
{
|
||||
/**
|
||||
* The key.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $key = 'token';
|
||||
|
||||
/**
|
||||
* Set the key.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setKey($key)
|
||||
{
|
||||
$this->key = $key;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
return $this->key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Http\Parser;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class LumenRouteParams extends RouteParams
|
||||
{
|
||||
/**
|
||||
* Try to get the token from the route parameters.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function parse(Request $request)
|
||||
{
|
||||
// WARNING: Only use this parser if you know what you're doing!
|
||||
// It will only work with poorly-specified aspects of certain Lumen releases.
|
||||
// Route is the expected kind of array, and has a parameter with the key we want.
|
||||
return Arr::get($request->route(), '2.'.$this->key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Http\Parser;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class Parser
|
||||
{
|
||||
/**
|
||||
* The chain.
|
||||
*/
|
||||
private array $chain;
|
||||
|
||||
/**
|
||||
* The request.
|
||||
*/
|
||||
protected Request $request;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Request $request, array $chain = [])
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->chain = $chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parser chain.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getChain()
|
||||
{
|
||||
return $this->chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new parser to the chain.
|
||||
*
|
||||
* @param array|\PHPOpenSourceSaver\JWTAuth\Contracts\Http\Parser $parsers
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addParser($parsers)
|
||||
{
|
||||
$this->chain = array_merge($this->chain, is_array($parsers) ? $parsers : [$parsers]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the order of the parser chain.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setChain(array $chain)
|
||||
{
|
||||
$this->chain = $chain;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for setting the order of the chain.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setChainOrder(array $chain)
|
||||
{
|
||||
return $this->setChain($chain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate through the parsers and attempt to retrieve
|
||||
* a value, otherwise return null.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function parseToken()
|
||||
{
|
||||
foreach ($this->chain as $parser) {
|
||||
if ($response = $parser->parse($this->request)) {
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a token exists in the chain.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasToken()
|
||||
{
|
||||
return null !== $this->parseToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the request instance.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRequest(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Http\Parser;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Http\Parser as ParserContract;
|
||||
|
||||
class QueryString implements ParserContract
|
||||
{
|
||||
use KeyTrait;
|
||||
|
||||
/**
|
||||
* Try to parse the token from the request query string.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function parse(Request $request)
|
||||
{
|
||||
return $request->query($this->key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Http\Parser;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Http\Parser as ParserContract;
|
||||
|
||||
class RouteParams implements ParserContract
|
||||
{
|
||||
use KeyTrait;
|
||||
|
||||
/**
|
||||
* Try to get the token from the route parameters.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function parse(Request $request)
|
||||
{
|
||||
$route = $request->route();
|
||||
|
||||
// Route may not be an instance of Illuminate\Routing\Route
|
||||
// (it's an array in Lumen <5.2) or not exist at all
|
||||
// (if the request was never dispatched)
|
||||
if (is_callable([$route, 'parameter'])) {
|
||||
return $route->parameter($this->key);
|
||||
}
|
||||
}
|
||||
}
|
||||
+402
@@ -0,0 +1,402 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\JWTException;
|
||||
use PHPOpenSourceSaver\JWTAuth\Http\Parser\Parser;
|
||||
use PHPOpenSourceSaver\JWTAuth\Support\CustomClaims;
|
||||
|
||||
class JWT
|
||||
{
|
||||
use CustomClaims;
|
||||
|
||||
/**
|
||||
* The authentication manager.
|
||||
*
|
||||
* @var Manager
|
||||
*/
|
||||
protected $manager;
|
||||
|
||||
/**
|
||||
* The HTTP parser.
|
||||
*
|
||||
* @var Parser
|
||||
*/
|
||||
protected $parser;
|
||||
|
||||
/**
|
||||
* The token.
|
||||
*
|
||||
* @var Token|null
|
||||
*/
|
||||
protected $token;
|
||||
|
||||
/**
|
||||
* Lock the subject.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $lockSubject = true;
|
||||
|
||||
/**
|
||||
* JWT constructor.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Manager $manager, Parser $parser)
|
||||
{
|
||||
$this->manager = $manager;
|
||||
$this->parser = $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a token for a given subject.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function fromSubject(JWTSubject $subject)
|
||||
{
|
||||
$payload = $this->makePayload($subject);
|
||||
|
||||
return $this->manager->encode($payload)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias to generate a token for a given user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function fromUser(JWTSubject $user)
|
||||
{
|
||||
return $this->fromSubject($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh an expired token.
|
||||
*
|
||||
* @param bool $forceForever
|
||||
* @param bool $resetClaims
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function refresh($forceForever = false, $resetClaims = false)
|
||||
{
|
||||
$this->requireToken();
|
||||
|
||||
return $this->manager->customClaims($this->getCustomClaims())
|
||||
->refresh($this->token, $forceForever, $resetClaims)
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate a token (add it to the blacklist).
|
||||
*
|
||||
* @param bool $forceForever
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function invalidate($forceForever = false)
|
||||
{
|
||||
$this->requireToken();
|
||||
|
||||
$this->manager->invalidate($this->token, $forceForever);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias to get the payload, and as a result checks that
|
||||
* the token is valid i.e. not expired or blacklisted.
|
||||
*
|
||||
* @return Payload
|
||||
*
|
||||
* @throws JWTException
|
||||
*/
|
||||
public function checkOrFail()
|
||||
{
|
||||
return $this->getPayload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the token is valid.
|
||||
*
|
||||
* @param bool $getPayload
|
||||
*
|
||||
* @return Payload|bool
|
||||
*/
|
||||
public function check($getPayload = false)
|
||||
{
|
||||
try {
|
||||
$payload = $this->checkOrFail();
|
||||
} catch (JWTException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $getPayload ? $payload : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token.
|
||||
*
|
||||
* @return Token|null
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
if (null === $this->token) {
|
||||
try {
|
||||
$this->parseToken();
|
||||
} catch (JWTException $e) {
|
||||
$this->token = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the token from the request.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws JWTException
|
||||
*/
|
||||
public function parseToken()
|
||||
{
|
||||
if (!$token = $this->parser->parseToken()) {
|
||||
throw new JWTException('The token could not be parsed from the request');
|
||||
}
|
||||
|
||||
return $this->setToken($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw Payload instance.
|
||||
*
|
||||
* @return Payload
|
||||
*/
|
||||
public function getPayload()
|
||||
{
|
||||
$this->requireToken();
|
||||
|
||||
return $this->manager->decode($this->token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for getPayload().
|
||||
*
|
||||
* @return Payload
|
||||
*/
|
||||
public function payload()
|
||||
{
|
||||
return $this->getPayload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to get a claim value.
|
||||
*
|
||||
* @param string $claim
|
||||
*/
|
||||
public function getClaim($claim)
|
||||
{
|
||||
return $this->payload()->get($claim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Payload instance.
|
||||
*
|
||||
* @return Payload
|
||||
*/
|
||||
public function makePayload(JWTSubject $subject)
|
||||
{
|
||||
return $this->factory()->customClaims($this->getClaimsArray($subject))->make();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the claims array and return it.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getClaimsArray(JWTSubject $subject)
|
||||
{
|
||||
return array_merge(
|
||||
$this->getClaimsForSubject($subject),
|
||||
$subject->getJWTCustomClaims(), // custom claims from JWTSubject method
|
||||
$this->customClaims // custom claims from inline setter
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the claims associated with a given subject.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getClaimsForSubject(JWTSubject $subject)
|
||||
{
|
||||
return array_merge([
|
||||
'sub' => $subject->getJWTIdentifier(),
|
||||
], $this->lockSubject ? ['prv' => $this->hashSubjectModel($subject)] : []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash the subject model and return it.
|
||||
*
|
||||
* @param string|object $model
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function hashSubjectModel($model)
|
||||
{
|
||||
return sha1(is_object($model) ? get_class($model) : $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the subject model matches the one saved in the token.
|
||||
*
|
||||
* @param string|object $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function checkSubjectModel($model)
|
||||
{
|
||||
if (($prv = $this->payload()->get('prv')) === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->hashSubjectModel($model) === $prv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the token.
|
||||
*
|
||||
* @param Token|string $token
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setToken($token)
|
||||
{
|
||||
$this->token = $token instanceof Token ? $token : new Token($token);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset the current token.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function unsetToken()
|
||||
{
|
||||
$this->token = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a token is available.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws JWTException
|
||||
*/
|
||||
protected function requireToken()
|
||||
{
|
||||
if (!$this->token) {
|
||||
throw new JWTException('A token is required');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the request instance.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRequest(Request $request)
|
||||
{
|
||||
$this->parser->setRequest($request);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the subject should be "locked".
|
||||
*
|
||||
* @param bool $lock
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function lockSubject($lock)
|
||||
{
|
||||
$this->lockSubject = $lock;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Manager instance.
|
||||
*
|
||||
* @return Manager
|
||||
*/
|
||||
public function manager()
|
||||
{
|
||||
return $this->manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Parser instance.
|
||||
*
|
||||
* @return Parser
|
||||
*/
|
||||
public function parser()
|
||||
{
|
||||
return $this->parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Payload Factory.
|
||||
*
|
||||
* @return Factory
|
||||
*/
|
||||
public function factory()
|
||||
{
|
||||
return $this->manager->getPayloadFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Blacklist.
|
||||
*
|
||||
* @return Blacklist
|
||||
*/
|
||||
public function blacklist()
|
||||
{
|
||||
return $this->manager->getBlacklist();
|
||||
}
|
||||
|
||||
/**
|
||||
* Magically call the JWT Manager.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
if (method_exists($this->manager, $method)) {
|
||||
return call_user_func_array([$this->manager, $method], $parameters);
|
||||
}
|
||||
|
||||
throw new \BadMethodCallException("Method [$method] does not exist.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Providers\Auth;
|
||||
use PHPOpenSourceSaver\JWTAuth\Http\Parser\Parser;
|
||||
|
||||
class JWTAuth extends JWT
|
||||
{
|
||||
/**
|
||||
* The authentication provider.
|
||||
*
|
||||
* @var Auth
|
||||
*/
|
||||
protected $auth;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Manager $manager, Auth $auth, Parser $parser)
|
||||
{
|
||||
parent::__construct($manager, $parser);
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to authenticate the user and return the token.
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
public function attempt(array $credentials)
|
||||
{
|
||||
if (!$this->auth->byCredentials($credentials)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->fromUser($this->user());
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate a user via a token.
|
||||
*
|
||||
* @return JWTSubject|false
|
||||
*/
|
||||
public function authenticate()
|
||||
{
|
||||
$id = $this->getPayload()->get('sub') ?: $this->getPayload()->get('id');
|
||||
|
||||
if (!$this->auth->byId($id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->user();
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for authenticate().
|
||||
*
|
||||
* @return JWTSubject|false
|
||||
*/
|
||||
public function toUser()
|
||||
{
|
||||
return $this->authenticate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authenticated user.
|
||||
*
|
||||
* @return JWTSubject
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->auth->user();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,619 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth;
|
||||
|
||||
use Illuminate\Auth\Events\Attempting;
|
||||
use Illuminate\Auth\Events\Authenticated;
|
||||
use Illuminate\Auth\Events\Failed;
|
||||
use Illuminate\Auth\Events\Login;
|
||||
use Illuminate\Auth\Events\Logout;
|
||||
use Illuminate\Auth\GuardHelpers;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Traits\Macroable;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\JWTException;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\UserNotDefinedException;
|
||||
|
||||
/**
|
||||
* @mixin JWT
|
||||
*/
|
||||
class JWTGuard implements Guard
|
||||
{
|
||||
use GuardHelpers {
|
||||
setUser as guardHelperSetUser;
|
||||
}
|
||||
use Macroable {
|
||||
__call as macroCall;
|
||||
}
|
||||
|
||||
/**
|
||||
* The user we last attempted to retrieve.
|
||||
*
|
||||
* @var Authenticatable
|
||||
*/
|
||||
protected $lastAttempted;
|
||||
|
||||
/**
|
||||
* The JWT instance.
|
||||
*
|
||||
* @var JWT
|
||||
*/
|
||||
protected $jwt;
|
||||
|
||||
/**
|
||||
* The request instance.
|
||||
*
|
||||
* @var Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* The event dispatcher instance.
|
||||
*
|
||||
* @var Dispatcher
|
||||
*/
|
||||
protected $events;
|
||||
|
||||
/**
|
||||
* The name of the Guard.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'tymon.jwt';
|
||||
|
||||
/**
|
||||
* Instantiate the class.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(JWT $jwt, UserProvider $provider, Request $request, Dispatcher $eventDispatcher)
|
||||
{
|
||||
$this->jwt = $jwt;
|
||||
$this->provider = $provider;
|
||||
$this->request = $request;
|
||||
$this->events = $eventDispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently authenticated user.
|
||||
*
|
||||
* @return Authenticatable|null
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
if (null !== $this->user) {
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
if (
|
||||
$this->jwt->setRequest($this->request)->getToken()
|
||||
&& ($payload = $this->jwt->check(true))
|
||||
&& $this->validateSubject()
|
||||
) {
|
||||
return $this->user = $this->provider->retrieveById($payload['sub']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|string|null
|
||||
*/
|
||||
public function getUserId()
|
||||
{
|
||||
if (null !== $this->user) {
|
||||
return $this->user->getAuthIdentifier();
|
||||
}
|
||||
|
||||
if (
|
||||
$this->jwt->setRequest($this->request)->getToken()
|
||||
&& ($payload = $this->jwt->check(true))
|
||||
&& $this->validateSubject()
|
||||
) {
|
||||
return $payload['sub'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID for the currently authenticated user.
|
||||
*
|
||||
* @return int|string|null
|
||||
*/
|
||||
public function id()
|
||||
{
|
||||
return $this->getUserId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently authenticated user or throws an exception.
|
||||
*
|
||||
* @return Authenticatable
|
||||
*
|
||||
* @throws UserNotDefinedException
|
||||
*/
|
||||
public function userOrFail()
|
||||
{
|
||||
if (!$user = $this->user()) {
|
||||
throw new UserNotDefinedException();
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a user's credentials.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validate(array $credentials = [])
|
||||
{
|
||||
return (bool) $this->attempt($credentials, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to authenticate the user using the given credentials and return the token.
|
||||
*
|
||||
* @param bool $login
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function attempt(array $credentials = [], $login = true)
|
||||
{
|
||||
$this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
|
||||
|
||||
$this->fireAttemptEvent($credentials);
|
||||
|
||||
if ($this->hasValidCredentials($user, $credentials)) {
|
||||
return $login ? $this->login($user) : true;
|
||||
}
|
||||
|
||||
$this->fireFailedEvent($user, $credentials);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a token for a user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function login(JWTSubject $user)
|
||||
{
|
||||
$token = $this->jwt->fromUser($user);
|
||||
$this->setToken($token)->setUser($user);
|
||||
|
||||
$this->fireLoginEvent($user);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout the user, thus invalidating the token.
|
||||
*
|
||||
* @param bool $forceForever
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function logout($forceForever = false)
|
||||
{
|
||||
try {
|
||||
$this->requireToken()->invalidate($forceForever);
|
||||
} catch (JWTException $e) {
|
||||
// Proceed with the logout as normal if we can't invalidate the token
|
||||
}
|
||||
|
||||
$this->fireLogoutEvent($this->user);
|
||||
|
||||
$this->user = null;
|
||||
$this->jwt->unsetToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the token.
|
||||
*
|
||||
* @param bool $forceForever
|
||||
* @param bool $resetClaims
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function refresh($forceForever = false, $resetClaims = false)
|
||||
{
|
||||
return $this->requireToken()->refresh($forceForever, $resetClaims);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate the token.
|
||||
*
|
||||
* @param bool $forceForever
|
||||
*
|
||||
* @return JWT
|
||||
*/
|
||||
public function invalidate($forceForever = false)
|
||||
{
|
||||
return $this->requireToken()->invalidate($forceForever);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new token by User id.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function tokenById($id)
|
||||
{
|
||||
if ($user = $this->provider->retrieveById($id)) {
|
||||
return $this->jwt->fromUser($user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a user into the application using their credentials.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function once(array $credentials = [])
|
||||
{
|
||||
if ($this->validate($credentials)) {
|
||||
$this->setUser($this->lastAttempted);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the given User into the application.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function onceUsingId($id)
|
||||
{
|
||||
if ($user = $this->provider->retrieveById($id)) {
|
||||
$this->setUser($user);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for onceUsingId.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function byId($id)
|
||||
{
|
||||
return $this->onceUsingId($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any custom claims.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function claims(array $claims)
|
||||
{
|
||||
$this->jwt->claims($claims);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw Payload instance.
|
||||
*
|
||||
* @return Payload
|
||||
*/
|
||||
public function getPayload()
|
||||
{
|
||||
return $this->requireToken()->getPayload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for getPayload().
|
||||
*
|
||||
* @return Payload
|
||||
*/
|
||||
public function payload()
|
||||
{
|
||||
return $this->getPayload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the token.
|
||||
*
|
||||
* @param Token|string $token
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setToken($token)
|
||||
{
|
||||
$this->jwt->setToken($token);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token ttl.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getTTL()
|
||||
{
|
||||
return $this->jwt->factory()->getTTL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the token ttl.
|
||||
*
|
||||
* @param int|null $ttl
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTTL($ttl)
|
||||
{
|
||||
$this->jwt->factory()->setTTL($ttl);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user provider used by the guard.
|
||||
*
|
||||
* @return UserProvider
|
||||
*/
|
||||
public function getProvider()
|
||||
{
|
||||
return $this->provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user provider used by the guard.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setProvider(UserProvider $provider)
|
||||
{
|
||||
$this->provider = $provider;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the currently cached user.
|
||||
*
|
||||
* @return Authenticatable|null
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current user.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUser(Authenticatable $user)
|
||||
{
|
||||
$result = $this->guardHelperSetUser($user);
|
||||
|
||||
$this->fireAuthenticatedEvent($user);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current request instance.
|
||||
*
|
||||
* @return Request
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request ?: Request::createFromGlobals();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current request instance.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRequest(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last user we attempted to authenticate.
|
||||
*
|
||||
* @return Authenticatable
|
||||
*/
|
||||
public function getLastAttempted()
|
||||
{
|
||||
return $this->lastAttempted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user matches the credentials.
|
||||
*
|
||||
* @param array $credentials
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasValidCredentials($user, $credentials)
|
||||
{
|
||||
$validated = null !== $user && $this->provider->validateCredentials($user, $credentials);
|
||||
|
||||
if ($validated) {
|
||||
$this->fireValidatedEvent($user);
|
||||
}
|
||||
|
||||
return $validated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the JWTSubject matches what is in the token.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function validateSubject()
|
||||
{
|
||||
// If the provider doesn't have the necessary method
|
||||
// to get the underlying model name then allow.
|
||||
if (!method_exists($this->provider, 'getModel')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->jwt->checkSubjectModel($this->provider->getModel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a token is available in the request.
|
||||
*
|
||||
* @return JWT
|
||||
*
|
||||
* @throws JWTException
|
||||
*/
|
||||
protected function requireToken()
|
||||
{
|
||||
if (!$this->jwt->setRequest($this->getRequest())->getToken()) {
|
||||
throw new JWTException('Token could not be parsed from the request.');
|
||||
}
|
||||
|
||||
return $this->jwt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire the attempt event.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function fireAttemptEvent(array $credentials)
|
||||
{
|
||||
$this->events->dispatch(new Attempting(
|
||||
$this->name,
|
||||
$credentials,
|
||||
false
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires the validated event.
|
||||
*
|
||||
* @param Authenticatable $user
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function fireValidatedEvent($user)
|
||||
{
|
||||
if (class_exists('Illuminate\Auth\Events\Validated')) {
|
||||
$this->events->dispatch(
|
||||
new \Illuminate\Auth\Events\Validated(
|
||||
$this->name,
|
||||
$user
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire the failed authentication attempt event.
|
||||
*
|
||||
* @param Authenticatable|null $user
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function fireFailedEvent($user, array $credentials)
|
||||
{
|
||||
$this->events->dispatch(new Failed(
|
||||
$this->name,
|
||||
$user,
|
||||
$credentials
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire the authenticated event.
|
||||
*
|
||||
* @param Authenticatable $user
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function fireAuthenticatedEvent($user)
|
||||
{
|
||||
$this->events->dispatch(new Authenticated(
|
||||
$this->name,
|
||||
$user
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire the login event.
|
||||
*
|
||||
* @param Authenticatable $user
|
||||
* @param bool $remember
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function fireLoginEvent($user, $remember = false)
|
||||
{
|
||||
$this->events->dispatch(new Login(
|
||||
$this->name,
|
||||
$user,
|
||||
$remember
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire the logout event.
|
||||
*
|
||||
* @param Authenticatable $user
|
||||
* @param bool $remember
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function fireLogoutEvent($user, $remember = false)
|
||||
{
|
||||
$this->events->dispatch(new Logout(
|
||||
$this->name,
|
||||
$user
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Magically call the JWT instance.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
if (method_exists($this->jwt, $method)) {
|
||||
return call_user_func_array([$this->jwt, $method], $parameters);
|
||||
}
|
||||
|
||||
if (static::hasMacro($method)) {
|
||||
return $this->macroCall($method, $parameters);
|
||||
}
|
||||
|
||||
throw new \BadMethodCallException("Method [$method] does not exist.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Providers\JWT as JWTContract;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\JWTException;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\TokenBlacklistedException;
|
||||
use PHPOpenSourceSaver\JWTAuth\Support\CustomClaims;
|
||||
use PHPOpenSourceSaver\JWTAuth\Support\RefreshFlow;
|
||||
use PHPOpenSourceSaver\JWTAuth\Support\Utils;
|
||||
|
||||
class Manager
|
||||
{
|
||||
use CustomClaims;
|
||||
use RefreshFlow;
|
||||
|
||||
/**
|
||||
* The provider.
|
||||
*
|
||||
* @var JWTContract
|
||||
*/
|
||||
protected $provider;
|
||||
|
||||
/**
|
||||
* The blacklist.
|
||||
*
|
||||
* @var Blacklist
|
||||
*/
|
||||
protected $blacklist;
|
||||
|
||||
/**
|
||||
* the payload factory.
|
||||
*
|
||||
* @var Factory
|
||||
*/
|
||||
protected $payloadFactory;
|
||||
|
||||
/**
|
||||
* The blacklist flag.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $blacklistEnabled = true;
|
||||
|
||||
/**
|
||||
* The refresh iat flag.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $refreshIat = false;
|
||||
|
||||
/**
|
||||
* the persistent claims.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $persistentClaims = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $showBlackListException = true;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(JWTContract $provider, Blacklist $blacklist, Factory $payloadFactory)
|
||||
{
|
||||
$this->provider = $provider;
|
||||
$this->blacklist = $blacklist;
|
||||
$this->payloadFactory = $payloadFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a Payload and return the Token.
|
||||
*
|
||||
* @return Token
|
||||
*/
|
||||
public function encode(Payload $payload)
|
||||
{
|
||||
$token = $this->provider->encode($payload->get());
|
||||
|
||||
return new Token($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a Token and return the Payload.
|
||||
*
|
||||
* @param bool $checkBlacklist
|
||||
*
|
||||
* @return Payload
|
||||
*
|
||||
* @throws TokenBlacklistedException
|
||||
*/
|
||||
public function decode(Token $token, $checkBlacklist = true)
|
||||
{
|
||||
$payloadArray = $this->provider->decode($token->get());
|
||||
|
||||
$payload = $this->payloadFactory
|
||||
->setRefreshFlow($this->refreshFlow)
|
||||
->customClaims($payloadArray)
|
||||
->make();
|
||||
|
||||
if (
|
||||
$checkBlacklist
|
||||
&& $this->blacklistEnabled
|
||||
&& $this->getBlackListExceptionEnabled()
|
||||
&& $this->blacklist->has($payload)
|
||||
) {
|
||||
throw new TokenBlacklistedException('The token has been blacklisted');
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh a Token and return a new Token.
|
||||
*
|
||||
* @param bool $forceForever
|
||||
* @param bool $resetClaims
|
||||
*
|
||||
* @return Token
|
||||
*/
|
||||
public function refresh(Token $token, $forceForever = false, $resetClaims = false)
|
||||
{
|
||||
$this->setRefreshFlow();
|
||||
|
||||
$claims = $this->buildRefreshClaims($this->decode($token));
|
||||
|
||||
if ($this->blacklistEnabled) {
|
||||
// Invalidate old token
|
||||
$this->invalidate($token, $forceForever);
|
||||
}
|
||||
|
||||
// Return the new token
|
||||
return $this->encode(
|
||||
$this->payloadFactory->customClaims($claims)->make($resetClaims)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate a Token by adding it to the blacklist.
|
||||
*
|
||||
* @param bool $forceForever
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws JWTException
|
||||
*/
|
||||
public function invalidate(Token $token, $forceForever = false)
|
||||
{
|
||||
if (!$this->blacklistEnabled) {
|
||||
throw new JWTException('You must have the blacklist enabled to invalidate a token.');
|
||||
}
|
||||
|
||||
return call_user_func(
|
||||
[$this->blacklist, $forceForever ? 'addForever' : 'add'],
|
||||
$this->decode($token, false)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the claims to go into the refreshed token.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function buildRefreshClaims(Payload $payload)
|
||||
{
|
||||
// Get the claims to be persisted from the payload
|
||||
$persistentClaims = collect($payload->toArray())
|
||||
->only($this->persistentClaims)
|
||||
->toArray();
|
||||
|
||||
// persist the relevant claims
|
||||
return array_merge(
|
||||
$this->customClaims,
|
||||
$persistentClaims,
|
||||
[
|
||||
'sub' => $payload['sub'],
|
||||
'iat' => $this->refreshIat ? Utils::now()->timestamp : $payload['iat'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Payload Factory instance.
|
||||
*
|
||||
* @return Factory
|
||||
*/
|
||||
public function getPayloadFactory()
|
||||
{
|
||||
return $this->payloadFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JWTProvider instance.
|
||||
*
|
||||
* @return JWTContract
|
||||
*/
|
||||
public function getJWTProvider()
|
||||
{
|
||||
return $this->provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Blacklist instance.
|
||||
*
|
||||
* @return Blacklist
|
||||
*/
|
||||
public function getBlacklist()
|
||||
{
|
||||
return $this->blacklist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the blacklist is enabled.
|
||||
*
|
||||
* @param bool $enabled
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBlacklistEnabled($enabled)
|
||||
{
|
||||
$this->blacklistEnabled = $enabled;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration to set up if show the TokenBlacklistedException
|
||||
* can be throwable or not.
|
||||
*
|
||||
* @param bool $showBlackListException
|
||||
*
|
||||
* @removed this
|
||||
*/
|
||||
public function setBlackListExceptionEnabled($showBlackListException = true)
|
||||
{
|
||||
$this->showBlackListException = $showBlackListException;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if the blacklist instance is enabled.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getBlackListExceptionEnabled()
|
||||
{
|
||||
return $this->showBlackListException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the claims to be persisted when refreshing a token.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPersistentClaims(array $claims)
|
||||
{
|
||||
$this->persistentClaims = $claims;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the refresh iat is enabled.
|
||||
*
|
||||
* @param bool $enabled
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRefreshIat($refreshIat)
|
||||
{
|
||||
$this->refreshIat = $refreshIat;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth;
|
||||
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Contracts\Support\Jsonable;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use PHPOpenSourceSaver\JWTAuth\Claims\Claim;
|
||||
use PHPOpenSourceSaver\JWTAuth\Claims\Collection;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\PayloadException;
|
||||
use PHPOpenSourceSaver\JWTAuth\Validators\PayloadValidator;
|
||||
|
||||
class Payload implements \ArrayAccess, Arrayable, \Countable, Jsonable, \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* The collection of claims.
|
||||
*
|
||||
* @var Collection
|
||||
*/
|
||||
private $claims;
|
||||
|
||||
/**
|
||||
* Build the Payload.
|
||||
*
|
||||
* @param bool $refreshFlow
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Collection $claims, PayloadValidator $validator, $refreshFlow = false)
|
||||
{
|
||||
$this->claims = $validator->setRefreshFlow($refreshFlow)->check($claims);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array of claim instances.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getClaims()
|
||||
{
|
||||
return $this->claims;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a payload matches some expected values.
|
||||
*
|
||||
* @param bool $strict
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function matches(array $values, $strict = false)
|
||||
{
|
||||
if (empty($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$claims = $this->getClaims();
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
if (!$claims->has($key) || !$claims->get($key)->matches($value, $strict)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a payload strictly matches some expected values.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function matchesStrict(array $values)
|
||||
{
|
||||
return $this->matches($values, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the payload.
|
||||
*/
|
||||
public function get($claim = null)
|
||||
{
|
||||
$claim = value($claim);
|
||||
|
||||
if (null !== $claim) {
|
||||
if (is_array($claim)) {
|
||||
return array_map([$this, 'get'], $claim);
|
||||
}
|
||||
|
||||
return Arr::get($this->toArray(), $claim);
|
||||
}
|
||||
|
||||
return $this->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying Claim instance.
|
||||
*
|
||||
* @param string $claim
|
||||
*
|
||||
* @return Claim
|
||||
*/
|
||||
public function getInternal($claim)
|
||||
{
|
||||
return $this->claims->getByClaimName($claim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the payload has the claim (by instance).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has(Claim $claim)
|
||||
{
|
||||
return $this->claims->has($claim->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the payload has the claim (by key).
|
||||
*
|
||||
* @param string $claim
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasKey($claim)
|
||||
{
|
||||
return $this->offsetExists($claim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array of claims.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->claims->toPlainArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the object into something JSON serializable.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the payload as JSON.
|
||||
*
|
||||
* @param int $options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toJson($options = JSON_UNESCAPED_SLASHES)
|
||||
{
|
||||
return json_encode($this->toArray(), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the payload as a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->toJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an item exists at an offset.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetExists($key)
|
||||
{
|
||||
return Arr::has($this->toArray(), $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item at a given offset.
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetGet($key)
|
||||
{
|
||||
return Arr::get($this->toArray(), $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't allow changing the payload as it should be immutable.
|
||||
*
|
||||
* @throws PayloadException
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
throw new PayloadException('The payload is immutable');
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't allow changing the payload as it should be immutable.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws PayloadException
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetUnset($key)
|
||||
{
|
||||
throw new PayloadException('The payload is immutable');
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of claims.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function count()
|
||||
{
|
||||
return count($this->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the Payload as a callable function.
|
||||
*/
|
||||
public function __invoke($claim = null)
|
||||
{
|
||||
return $this->get($claim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magically get a claim value.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
if (preg_match('/get(.+)\b/i', $method, $matches)) {
|
||||
foreach ($this->claims as $claim) {
|
||||
if (get_class($claim) === 'PHPOpenSourceSaver\\JWTAuth\\Claims\\'.$matches[1]) {
|
||||
return $claim->getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new \BadMethodCallException(sprintf('The claim [%s] does not exist on the payload.', Str::after($method, 'get')));
|
||||
}
|
||||
}
|
||||
+355
@@ -0,0 +1,355 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Providers;
|
||||
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Namshi\JOSE\JWS;
|
||||
use PHPOpenSourceSaver\JWTAuth\Blacklist;
|
||||
use PHPOpenSourceSaver\JWTAuth\Claims\Factory as ClaimFactory;
|
||||
use PHPOpenSourceSaver\JWTAuth\Console\JWTGenerateCertCommand;
|
||||
use PHPOpenSourceSaver\JWTAuth\Console\JWTGenerateSecretCommand;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Providers\Auth;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Providers\JWT as JWTContract;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Providers\Storage;
|
||||
use PHPOpenSourceSaver\JWTAuth\Factory;
|
||||
use PHPOpenSourceSaver\JWTAuth\Http\Middleware\Authenticate;
|
||||
use PHPOpenSourceSaver\JWTAuth\Http\Middleware\AuthenticateAndRenew;
|
||||
use PHPOpenSourceSaver\JWTAuth\Http\Middleware\Check;
|
||||
use PHPOpenSourceSaver\JWTAuth\Http\Middleware\RefreshToken;
|
||||
use PHPOpenSourceSaver\JWTAuth\Http\Parser\AuthHeaders;
|
||||
use PHPOpenSourceSaver\JWTAuth\Http\Parser\InputSource;
|
||||
use PHPOpenSourceSaver\JWTAuth\Http\Parser\Parser;
|
||||
use PHPOpenSourceSaver\JWTAuth\Http\Parser\QueryString;
|
||||
use PHPOpenSourceSaver\JWTAuth\JWT;
|
||||
use PHPOpenSourceSaver\JWTAuth\JWTAuth;
|
||||
use PHPOpenSourceSaver\JWTAuth\JWTGuard;
|
||||
use PHPOpenSourceSaver\JWTAuth\Manager;
|
||||
use PHPOpenSourceSaver\JWTAuth\Providers\JWT\Lcobucci;
|
||||
use PHPOpenSourceSaver\JWTAuth\Providers\JWT\Namshi;
|
||||
use PHPOpenSourceSaver\JWTAuth\Validators\PayloadValidator;
|
||||
|
||||
abstract class AbstractServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* The middleware aliases.
|
||||
*/
|
||||
protected array $middlewareAliases = [
|
||||
'jwt.auth' => Authenticate::class,
|
||||
'jwt.check' => Check::class,
|
||||
'jwt.refresh' => RefreshToken::class,
|
||||
'jwt.renew' => AuthenticateAndRenew::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Boot the service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract public function boot();
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->registerAliases();
|
||||
|
||||
$this->registerJWTProvider();
|
||||
$this->registerAuthProvider();
|
||||
$this->registerStorageProvider();
|
||||
$this->registerJWTBlacklist();
|
||||
|
||||
$this->registerManager();
|
||||
$this->registerTokenParser();
|
||||
|
||||
$this->registerJWT();
|
||||
$this->registerJWTAuth();
|
||||
$this->registerPayloadValidator();
|
||||
$this->registerClaimFactory();
|
||||
$this->registerPayloadFactory();
|
||||
$this->registerJWTCommands();
|
||||
|
||||
$this->commands([
|
||||
'tymon.jwt.secret',
|
||||
'tymon.jwt.cert',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend Laravel's Auth.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function extendAuthGuard()
|
||||
{
|
||||
$this->app['auth']->extend('jwt', function ($app, $name, array $config) {
|
||||
$guard = new JWTGuard(
|
||||
$app['tymon.jwt'],
|
||||
$app['auth']->createUserProvider($config['provider']),
|
||||
$app['request'],
|
||||
$app['events']
|
||||
);
|
||||
|
||||
if (Arr::has($config, 'ttl')) {
|
||||
$guard->setTTL(Arr::get($config, 'ttl'));
|
||||
} else {
|
||||
$guard->setTTL($app->make('config')->get('jwt.ttl'));
|
||||
}
|
||||
|
||||
$app->refresh('request', $guard, 'setRequest');
|
||||
|
||||
return $guard;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind some aliases.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerAliases()
|
||||
{
|
||||
$this->app->alias('tymon.jwt', JWT::class);
|
||||
$this->app->alias('tymon.jwt.auth', JWTAuth::class);
|
||||
$this->app->alias('tymon.jwt.provider.jwt', JWTContract::class);
|
||||
$this->app->alias('tymon.jwt.provider.jwt.namshi', Namshi::class);
|
||||
$this->app->alias('tymon.jwt.provider.jwt.lcobucci', Lcobucci::class);
|
||||
$this->app->alias('tymon.jwt.provider.auth', Auth::class);
|
||||
$this->app->alias('tymon.jwt.provider.storage', Storage::class);
|
||||
$this->app->alias('tymon.jwt.manager', Manager::class);
|
||||
$this->app->alias('tymon.jwt.blacklist', Blacklist::class);
|
||||
$this->app->alias('tymon.jwt.payload.factory', Factory::class);
|
||||
$this->app->alias('tymon.jwt.validators.payload', PayloadValidator::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the bindings for the JSON Web Token provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerJWTProvider()
|
||||
{
|
||||
$this->registerNamshiProvider();
|
||||
$this->registerLcobucciProvider();
|
||||
|
||||
$this->app->singleton('tymon.jwt.provider.jwt', fn ($app) => $this->getConfigInstance($app, 'providers.jwt'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the bindings for the Namshi JWT provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerNamshiProvider()
|
||||
{
|
||||
$this->app->singleton('tymon.jwt.provider.jwt.namshi', fn ($app) => new Namshi(
|
||||
new JWS(['typ' => 'JWT', 'alg' => $app->make('config')->get('jwt.algo')]),
|
||||
$app->make('config')->get('jwt.secret'),
|
||||
$app->make('config')->get('jwt.algo'),
|
||||
$app->make('config')->get('jwt.keys')
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the bindings for the Lcobucci JWT provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerLcobucciProvider()
|
||||
{
|
||||
$this->app->singleton('tymon.jwt.provider.jwt.lcobucci', fn ($app) => new Lcobucci(
|
||||
$app->make('config')->get('jwt.secret'),
|
||||
$app->make('config')->get('jwt.algo'),
|
||||
$app->make('config')->get('jwt.keys')
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the bindings for the Auth provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerAuthProvider()
|
||||
{
|
||||
$this->app->singleton('tymon.jwt.provider.auth', fn ($app) => $this->getConfigInstance($app, 'providers.auth'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the bindings for the Storage provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerStorageProvider()
|
||||
{
|
||||
$this->app->singleton('tymon.jwt.provider.storage', fn ($app) => $this->getConfigInstance($app, 'providers.storage'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the bindings for the JWT Manager.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerManager()
|
||||
{
|
||||
$this->app->singleton('tymon.jwt.manager', function ($app) {
|
||||
$instance = new Manager(
|
||||
$app['tymon.jwt.provider.jwt'],
|
||||
$app['tymon.jwt.blacklist'],
|
||||
$app['tymon.jwt.payload.factory']
|
||||
);
|
||||
|
||||
return $instance->setBlacklistEnabled((bool) $app->make('config')->get('jwt.blacklist_enabled'))
|
||||
->setRefreshIat((bool) $app->make('config')->get('jwt.refresh_iat', false))
|
||||
->setPersistentClaims($app->make('config')->get('jwt.persistent_claims'))
|
||||
->setBlackListExceptionEnabled((bool) $app->make('config')->get('jwt.show_black_list_exception', 0));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the bindings for the Token Parser.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerTokenParser()
|
||||
{
|
||||
$this->app->singleton('tymon.jwt.parser', function ($app) {
|
||||
$parser = new Parser(
|
||||
$app['request'],
|
||||
[
|
||||
new AuthHeaders(),
|
||||
new QueryString(),
|
||||
new InputSource(),
|
||||
]
|
||||
);
|
||||
|
||||
$app->refresh('request', $parser, 'setRequest');
|
||||
|
||||
return $parser;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the bindings for the main JWT class.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerJWT()
|
||||
{
|
||||
$this->app->singleton('tymon.jwt', fn ($app) => (new JWT(
|
||||
$app['tymon.jwt.manager'],
|
||||
$app['tymon.jwt.parser']
|
||||
))->lockSubject($app->make('config')->get('jwt.lock_subject')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the bindings for the main JWTAuth class.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerJWTAuth()
|
||||
{
|
||||
$this->app->singleton('tymon.jwt.auth', fn ($app) => (new JWTAuth(
|
||||
$app['tymon.jwt.manager'],
|
||||
$app['tymon.jwt.provider.auth'],
|
||||
$app['tymon.jwt.parser']
|
||||
))->lockSubject($app->make('config')->get('jwt.lock_subject')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the bindings for the Blacklist.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerJWTBlacklist()
|
||||
{
|
||||
$this->app->singleton('tymon.jwt.blacklist', function ($app) {
|
||||
$instance = new Blacklist($app['tymon.jwt.provider.storage']);
|
||||
|
||||
return $instance->setGracePeriod($app->make('config')->get('jwt.blacklist_grace_period'))
|
||||
->setRefreshTTL($app->make('config')->get('jwt.refresh_ttl'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the bindings for the payload validator.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerPayloadValidator()
|
||||
{
|
||||
$this->app->singleton('tymon.jwt.validators.payload', fn ($app) => (new PayloadValidator())
|
||||
->setRefreshTTL($app->make('config')->get('jwt.refresh_ttl'))
|
||||
->setRequiredClaims($app->make('config')->get('jwt.required_claims')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the bindings for the Claim Factory.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerClaimFactory()
|
||||
{
|
||||
$this->app->singleton('tymon.jwt.claim.factory', function ($app) {
|
||||
$factory = new ClaimFactory($app['request']);
|
||||
$app->refresh('request', $factory, 'setRequest');
|
||||
|
||||
return $factory->setTTL($app->make('config')->get('jwt.ttl'))
|
||||
->setLeeway($app->make('config')->get('jwt.leeway'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the bindings for the Payload Factory.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerPayloadFactory()
|
||||
{
|
||||
$this->app->singleton('tymon.jwt.payload.factory', fn ($app) => new Factory(
|
||||
$app['tymon.jwt.claim.factory'],
|
||||
$app['tymon.jwt.validators.payload']
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the Artisan command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerJWTCommands()
|
||||
{
|
||||
$this->app->singleton('tymon.jwt.secret', fn () => new JWTGenerateSecretCommand());
|
||||
$this->app->singleton('tymon.jwt.cert', fn () => new JWTGenerateCertCommand());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instantiable configuration instance.
|
||||
*
|
||||
* @param Application $app
|
||||
* @param string $key
|
||||
*/
|
||||
protected function getConfigInstance($app, $key)
|
||||
{
|
||||
$instance = $app->make('config')->get('jwt.'.$key);
|
||||
|
||||
if (is_string($instance)) {
|
||||
return $this->app->make($instance);
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Providers\Auth;
|
||||
|
||||
use Illuminate\Contracts\Auth\Guard as GuardContract;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Providers\Auth;
|
||||
|
||||
class Illuminate implements Auth
|
||||
{
|
||||
/**
|
||||
* The authentication guard.
|
||||
*
|
||||
* @var GuardContract
|
||||
*/
|
||||
protected $auth;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(GuardContract $auth)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a user's credentials.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function byCredentials(array $credentials)
|
||||
{
|
||||
return $this->auth->once($credentials);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate a user via the id.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function byId($id)
|
||||
{
|
||||
return $this->auth->onceUsingId($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently authenticated user.
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->auth->user();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Providers\JWT;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Lcobucci\JWT\Builder;
|
||||
use Lcobucci\JWT\Configuration;
|
||||
use Lcobucci\JWT\Signer;
|
||||
use Lcobucci\JWT\Signer\Ecdsa;
|
||||
use Lcobucci\JWT\Signer\Ecdsa\Sha256 as ES256;
|
||||
use Lcobucci\JWT\Signer\Ecdsa\Sha384 as ES384;
|
||||
use Lcobucci\JWT\Signer\Ecdsa\Sha512 as ES512;
|
||||
use Lcobucci\JWT\Signer\Hmac\Sha256 as HS256;
|
||||
use Lcobucci\JWT\Signer\Hmac\Sha384 as HS384;
|
||||
use Lcobucci\JWT\Signer\Hmac\Sha512 as HS512;
|
||||
use Lcobucci\JWT\Signer\Key;
|
||||
use Lcobucci\JWT\Signer\Key\InMemory;
|
||||
use Lcobucci\JWT\Signer\Rsa;
|
||||
use Lcobucci\JWT\Signer\Rsa\Sha256 as RS256;
|
||||
use Lcobucci\JWT\Signer\Rsa\Sha384 as RS384;
|
||||
use Lcobucci\JWT\Signer\Rsa\Sha512 as RS512;
|
||||
use Lcobucci\JWT\Token\RegisteredClaims;
|
||||
use Lcobucci\JWT\Validation\Constraint\SignedWith;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Providers\JWT;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\JWTException;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\TokenInvalidException;
|
||||
|
||||
class Lcobucci extends Provider implements JWT
|
||||
{
|
||||
/**
|
||||
* The builder instance.
|
||||
*
|
||||
* @var Builder
|
||||
*/
|
||||
protected $builder;
|
||||
|
||||
/**
|
||||
* The configuration instance.
|
||||
*
|
||||
* @var Configuration
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* The Signer instance.
|
||||
*
|
||||
* @var Signer
|
||||
*/
|
||||
protected $signer;
|
||||
|
||||
/**
|
||||
* Create the Lcobucci provider.
|
||||
*
|
||||
* @param string $secret
|
||||
* @param string $algo
|
||||
* @param Configuration $config optional, to pass an existing configuration to be used
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
$secret,
|
||||
$algo,
|
||||
array $keys,
|
||||
$config = null,
|
||||
) {
|
||||
parent::__construct($secret, $algo, $keys);
|
||||
$this->generateConfig($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the config.
|
||||
*
|
||||
* @param Configuration $config optional, to pass an existing configuration to be used
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function generateConfig($config = null)
|
||||
{
|
||||
$this->signer = $this->getSigner();
|
||||
|
||||
if (!is_null($config)) {
|
||||
$this->config = $config;
|
||||
} elseif ($this->isAsymmetric()) {
|
||||
$this->config = Configuration::forAsymmetricSigner($this->signer, $this->getSigningKey(), $this->getVerificationKey());
|
||||
} else {
|
||||
$this->config = Configuration::forSymmetricSigner($this->signer, InMemory::plainText($this->getSecret()));
|
||||
}
|
||||
if (!count($this->config->validationConstraints())) {
|
||||
$this->config->setValidationConstraints(
|
||||
new SignedWith($this->signer, $this->getVerificationKey()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the secret used to sign the token and regenerate the config using the secret.
|
||||
*
|
||||
* @param string $secret
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSecret($secret)
|
||||
{
|
||||
$this->secret = $secret;
|
||||
$this->generateConfig();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@see $config} attribute.
|
||||
*
|
||||
* @return Configuration
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signers that this provider supports.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $signers = [
|
||||
'HS256' => HS256::class,
|
||||
'HS384' => HS384::class,
|
||||
'HS512' => HS512::class,
|
||||
'RS256' => RS256::class,
|
||||
'RS384' => RS384::class,
|
||||
'RS512' => RS512::class,
|
||||
'ES256' => ES256::class,
|
||||
'ES384' => ES384::class,
|
||||
'ES512' => ES512::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Create a JSON Web Token.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws JWTException
|
||||
*/
|
||||
public function encode(array $payload)
|
||||
{
|
||||
$this->builder = null;
|
||||
$this->builder = $this->config->builder();
|
||||
|
||||
try {
|
||||
foreach ($payload as $key => $value) {
|
||||
$this->builder = $this->addClaim($key, $value);
|
||||
}
|
||||
|
||||
return $this->builder->getToken($this->config->signer(), $this->config->signingKey())->toString();
|
||||
} catch (\Exception $e) {
|
||||
throw new JWTException('Could not create token: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a JSON Web Token.
|
||||
*
|
||||
* @param string $token
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws JWTException
|
||||
*/
|
||||
public function decode($token)
|
||||
{
|
||||
try {
|
||||
$jwt = $this->config->parser()->parse($token);
|
||||
} catch (\Exception $e) {
|
||||
throw new TokenInvalidException('Could not decode token: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
if (!$this->config->validator()->validate($jwt, ...$this->config->validationConstraints())) {
|
||||
throw new TokenInvalidException('Token Signature could not be verified.');
|
||||
}
|
||||
|
||||
return (new Collection($jwt->claims()->all()))->map(function ($claim) {
|
||||
if (is_a($claim, \DateTimeImmutable::class)) {
|
||||
return $claim->getTimestamp();
|
||||
}
|
||||
if (is_object($claim) && method_exists($claim, 'getValue')) {
|
||||
return $claim->getValue();
|
||||
}
|
||||
|
||||
return $claim;
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a claim to the {@see $config}.
|
||||
*
|
||||
* @param string $key
|
||||
*/
|
||||
protected function addClaim($key, $value): Builder
|
||||
{
|
||||
if (!isset($this->builder)) {
|
||||
$this->builder = $this->config->builder();
|
||||
}
|
||||
|
||||
return match ($key) {
|
||||
RegisteredClaims::ID => $this->builder->identifiedBy($value),
|
||||
RegisteredClaims::EXPIRATION_TIME => $this->builder->expiresAt(\DateTimeImmutable::createFromFormat('U', $value)),
|
||||
RegisteredClaims::NOT_BEFORE => $this->builder->canOnlyBeUsedAfter(\DateTimeImmutable::createFromFormat('U', $value)),
|
||||
RegisteredClaims::ISSUED_AT => $this->builder->issuedAt(\DateTimeImmutable::createFromFormat('U', $value)),
|
||||
RegisteredClaims::ISSUER => $this->builder->issuedBy($value),
|
||||
RegisteredClaims::AUDIENCE => is_array($value) ? $this->builder->permittedFor(...$value) : $this->builder->permittedFor($value),
|
||||
RegisteredClaims::SUBJECT => $this->builder->relatedTo($value),
|
||||
default => $this->builder->withClaim($key, $value),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the signer instance.
|
||||
*
|
||||
* @return Signer
|
||||
*
|
||||
* @throws JWTException
|
||||
*/
|
||||
protected function getSigner()
|
||||
{
|
||||
if (!array_key_exists($this->algo, $this->signers)) {
|
||||
throw new JWTException('The given algorithm could not be found');
|
||||
}
|
||||
|
||||
$signer = $this->signers[$this->algo];
|
||||
|
||||
return new $signer();
|
||||
}
|
||||
|
||||
protected function isAsymmetric()
|
||||
{
|
||||
$reflect = new \ReflectionClass($this->signer);
|
||||
|
||||
return $reflect->isSubclassOf(Rsa::class) || $reflect->isSubclassOf(Ecdsa::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key used to sign the tokens.
|
||||
*
|
||||
* @return Key|string
|
||||
*/
|
||||
protected function getSigningKey()
|
||||
{
|
||||
return $this->isAsymmetric() ?
|
||||
InMemory::plainText($this->getPrivateKey(), $this->getPassphrase() ?? '') :
|
||||
InMemory::plainText($this->getSecret());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key used to verify the tokens.
|
||||
*
|
||||
* @return Key|string
|
||||
*/
|
||||
protected function getVerificationKey()
|
||||
{
|
||||
return $this->isAsymmetric() ?
|
||||
InMemory::plainText($this->getPublicKey()) :
|
||||
InMemory::plainText($this->getSecret());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Providers\JWT;
|
||||
|
||||
use Namshi\JOSE\JWS;
|
||||
use Namshi\JOSE\Signer\OpenSSL\PublicKey;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Providers\JWT;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\JWTException;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\TokenInvalidException;
|
||||
|
||||
class Namshi extends Provider implements JWT
|
||||
{
|
||||
/**
|
||||
* The JWS.
|
||||
*
|
||||
* @var JWS
|
||||
*/
|
||||
protected $jws;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $secret
|
||||
* @param string $algo
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(JWS $jws, $secret, $algo, array $keys)
|
||||
{
|
||||
parent::__construct($secret, $algo, $keys);
|
||||
|
||||
$this->jws = $jws;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JSON Web Token.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws JWTException
|
||||
*/
|
||||
public function encode(array $payload)
|
||||
{
|
||||
try {
|
||||
$this->jws->setPayload($payload)->sign($this->getSigningKey(), $this->getPassphrase());
|
||||
|
||||
return (string) $this->jws->getTokenString();
|
||||
} catch (\Exception $e) {
|
||||
throw new JWTException('Could not create token: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a JSON Web Token.
|
||||
*
|
||||
* @param string $token
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws JWTException
|
||||
*/
|
||||
public function decode($token)
|
||||
{
|
||||
try {
|
||||
// Let's never allow insecure tokens
|
||||
$jws = $this->jws->load($token, false);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new TokenInvalidException('Could not decode token: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
if (!$jws->verify($this->getVerificationKey(), $this->getAlgo())) {
|
||||
throw new TokenInvalidException('Token Signature could not be verified.');
|
||||
}
|
||||
|
||||
return (array) $jws->getPayload();
|
||||
}
|
||||
|
||||
protected function isAsymmetric()
|
||||
{
|
||||
try {
|
||||
return (new \ReflectionClass(sprintf('Namshi\\JOSE\\Signer\\OpenSSL\\%s', $this->getAlgo())))->isSubclassOf(PublicKey::class);
|
||||
} catch (\ReflectionException $e) {
|
||||
throw new JWTException('The given algorithm could not be found', $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Providers\JWT;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\JWTException;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\SecretMissingException;
|
||||
|
||||
abstract class Provider
|
||||
{
|
||||
/**
|
||||
* The secret.
|
||||
*/
|
||||
protected ?string $secret;
|
||||
|
||||
/**
|
||||
* The array of keys.
|
||||
*/
|
||||
protected array $keys;
|
||||
|
||||
/**
|
||||
* The used algorithm.
|
||||
*/
|
||||
protected string $algo;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $secret
|
||||
* @param string $algo
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($secret, $algo, array $keys)
|
||||
{
|
||||
if (is_null($secret) && (is_null($keys['public']) || is_null($keys['private']))) {
|
||||
throw new SecretMissingException();
|
||||
}
|
||||
|
||||
$this->secret = $secret;
|
||||
$this->algo = $algo;
|
||||
$this->keys = $keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the algorithm used to sign the token.
|
||||
*
|
||||
* @param string $algo
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAlgo($algo)
|
||||
{
|
||||
$this->algo = $algo;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the algorithm used to sign the token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAlgo()
|
||||
{
|
||||
return $this->algo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the secret used to sign the token.
|
||||
*
|
||||
* @param string $secret
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSecret($secret)
|
||||
{
|
||||
$this->secret = $secret;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the secret used to sign the token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSecret()
|
||||
{
|
||||
return $this->secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the keys used to sign the token.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setKeys(array $keys)
|
||||
{
|
||||
$this->keys = $keys;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array of keys used to sign tokens
|
||||
* with an asymmetric algorithm.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getKeys()
|
||||
{
|
||||
return $this->keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the public key used to sign tokens
|
||||
* with an asymmetric algorithm.
|
||||
*
|
||||
* @return resource|string
|
||||
*/
|
||||
public function getPublicKey()
|
||||
{
|
||||
return Arr::get($this->keys, 'public');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the private key used to sign tokens
|
||||
* with an asymmetric algorithm.
|
||||
*
|
||||
* @return resource|string
|
||||
*/
|
||||
public function getPrivateKey()
|
||||
{
|
||||
return Arr::get($this->keys, 'private');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the passphrase used to sign tokens
|
||||
* with an asymmetric algorithm.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPassphrase()
|
||||
{
|
||||
return Arr::get($this->keys, 'passphrase');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key used to sign the tokens.
|
||||
*
|
||||
* @return resource|string
|
||||
*/
|
||||
protected function getSigningKey()
|
||||
{
|
||||
return $this->isAsymmetric() ? $this->getPrivateKey() : $this->getSecret();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key used to verify the tokens.
|
||||
*
|
||||
* @return resource|string
|
||||
*/
|
||||
protected function getVerificationKey()
|
||||
{
|
||||
return $this->isAsymmetric() ? $this->getPublicKey() : $this->getSecret();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the algorithm is asymmetric, and thus
|
||||
* requires a public/private key combo.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws JWTException
|
||||
*/
|
||||
abstract protected function isAsymmetric();
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Providers;
|
||||
|
||||
use Laravel\Octane\Events\RequestReceived;
|
||||
use Laravel\Octane\Events\TaskReceived;
|
||||
use Laravel\Octane\Events\TickReceived;
|
||||
use PHPOpenSourceSaver\JWTAuth\Facades\JWTAuth;
|
||||
use PHPOpenSourceSaver\JWTAuth\Facades\JWTFactory;
|
||||
use PHPOpenSourceSaver\JWTAuth\Facades\JWTProvider;
|
||||
use PHPOpenSourceSaver\JWTAuth\Http\Parser\Cookies;
|
||||
use PHPOpenSourceSaver\JWTAuth\Http\Parser\RouteParams;
|
||||
|
||||
class LaravelServiceProvider extends AbstractServiceProvider
|
||||
{
|
||||
public function boot()
|
||||
{
|
||||
$path = realpath(__DIR__.'/../../config/config.php');
|
||||
|
||||
$this->publishes([$path => $this->app->configPath('jwt.php')], 'config');
|
||||
$this->mergeConfigFrom($path, 'jwt');
|
||||
|
||||
$this->aliasMiddleware();
|
||||
|
||||
$this->extendAuthGuard();
|
||||
|
||||
$config = $this->app->make('config');
|
||||
|
||||
$this->app['tymon.jwt.parser']->addParser([
|
||||
new RouteParams(),
|
||||
(new Cookies(
|
||||
$config->get('jwt.decrypt_cookies'),
|
||||
))->setKey($config->get('jwt.cookie_key_name', 'token')),
|
||||
]);
|
||||
|
||||
if (isset($_SERVER['LARAVEL_OCTANE'])) {
|
||||
$clear = function () {
|
||||
JWTAuth::clearResolvedInstances();
|
||||
JWTFactory::clearResolvedInstances();
|
||||
JWTProvider::clearResolvedInstances();
|
||||
};
|
||||
|
||||
$this->app['events']->listen(RequestReceived::class, $clear);
|
||||
$this->app['events']->listen(TaskReceived::class, $clear);
|
||||
$this->app['events']->listen(TickReceived::class, $clear);
|
||||
}
|
||||
}
|
||||
|
||||
protected function registerStorageProvider()
|
||||
{
|
||||
$this->app->singleton('tymon.jwt.provider.storage', function ($app) {
|
||||
$instance = $this->getConfigInstance($app, 'providers.storage');
|
||||
|
||||
if (method_exists($instance, 'setLaravelVersion')) {
|
||||
$instance->setLaravelVersion($this->app->version());
|
||||
}
|
||||
|
||||
return $instance;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias the middleware.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function aliasMiddleware()
|
||||
{
|
||||
$router = $this->app['router'];
|
||||
|
||||
$method = method_exists($router, 'aliasMiddleware') ? 'aliasMiddleware' : 'middleware';
|
||||
|
||||
foreach ($this->middlewareAliases as $alias => $middleware) {
|
||||
$router->$method($alias, $middleware);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Providers;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Http\Parser\LumenRouteParams;
|
||||
|
||||
class LumenServiceProvider extends AbstractServiceProvider
|
||||
{
|
||||
public function boot()
|
||||
{
|
||||
$this->app->configure('jwt');
|
||||
|
||||
$path = realpath(__DIR__.'/../../config/config.php');
|
||||
$this->mergeConfigFrom($path, 'jwt');
|
||||
|
||||
$this->app->routeMiddleware($this->middlewareAliases);
|
||||
|
||||
$this->extendAuthGuard();
|
||||
|
||||
$this->app['tymon.jwt.parser']->addParser(new LumenRouteParams());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Providers\Storage;
|
||||
|
||||
use Illuminate\Contracts\Cache\Repository as CacheContract;
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Providers\Storage;
|
||||
use Psr\SimpleCache\CacheInterface as PsrCacheInterface;
|
||||
|
||||
class Illuminate implements Storage
|
||||
{
|
||||
/**
|
||||
* The cache repository contract.
|
||||
*
|
||||
* @var CacheContract
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* The used cache tag.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $tag = 'tymon.jwt';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $supportsTags;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $laravelVersion;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(CacheContract $cache)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new item into storage.
|
||||
*
|
||||
* @param string $key
|
||||
* @param int $minutes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($key, $value, $minutes)
|
||||
{
|
||||
// If the laravel version is 5.8 or higher then convert minutes to seconds.
|
||||
if (null !== $this->laravelVersion
|
||||
&& is_int($minutes)
|
||||
&& version_compare($this->laravelVersion, '5.8', '>=')
|
||||
) {
|
||||
$minutes = $minutes * 60;
|
||||
}
|
||||
|
||||
$this->cache()->put($key, $value, $minutes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new item into storage forever.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function forever($key, $value)
|
||||
{
|
||||
$this->cache()->forever($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item from storage.
|
||||
*
|
||||
* @param string $key
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
return $this->cache()->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from storage.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy($key)
|
||||
{
|
||||
return $this->cache()->forget($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items associated with the tag.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function flush()
|
||||
{
|
||||
$this->cache()->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache instance with tags attached.
|
||||
*
|
||||
* @return CacheContract
|
||||
*/
|
||||
protected function cache()
|
||||
{
|
||||
if (null === $this->supportsTags) {
|
||||
$this->determineTagSupport();
|
||||
}
|
||||
|
||||
if ($this->supportsTags) {
|
||||
return $this->cache->tags($this->tag);
|
||||
}
|
||||
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the laravel version.
|
||||
*/
|
||||
public function setLaravelVersion($version)
|
||||
{
|
||||
$this->laravelVersion = $version;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect as best we can whether tags are supported with this repository & store,
|
||||
* and save our result on the $supportsTags flag.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function determineTagSupport()
|
||||
{
|
||||
// Laravel >= 5.1.28
|
||||
if (method_exists($this->cache, 'tags') || $this->cache instanceof PsrCacheInterface) {
|
||||
try {
|
||||
// Attempt the repository tags command, which throws exceptions when unsupported
|
||||
$this->cache->tags($this->tag);
|
||||
$this->supportsTags = true;
|
||||
} catch (\BadMethodCallException $ex) {
|
||||
$this->supportsTags = false;
|
||||
}
|
||||
} else {
|
||||
// Laravel <= 5.1.27
|
||||
if (method_exists($this->cache, 'getStore')) {
|
||||
// Check for the tags function directly on the store
|
||||
$this->supportsTags = method_exists($this->cache->getStore(), 'tags');
|
||||
} else {
|
||||
// Must be using custom cache repository without getStore(), and all bets are off,
|
||||
// or we are mocking the cache contract (in testing), which will not create a getStore method
|
||||
$this->supportsTags = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Support;
|
||||
|
||||
trait CustomClaims
|
||||
{
|
||||
/**
|
||||
* Custom claims.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $customClaims = [];
|
||||
|
||||
/**
|
||||
* Set the custom claims.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function customClaims(array $customClaims)
|
||||
{
|
||||
$this->customClaims = $customClaims;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias to set the custom claims.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function claims(array $customClaims)
|
||||
{
|
||||
return $this->customClaims($customClaims);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the custom claims.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCustomClaims()
|
||||
{
|
||||
return $this->customClaims;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Support;
|
||||
|
||||
trait RefreshFlow
|
||||
{
|
||||
/**
|
||||
* The refresh flow flag.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $refreshFlow = false;
|
||||
|
||||
/**
|
||||
* Set the refresh flow flag.
|
||||
*
|
||||
* @param bool $refreshFlow
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRefreshFlow($refreshFlow = true)
|
||||
{
|
||||
$this->refreshFlow = $refreshFlow;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Support;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
class Utils
|
||||
{
|
||||
/**
|
||||
* Get the Carbon instance for the current time.
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
public static function now()
|
||||
{
|
||||
return Carbon::now('UTC');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Carbon instance for the timestamp.
|
||||
*
|
||||
* @param int $timestamp
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
public static function timestamp($timestamp)
|
||||
{
|
||||
return Carbon::createFromTimestampUTC($timestamp)->timezone('UTC');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a timestamp is in the past.
|
||||
*
|
||||
* @param int $timestamp
|
||||
* @param int $leeway
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isPast($timestamp, $leeway = 0)
|
||||
{
|
||||
$timestamp = static::timestamp($timestamp);
|
||||
|
||||
return $leeway > 0
|
||||
? $timestamp->addSeconds($leeway)->isPast()
|
||||
: $timestamp->isPast();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a timestamp is in the future.
|
||||
*
|
||||
* @param int $timestamp
|
||||
* @param int $leeway
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isFuture($timestamp, $leeway = 0)
|
||||
{
|
||||
$timestamp = static::timestamp($timestamp);
|
||||
|
||||
return $leeway > 0
|
||||
? $timestamp->subSeconds($leeway)->isFuture()
|
||||
: $timestamp->isFuture();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Validators\TokenValidator;
|
||||
|
||||
class Token
|
||||
{
|
||||
private string $value;
|
||||
|
||||
/**
|
||||
* Create a new JSON Web Token.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws Exceptions\TokenInvalidException
|
||||
*/
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->value = (string) (new TokenValidator())->check($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token when casting to string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Validators;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Claims\Collection;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\TokenInvalidException;
|
||||
|
||||
class PayloadValidator extends Validator
|
||||
{
|
||||
/**
|
||||
* The required claims.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $requiredClaims = [
|
||||
'iss',
|
||||
'iat',
|
||||
'exp',
|
||||
'nbf',
|
||||
'sub',
|
||||
'jti',
|
||||
];
|
||||
|
||||
/**
|
||||
* The refresh TTL.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $refreshTTL = 20160;
|
||||
|
||||
/**
|
||||
* Run the validations on the payload array.
|
||||
*
|
||||
* @param Collection $value
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function check($value)
|
||||
{
|
||||
$this->validateStructure($value);
|
||||
|
||||
return $this->refreshFlow ? $this->validateRefresh($value) : $this->validatePayload($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the payload contains the required claims and
|
||||
* the claims have the relevant type.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws TokenInvalidException
|
||||
*/
|
||||
protected function validateStructure(Collection $claims)
|
||||
{
|
||||
if ($this->requiredClaims && !$claims->hasAllClaims($this->requiredClaims)) {
|
||||
throw new TokenInvalidException('JWT payload does not contain the required claims');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the payload timestamps.
|
||||
*
|
||||
* @return Collection
|
||||
*
|
||||
* @throws TokenInvalidException
|
||||
* @throws \PHPOpenSourceSaver\JWTAuth\Exceptions\TokenExpiredException
|
||||
*/
|
||||
protected function validatePayload(Collection $claims)
|
||||
{
|
||||
return $claims->validate('payload');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the token in the refresh flow context.
|
||||
*
|
||||
* @return Collection
|
||||
*
|
||||
* @throws \PHPOpenSourceSaver\JWTAuth\Exceptions\TokenExpiredException
|
||||
*/
|
||||
protected function validateRefresh(Collection $claims)
|
||||
{
|
||||
return null === $this->refreshTTL ? $claims : $claims->validate('refresh', $this->refreshTTL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the required claims.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRequiredClaims(array $claims)
|
||||
{
|
||||
$this->requiredClaims = $claims;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the refresh ttl.
|
||||
*
|
||||
* @param int $ttl
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRefreshTTL($ttl)
|
||||
{
|
||||
$this->refreshTTL = $ttl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Validators;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\TokenInvalidException;
|
||||
|
||||
class TokenValidator extends Validator
|
||||
{
|
||||
/**
|
||||
* Check the structure of the token.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws TokenInvalidException
|
||||
*/
|
||||
public function check($value)
|
||||
{
|
||||
return $this->validateStructure($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $token
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws TokenInvalidException
|
||||
*/
|
||||
protected function validateStructure($token)
|
||||
{
|
||||
$parts = explode('.', $token);
|
||||
|
||||
if (3 !== count($parts)) {
|
||||
throw new TokenInvalidException('Wrong number of segments');
|
||||
}
|
||||
|
||||
$parts = array_filter(array_map('trim', $parts));
|
||||
|
||||
if (3 !== count($parts) || implode('.', $parts) !== $token) {
|
||||
throw new TokenInvalidException('Malformed token');
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) 2014-2021 Sean Tymon <tymon148@gmail.com>
|
||||
* (c) 2021 PHP Open Source Saver
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace PHPOpenSourceSaver\JWTAuth\Validators;
|
||||
|
||||
use PHPOpenSourceSaver\JWTAuth\Contracts\Validator as ValidatorContract;
|
||||
use PHPOpenSourceSaver\JWTAuth\Exceptions\JWTException;
|
||||
use PHPOpenSourceSaver\JWTAuth\Support\RefreshFlow;
|
||||
|
||||
abstract class Validator implements ValidatorContract
|
||||
{
|
||||
use RefreshFlow;
|
||||
|
||||
/**
|
||||
* Helper function to return a boolean.
|
||||
*
|
||||
* @param array $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($value)
|
||||
{
|
||||
try {
|
||||
$this->check($value);
|
||||
} catch (JWTException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the validation.
|
||||
*
|
||||
* @param array $value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract public function check($value);
|
||||
}
|
||||
Reference in New Issue
Block a user