From 1c8c9e2061b1c2cfbbd7402b59eeeebbb8f92518 Mon Sep 17 00:00:00 2001 From: giannidhooge Date: Mon, 14 Sep 2020 15:54:37 +0200 Subject: [PATCH 001/525] support Laravel 8 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index bf5a2954..d4fcfa0a 100644 --- a/composer.json +++ b/composer.json @@ -6,8 +6,8 @@ "require": { "php": "^7.1", "auth0/auth0-php": "^7.2.0", - "illuminate/support": "5.* | ^6.0 | ^7.0", - "illuminate/contracts": "5.* | ^6.0 | ^7.0" + "illuminate/support": "5.* | ^6.0 | ^7.0 | ^8.0", + "illuminate/contracts": "5.* | ^6.0 | ^7.0 | ^8.0" }, "require-dev": { "phpunit/phpunit": "^7|^8|^9", From 4fdfd7a7677589648131cf9800249dcabee50d41 Mon Sep 17 00:00:00 2001 From: James Anderson Date: Thu, 17 Sep 2020 14:57:24 -0500 Subject: [PATCH 002/525] fix comnposer.json whitespace issue --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index d4fcfa0a..60ae9043 100644 --- a/composer.json +++ b/composer.json @@ -6,8 +6,8 @@ "require": { "php": "^7.1", "auth0/auth0-php": "^7.2.0", - "illuminate/support": "5.* | ^6.0 | ^7.0 | ^8.0", - "illuminate/contracts": "5.* | ^6.0 | ^7.0 | ^8.0" + "illuminate/support": "5.* | ^6.0 | ^7.0 | ^8.0", + "illuminate/contracts": "5.* | ^6.0 | ^7.0 | ^8.0" }, "require-dev": { "phpunit/phpunit": "^7|^8|^9", From 05c194b869f11693d0591fe05648a47e2a09540c Mon Sep 17 00:00:00 2001 From: James Anderson Date: Thu, 17 Sep 2020 15:36:04 -0500 Subject: [PATCH 003/525] Release 6.1.0 --- CHANGELOG.md | 9 +++++++++ src/Auth0/Login/LoginServiceProvider.php | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebce6c7a..97e68f32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Change Log +## [6.1.0](https://github.com/auth0/laravel-auth0/tree/6.1.0) (2020-09-17) +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.0.1...6.1.0) + +**Added** +- Support Laravel 8 [\#190](https://github.com/auth0/laravel-auth0/pull/190) ([giannidhooge](hhttps://github.com/giannidhooge)) + +**Fixed** +- Fix composer.json whitespace issue [\#192](https://github.com/auth0/laravel-auth0/pull/192) ([jimmyjames](https://github.com/jimmyjames)) + ## [6.0.1](https://github.com/auth0/laravel-auth0/tree/6.0.1) (2020-04-28) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.0.0...6.0.1) diff --git a/src/Auth0/Login/LoginServiceProvider.php b/src/Auth0/Login/LoginServiceProvider.php index b5d1d293..67ec7a08 100644 --- a/src/Auth0/Login/LoginServiceProvider.php +++ b/src/Auth0/Login/LoginServiceProvider.php @@ -14,7 +14,7 @@ class LoginServiceProvider extends ServiceProvider { - const SDK_VERSION = "6.0.1"; + const SDK_VERSION = "6.1.0"; /** * Bootstrap the application events. From 9c3125be79d669d6c4699cd2f336474404bbd57b Mon Sep 17 00:00:00 2001 From: lbalmaceda Date: Tue, 27 Oct 2020 08:43:23 -0300 Subject: [PATCH 004/525] Setup the CODEOWNERS for pull request reviews --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c9ff4921..60f116c0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @auth0/dx-sdks-approver +* @auth0/dx-sdks-engineer From bcae41c06708ddca3f402acde7fc3af64cae498a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 27 Oct 2020 09:51:34 -0400 Subject: [PATCH 005/525] SDK-2102 Fix Composer V2 installation errors --- composer.json | 90 +++++++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/composer.json b/composer.json index 60ae9043..94d8a20e 100644 --- a/composer.json +++ b/composer.json @@ -1,48 +1,48 @@ { - "name": "auth0/login", - "description": "Laravel plugin that helps authenticate with the auth0 service", - "license": "MIT", - "prefer-stable": true, - "require": { - "php": "^7.1", - "auth0/auth0-php": "^7.2.0", - "illuminate/support": "5.* | ^6.0 | ^7.0 | ^8.0", - "illuminate/contracts": "5.* | ^6.0 | ^7.0 | ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^7|^8|^9", - "squizlabs/php_codesniffer": "^3.2", - "phpcompatibility/php-compatibility": "^8.1", - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", - "orchestra/testbench": "^3.8|^4.0|^5.0" - }, - "scripts": { - "test": "SHELL_INTERACTIVE=1 \"vendor/bin/phpunit\" --coverage-text ", - "phpcs": "\"vendor/bin/phpcs\"", - "sniffs": "\"vendor/bin/phpcs\" -e" - }, - "autoload": { - "classmap": [ - "src/controllers", - "src/facade" - ], - "psr-0": { - "Auth0\\Login\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "Auth0\\Login\\Tests\\": "tests" - } - }, - "extra": { - "laravel": { - "providers": [ - "Auth0\\Login\\LoginServiceProvider" - ], - "aliases": { - "Auth0": "Auth0\\Login\\Facade\\Auth0" - } - } + "name": "auth0/login", + "description": "Laravel plugin that helps authenticate with the auth0 service", + "license": "MIT", + "prefer-stable": true, + "require": { + "php": "^7.1", + "auth0/auth0-php": "^7.2.0", + "illuminate/support": "5.* | ^6.0 | ^7.0 | ^8.0", + "illuminate/contracts": "5.* | ^6.0 | ^7.0 | ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^7|^8|^9", + "squizlabs/php_codesniffer": "^3.2", + "phpcompatibility/php-compatibility": "^8.1", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "orchestra/testbench": "^3.8|^4.0|^5.0" + }, + "scripts": { + "test": "SHELL_INTERACTIVE=1 \"vendor/bin/phpunit\" --coverage-text ", + "phpcs": "\"vendor/bin/phpcs\"", + "sniffs": "\"vendor/bin/phpcs\" -e" + }, + "autoload": { + "classmap": [ + "src/controllers", + "src/facade" + ], + "psr-0": { + "Auth0\\Login\\": "src/" } + }, + "autoload-dev": { + "psr-4": { + "Auth0\\Login\\Tests\\": "tests" + } + }, + "extra": { + "laravel": { + "providers": [ + "Auth0\\Login\\LoginServiceProvider" + ], + "aliases": { + "Auth0": "Auth0\\Login\\Facade\\Auth0" + } + } + } } From b80b8798c5cf0eb8a6cde2ebb50c8edf023918d4 Mon Sep 17 00:00:00 2001 From: Luciano Balmaceda Date: Wed, 18 Nov 2020 11:07:45 -0300 Subject: [PATCH 006/525] Setup pull-request and issue templates (#199) --- .github/ISSUE_TEMPLATE.md | 43 ------------------ .github/ISSUE_TEMPLATE/config.yml | 5 +++ .github/ISSUE_TEMPLATE/feature_request.md | 39 ++++++++++++++++ .github/ISSUE_TEMPLATE/report_a_bug.md | 55 +++++++++++++++++++++++ 4 files changed, 99 insertions(+), 43 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/report_a_bug.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 6c9bf0d5..00000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,43 +0,0 @@ -In order to efficiently and accurately address your issue or feature request, please read through the template below and answer all relevant questions. Your additional work here is greatly appreciated and will help us respond as quickly as possible. Please delete any sections or questions below that do not pertain to this request. - -For general support or usage questions, please use the [Auth0 Community](https://community.auth0.com/) or [Auth0 Support](https://support.auth0.com.). - -### Description - -Description of the bug or feature request and why it's a problem. Consider including: - -- The use case or overall problem you're trying to solve -- Information about when the problem started - -### Prerequisites - -[ ] I have checked the [Auth0 Community](https://community.auth0.com/) for related posts. - -[ ] I have checked for related or duplicate [Issues](https://github.com/auth0/REPO-NAME/issues) and [PRs](https://github.com/auth0/REPO-NAME/pulls). - -[ ] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md). - -[ ] I have read the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). - -[ ] I am reporting this to the correct repository (this module runs on [Auth0-PHP](https://github.com/auth0/auth0-PHP)). - -### Environment - -Please provide the following: - -- Version of the module used: -- Version of PHP used: -- Version of Laravel used: -- Apache/Nginx and MySQL versions, if related: -- Additional packages that might be affecting your instance: - -### Reproduction - -Detail the steps taken to reproduce this error and note if this issue can be reproduced consistently or if it is intermittent. - -Please include: - -- Code samples that reproduce the error -- Log files (redact/remove sensitive information) -- Application settings (redact/remove sensitive information) -- Screenshots, if helpful diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..b785e527 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Auth0 Community + url: https://community.auth0.com/c/sdks/5 + about: Discuss this SDK in the Auth0 Community forums \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..68352ba2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,39 @@ +--- +name: Feature request +about: Suggest an idea or a feature for this project +title: '' +labels: feature request +assignees: '' +--- + + + +### Describe the problem you'd like to have solved + + + +### Describe the ideal solution + + + +## Alternatives and current work-arounds + + + +### Additional information, if any + + \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/report_a_bug.md b/.github/ISSUE_TEMPLATE/report_a_bug.md new file mode 100644 index 00000000..50b9fa7e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/report_a_bug.md @@ -0,0 +1,55 @@ +--- +name: Report a bug +about: Have you found a bug or issue? Create a bug report for this SDK +title: '' +labels: bug report +assignees: '' +--- + + + +### Describe the problem + + + +### What was the expected behavior? + + + +### Reproduction + + +- Step 1.. +- Step 2.. +- ... + +### Environment + + + +- **Version of this library used:** +- **Which framework are you using, if applicable:** +- **Other modules/plugins/libraries that might be involved:** +- **Any other relevant information you think would be useful:** \ No newline at end of file From 07fd05f0cbe7a5f6058aa8ff6937fc3a4d1a81e4 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 23 Nov 2020 17:41:57 -0500 Subject: [PATCH 007/525] Update composer.json --- composer.json | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 94d8a20e..014c9caf 100644 --- a/composer.json +++ b/composer.json @@ -2,15 +2,27 @@ "name": "auth0/login", "description": "Laravel plugin that helps authenticate with the auth0 service", "license": "MIT", - "prefer-stable": true, + "repositories": [ + { + "type": "git", + "url": "https://github.com/auth0/auth0-PHP.git" + }, + { + "type": "git", + "url": "https://github.com/evansims/jwt.git" + } + ], "require": { - "php": "^7.1", - "auth0/auth0-php": "^7.2.0", + "php": "^7.3 | ^8.0", + "ext-json": "*", + "ext-openssl": "*", + "auth0/auth0-php": "dev-update-php8", + "lcobucci/jwt": "dev-3.3-php8-compatibility", "illuminate/support": "5.* | ^6.0 | ^7.0 | ^8.0", "illuminate/contracts": "5.* | ^6.0 | ^7.0 | ^8.0" }, "require-dev": { - "phpunit/phpunit": "^7|^8|^9", + "phpunit/phpunit": "^9", "squizlabs/php_codesniffer": "^3.2", "phpcompatibility/php-compatibility": "^8.1", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", From 35b8d2a53d7c53eeeaca1e6aa93a4d565c40f32a Mon Sep 17 00:00:00 2001 From: Sebastian Wasser Date: Tue, 1 Dec 2020 16:52:12 +0200 Subject: [PATCH 008/525] Fix the missing `return null;` in `getUserByIdentifier` --- src/Auth0/Login/Repository/Auth0UserRepository.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Auth0/Login/Repository/Auth0UserRepository.php b/src/Auth0/Login/Repository/Auth0UserRepository.php index dc6b8b90..1cd5b03a 100644 --- a/src/Auth0/Login/Repository/Auth0UserRepository.php +++ b/src/Auth0/Login/Repository/Auth0UserRepository.php @@ -50,5 +50,7 @@ public function getUserByIdentifier($identifier) : ?Authenticatable if ($auth0User && $auth0User->getAuthIdentifier() == $identifier) { return $auth0User; } + + return null; } } From 0b304c56f3313b71df4cb012f6c5627ef60c611a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 28 Dec 2020 14:36:14 -0500 Subject: [PATCH 009/525] Update composer and CircleCI configurations --- .circleci/config.yml | 56 +++++++++++++++++++++++++++++++----------- .phpcs-compat.xml.dist | 16 ++++++++++++ composer.json | 29 +++++++++++++++------- phpstan.neon | 8 ++++++ 4 files changed, 86 insertions(+), 23 deletions(-) create mode 100644 .phpcs-compat.xml.dist create mode 100644 phpstan.neon diff --git a/.circleci/config.yml b/.circleci/config.yml index b43357b3..a9cd30f9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,31 +7,51 @@ commands: - run: sudo composer self-update - restore_cache: keys: - - composer-v1-{{ checksum "composer.json" }} - - composer-v1- + - composer-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "composer.json" }} + - composer-v1-{{ .Environment.CIRCLE_JOB }} - run: composer install -n --prefer-dist + - run: composer update --prefer-dist --no-interaction - persist_to_workspace: root: . paths: - composer.* - .snyk - save_cache: - key: composer-v1-{{ checksum "composer.json" }} + key: composer-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "composer.json" }} paths: - vendor + run-static-analysis: + steps: + - run composer static-analysis + run-unit-tests: + steps: + - run: composer test + - store_artifacts: + path: build/coverage.xml jobs: - php_7: + php_7_3: docker: - - image: circleci/php:7.1 + - image: circleci/php:7.3 steps: - prepare - - run: - name: Check PHP Compatibility - command: composer phpcs - - run: - name: Run Tests - command: composer test + - run-php-compatibility + - run-static-analysis + - run-unit-tests + php_7_4: + docker: + - image: circleci/php:7.4 + steps: + - prepare + - run-static-analysis + - run-unit-tests + php_8_0: + docker: + - image: circleci/php:8.0 + steps: + - prepare + - run-static-analysis + - run-unit-tests snyk: docker: - image: snyk/snyk-cli:composer @@ -47,13 +67,21 @@ jobs: fi when: always -#Each workflow represents a Github check workflows: + build-and-test: + jobs: + - php_7_3 + - php_7_4 + - php_8_0 + - snyk: + context: snyk-env + requires: + - php_7_3 snyk: jobs: - - php_7 + - php_7_3 - snyk: # Must define SNYK_TOKEN env context: snyk-env requires: - - php_7 + - php_7_3 diff --git a/.phpcs-compat.xml.dist b/.phpcs-compat.xml.dist new file mode 100644 index 00000000..816c94c8 --- /dev/null +++ b/.phpcs-compat.xml.dist @@ -0,0 +1,16 @@ + + + PHPCompatibility check for Auth0 Laravel SDK + ./src + + + + + + + + + diff --git a/composer.json b/composer.json index 014c9caf..6c8c5d61 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ }, { "type": "git", - "url": "https://github.com/evansims/jwt.git" + "url": "https://github.com/evansims/php-jwt.git" } ], "require": { @@ -17,21 +17,32 @@ "ext-json": "*", "ext-openssl": "*", "auth0/auth0-php": "dev-update-php8", - "lcobucci/jwt": "dev-3.3-php8-compatibility", - "illuminate/support": "5.* | ^6.0 | ^7.0 | ^8.0", - "illuminate/contracts": "5.* | ^6.0 | ^7.0 | ^8.0" + "lcobucci/jwt": "dev-3.3-php8-compatibility#daa6aff67a22bf737504143ae55a6913d9ff484d", + "illuminate/support": " ^6.0 | ^7.0 | ^8.0", + "illuminate/contracts": "^6.0 | ^7.0 | ^8.0" }, "require-dev": { - "phpunit/phpunit": "^9", + "phpunit/phpunit": "^9.3", "squizlabs/php_codesniffer": "^3.2", "phpcompatibility/php-compatibility": "^8.1", - "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", - "orchestra/testbench": "^3.8|^4.0|^5.0" + "dealerdirect/phpcodesniffer-composer-installer": "^0.7", + "orchestra/testbench": "^4.0 | ^5.0", + "nunomaduro/larastan": "^0.6.11" }, "scripts": { "test": "SHELL_INTERACTIVE=1 \"vendor/bin/phpunit\" --coverage-text ", - "phpcs": "\"vendor/bin/phpcs\"", - "sniffs": "\"vendor/bin/phpcs\" -e" + "static-analysis": "\"vendor/bin/phpstan\" analyze", + "compat": "@php ./vendor/bin/phpcs --standard=.phpcs-compat.xml.dist", + "format": "@php ./vendor/bin/phpcbf", + "lint": "@php ./vendor/bin/phpcs", + "sniffs": "\"vendor/bin/phpcs\" -e", + "config-phpcs": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run", + "pre-commit": [ + "@static-analysis", + "@test", + "@format", + "@compat" + ] }, "autoload": { "classmap": [ diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000..5cc39852 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,8 @@ +parameters: + checkGenericClassInNonGenericObjectType: false + level: 2 + ignoreErrors: + - '#Call to an undefined static method Event::listen#' + - '#Call to static method#' + paths: + - src From b8a24ef2163054e86767460ba2a240fa8cc6a7c1 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 28 Dec 2020 14:37:07 -0500 Subject: [PATCH 010/525] Docblock fixes --- src/Auth0/Login/Auth0JWTUser.php | 2 +- src/Auth0/Login/Auth0Service.php | 13 +++++++------ src/Auth0/Login/Auth0User.php | 2 +- src/Auth0/Login/LaravelSessionStore.php | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Auth0/Login/Auth0JWTUser.php b/src/Auth0/Login/Auth0JWTUser.php index 013a2239..86361545 100644 --- a/src/Auth0/Login/Auth0JWTUser.php +++ b/src/Auth0/Login/Auth0JWTUser.php @@ -13,7 +13,7 @@ class Auth0JWTUser implements \Illuminate\Contracts\Auth\Authenticatable /** * Auth0JWTUser constructor. * - * @param $userInfo + * @param array $userInfo */ public function __construct(array $userInfo) { diff --git a/src/Auth0/Login/Auth0Service.php b/src/Auth0/Login/Auth0Service.php index 6d153d1c..81faf795 100644 --- a/src/Auth0/Login/Auth0Service.php +++ b/src/Auth0/Login/Auth0Service.php @@ -12,6 +12,7 @@ use Illuminate\Contracts\Config\Repository as ConfigRepository; use Illuminate\Http\RedirectResponse; use Psr\SimpleCache\CacheInterface; +use \Illuminate\Contracts\Auth\Authenticatable; /** * Service that provides access to the Auth0 SDK. @@ -31,7 +32,7 @@ class Auth0Service /** * Auth0Service constructor. * - * @param array|null $auth0Config + * @param array $auth0Config * @param StoreInterface|null $store * @param CacheInterface|null $cache * @@ -124,9 +125,9 @@ public function getUser() /** * Sets a callback to be called when the user is logged in. * - * @param callback $cb A function that receives an auth0User and receives a Laravel user + * @param callable $cb A function that receives an auth0User and receives a Laravel user */ - public function onLogin($cb) + public function onLogin(callable $cb) { $this->_onLoginCb = $cb; } @@ -140,7 +141,7 @@ public function hasOnLogin() } /** - * @param $auth0User + * @param Authenticatable $auth0User * * @return mixed */ @@ -166,13 +167,13 @@ public function rememberUser($value = null) } /** - * @param $encUser + * @param string $encUser * @param array $verifierOptions * * @return array * @throws \Auth0\SDK\Exception\InvalidTokenException */ - public function decodeJWT($encUser, array $verifierOptions = []) + public function decodeJWT(string $encUser, array $verifierOptions = []) { $token_issuer = 'https://'.$this->auth0Config['domain'].'/'; $apiIdentifier = $this->auth0Config['api_identifier']; diff --git a/src/Auth0/Login/Auth0User.php b/src/Auth0/Login/Auth0User.php index 3fe607b2..7ce2faf4 100644 --- a/src/Auth0/Login/Auth0User.php +++ b/src/Auth0/Login/Auth0User.php @@ -80,7 +80,7 @@ public function getRememberTokenName() /** * Add a generic getter to get all the properties of the userInfo. * - * @return the related value or null if it is not set + * @return null|mixed Returns the related value, or null if not set. */ public function __get($name) { diff --git a/src/Auth0/Login/LaravelSessionStore.php b/src/Auth0/Login/LaravelSessionStore.php index c2eaf784..147e6e6d 100644 --- a/src/Auth0/Login/LaravelSessionStore.php +++ b/src/Auth0/Login/LaravelSessionStore.php @@ -22,7 +22,7 @@ public function set(string $key, $value) } /** - * @param $key + * @param string $key * @param null $default * * @return mixed From db28fa860662eb8857eedffdc2ca5e9026bb8fc0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 28 Dec 2020 14:37:21 -0500 Subject: [PATCH 011/525] Remove obsolete authorized_issuers reference from config --- src/config/config.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/config/config.php b/src/config/config.php index 66a1a5f4..8706f5ba 100644 --- a/src/config/config.php +++ b/src/config/config.php @@ -54,15 +54,6 @@ 'persist_refresh_token' => false, 'persist_id_token' => false, - /* - |-------------------------------------------------------------------------- - | The authorized token issuers - |-------------------------------------------------------------------------- - | This is used to verify the decoded tokens when using RS256 - | - */ - 'authorized_issuers' => [ env( 'AUTH0_DOMAIN' ) ], - /* |-------------------------------------------------------------------------- | The authorized token audiences From 8ae4ad403f2902ad5ea3fd1d330e46c605a9ee0f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 28 Dec 2020 14:38:56 -0500 Subject: [PATCH 012/525] Remove lockfile reference from CircleCI config --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a9cd30f9..1d428492 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,6 @@ commands: - composer-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "composer.json" }} - composer-v1-{{ .Environment.CIRCLE_JOB }} - run: composer install -n --prefer-dist - - run: composer update --prefer-dist --no-interaction - persist_to_workspace: root: . paths: From 9163511bdc101880d6192140e28fd5b2b7b1d94c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 28 Dec 2020 14:39:49 -0500 Subject: [PATCH 013/525] Update CircleCI config --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1d428492..f3818c65 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,7 +9,7 @@ commands: keys: - composer-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "composer.json" }} - composer-v1-{{ .Environment.CIRCLE_JOB }} - - run: composer install -n --prefer-dist + - run: composer update --prefer-dist --no-interaction - persist_to_workspace: root: . paths: From fd8ea4bf347bcfd1e0af443b39094b580f67cad8 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 28 Dec 2020 14:42:06 -0500 Subject: [PATCH 014/525] Update CircleCI config --- .circleci/config.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f3818c65..dd4a2e2b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,9 +19,12 @@ commands: key: composer-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "composer.json" }} paths: - vendor + run-php-compatibility: + steps: + - run: composer compat run-static-analysis: steps: - - run composer static-analysis + - run: composer static-analysis run-unit-tests: steps: - run: composer test From 3901344adebae27d9cbbbdb0d08721cea990a878 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 28 Dec 2020 14:45:37 -0500 Subject: [PATCH 015/525] Fix missing return statement in getUserByIdentifier --- src/Auth0/Login/Repository/Auth0UserRepository.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Auth0/Login/Repository/Auth0UserRepository.php b/src/Auth0/Login/Repository/Auth0UserRepository.php index dc6b8b90..c35a6a0a 100644 --- a/src/Auth0/Login/Repository/Auth0UserRepository.php +++ b/src/Auth0/Login/Repository/Auth0UserRepository.php @@ -50,5 +50,7 @@ public function getUserByIdentifier($identifier) : ?Authenticatable if ($auth0User && $auth0User->getAuthIdentifier() == $identifier) { return $auth0User; } + + return null; } } From 5a3bd7f3efd0493e73a5c1ff5548a7232be9ab7a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 28 Dec 2020 14:47:15 -0500 Subject: [PATCH 016/525] Update CircleCI config --- .circleci/config.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index dd4a2e2b..303b5d58 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -79,11 +79,3 @@ workflows: context: snyk-env requires: - php_7_3 - snyk: - jobs: - - php_7_3 - - snyk: - # Must define SNYK_TOKEN env - context: snyk-env - requires: - - php_7_3 From 2abf2790372c15be87ce660c706c63e216ddc029 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 4 Jan 2021 14:10:15 -0500 Subject: [PATCH 017/525] Update composer.json --- composer.json | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 6c8c5d61..a97efed7 100644 --- a/composer.json +++ b/composer.json @@ -1,22 +1,18 @@ { "name": "auth0/login", - "description": "Laravel plugin that helps authenticate with the auth0 service", + "description": "Laravel plugin that helps authenticate with the Auth0 service", "license": "MIT", "repositories": [ { "type": "git", - "url": "https://github.com/auth0/auth0-PHP.git" - }, - { - "type": "git", - "url": "https://github.com/evansims/php-jwt.git" + "url": "https://github.com/auth0/php-jwt.git" } ], "require": { "php": "^7.3 | ^8.0", "ext-json": "*", "ext-openssl": "*", - "auth0/auth0-php": "dev-update-php8", + "auth0/auth0-php": "^7.6", "lcobucci/jwt": "dev-3.3-php8-compatibility#daa6aff67a22bf737504143ae55a6913d9ff484d", "illuminate/support": " ^6.0 | ^7.0 | ^8.0", "illuminate/contracts": "^6.0 | ^7.0 | ^8.0" @@ -31,14 +27,14 @@ }, "scripts": { "test": "SHELL_INTERACTIVE=1 \"vendor/bin/phpunit\" --coverage-text ", - "static-analysis": "\"vendor/bin/phpstan\" analyze", + "analyze": "\"vendor/bin/phpstan\" analyze", "compat": "@php ./vendor/bin/phpcs --standard=.phpcs-compat.xml.dist", "format": "@php ./vendor/bin/phpcbf", "lint": "@php ./vendor/bin/phpcs", "sniffs": "\"vendor/bin/phpcs\" -e", "config-phpcs": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run", "pre-commit": [ - "@static-analysis", + "@analyze", "@test", "@format", "@compat" From 1752efe312771bdfe1eeb669d4dca88f635ad0b2 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 4 Jan 2021 14:11:46 -0500 Subject: [PATCH 018/525] Update CircleCI config --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 303b5d58..6e103b87 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -24,7 +24,7 @@ commands: - run: composer compat run-static-analysis: steps: - - run: composer static-analysis + - run: composer analyze run-unit-tests: steps: - run: composer test From abbae33e37e7e686048a46d67ef8f6ceae59e2ec Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 4 Jan 2021 14:20:19 -0500 Subject: [PATCH 019/525] Coding standards pass --- .phpcs.xml.dist | 94 +++++++++++++++- src/Auth0/Login/Auth0JWTUser.php | 3 +- src/Auth0/Login/Auth0Service.php | 43 ++++---- src/Auth0/Login/Auth0User.php | 17 +-- src/Auth0/Login/Auth0UserProvider.php | 8 +- .../Login/Contract/Auth0UserRepository.php | 2 +- src/Auth0/Login/LaravelSessionStore.php | 2 +- src/Auth0/Login/LoginServiceProvider.php | 2 +- .../Login/Repository/Auth0UserRepository.php | 2 +- src/config/config.php | 101 +++++++++--------- src/controllers/Auth0Controller.php | 2 + 11 files changed, 190 insertions(+), 86 deletions(-) diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index c1aa8dda..b5f52d09 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -20,7 +20,99 @@ PHPCompatibility sniffs to check for PHP cross-version incompatible code. https://github.com/PHPCompatibility/PHPCompatibility --> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + tests/*\.php + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Auth0/Login/Auth0JWTUser.php b/src/Auth0/Login/Auth0JWTUser.php index 86361545..6c59ec2d 100644 --- a/src/Auth0/Login/Auth0JWTUser.php +++ b/src/Auth0/Login/Auth0JWTUser.php @@ -8,6 +8,7 @@ */ class Auth0JWTUser implements \Illuminate\Contracts\Auth\Authenticatable { + private $userInfo; /** @@ -75,7 +76,7 @@ public function getRememberTokenName() */ public function __get($name) { - if (!array_key_exists($name, $this->userInfo)) { + if (! array_key_exists($name, $this->userInfo)) { return; } diff --git a/src/Auth0/Login/Auth0Service.php b/src/Auth0/Login/Auth0Service.php index 81faf795..9ac0ccb2 100644 --- a/src/Auth0/Login/Auth0Service.php +++ b/src/Auth0/Login/Auth0Service.php @@ -19,20 +19,24 @@ */ class Auth0Service { + /** * @var Auth0 */ private $auth0; private $apiuser; + private $_onLoginCb = null; + private $rememberUser = false; + private $auth0Config = []; /** * Auth0Service constructor. * - * @param array $auth0Config + * @param array $auth0Config * @param StoreInterface|null $store * @param CacheInterface|null $cache * @@ -44,25 +48,26 @@ public function __construct( CacheInterface $cache = null ) { - - if (!$auth0Config instanceof ConfigRepository && !is_array($auth0Config)) { + if (! $auth0Config instanceof ConfigRepository && ! is_array($auth0Config)) { $auth0Config = config('laravel-auth0'); } $store = $auth0Config['store'] ?? $store; - if (false !== $store && !$store instanceof StoreInterface) { + if (false !== $store && ! $store instanceof StoreInterface) { $store = new LaravelSessionStore(); } + $auth0Config['store'] = $store; $cache = $auth0Config['cache_handler'] ?? $cache; - if (!($cache instanceof CacheInterface)) { + if (! ($cache instanceof CacheInterface)) { $cache = app()->make('cache.store'); } + $auth0Config['cache_handler'] = $cache; $this->auth0Config = $auth0Config; - $this->auth0 = new Auth0($auth0Config); + $this->auth0 = new Auth0($auth0Config); } /** @@ -97,7 +102,7 @@ public function login($connection = null, $state = null, $additional_params = [' } $additional_params['response_type'] = $response_type; - $auth_url = $this->auth0->getLoginUrl($additional_params); + $auth_url = $this->auth0->getLoginUrl($additional_params); return new RedirectResponse($auth_url); } @@ -110,7 +115,7 @@ public function getUser() { // Get the user info from auth0 $auth0 = $this->getSDK(); - $user = $auth0->getUser(); + $user = $auth0->getUser(); if ($user === null) { return; @@ -125,15 +130,15 @@ public function getUser() /** * Sets a callback to be called when the user is logged in. * - * @param callable $cb A function that receives an auth0User and receives a Laravel user + * @param $cb A function that receives an auth0User and receives a Laravel user */ - public function onLogin(callable $cb) + public function onLogin($cb) { $this->_onLoginCb = $cb; } /** - * @return bool + * @return boolean */ public function hasOnLogin() { @@ -155,7 +160,7 @@ public function callOnLogin($auth0User) * * @param null $value * - * @return bool|null + * @return boolean|null */ public function rememberUser($value = null) { @@ -168,22 +173,22 @@ public function rememberUser($value = null) /** * @param string $encUser - * @param array $verifierOptions + * @param array $verifierOptions * * @return array * @throws \Auth0\SDK\Exception\InvalidTokenException */ - public function decodeJWT(string $encUser, array $verifierOptions = []) + public function decodeJWT($encUser, array $verifierOptions = []) { - $token_issuer = 'https://'.$this->auth0Config['domain'].'/'; + $token_issuer = 'https://'.$this->auth0Config['domain'].'/'; $apiIdentifier = $this->auth0Config['api_identifier']; - $idTokenAlg = $this->auth0Config['supported_algs'][0] ?? 'RS256'; + $idTokenAlg = $this->auth0Config['supported_algs'][0] ?? 'RS256'; $signature_verifier = null; if ('RS256' === $idTokenAlg) { - $jwksUri = $this->auth0Config['jwks_uri'] ?? 'https://'.$this->auth0Config['domain'].'/.well-known/jwks.json'; - $jwks_fetcher = new JWKFetcher($this->auth0Config['cache_handler']); - $jwks = $jwks_fetcher->getKeys($jwksUri); + $jwksUri = $this->auth0Config['jwks_uri'] ?? 'https://'.$this->auth0Config['domain'].'/.well-known/jwks.json'; + $jwks_fetcher = new JWKFetcher($this->auth0Config['cache_handler']); + $jwks = $jwks_fetcher->getKeys($jwksUri); $signature_verifier = new AsymmetricVerifier($jwks); } else if ('HS256' === $idTokenAlg) { $signature_verifier = new SymmetricVerifier($this->auth0Config['client_secret']); diff --git a/src/Auth0/Login/Auth0User.php b/src/Auth0/Login/Auth0User.php index 7ce2faf4..fa108f9a 100644 --- a/src/Auth0/Login/Auth0User.php +++ b/src/Auth0/Login/Auth0User.php @@ -8,18 +8,20 @@ */ class Auth0User implements \Illuminate\Contracts\Auth\Authenticatable { + protected $userInfo; + protected $accessToken; /** * Auth0User constructor. * - * @param array $userInfo + * @param array $userInfo * @param string|null $accessToken */ public function __construct(array $userInfo, $accessToken) { - $this->userInfo = $userInfo; + $this->userInfo = $userInfo; $this->accessToken = $accessToken; } @@ -30,10 +32,11 @@ public function __construct(array $userInfo, $accessToken) */ public function getAuthIdentifier() { - if (isset($this->userInfo['sub'])) { - return $this->userInfo['sub']; - } - return $this->userInfo['user_id']; + if (isset($this->userInfo['sub'])) { + return $this->userInfo['sub']; + } + + return $this->userInfo['user_id']; } /** @@ -84,7 +87,7 @@ public function getRememberTokenName() */ public function __get($name) { - if (!array_key_exists($name, $this->userInfo)) { + if (! array_key_exists($name, $this->userInfo)) { return; } diff --git a/src/Auth0/Login/Auth0UserProvider.php b/src/Auth0/Login/Auth0UserProvider.php index f7151add..b9a53288 100644 --- a/src/Auth0/Login/Auth0UserProvider.php +++ b/src/Auth0/Login/Auth0UserProvider.php @@ -14,7 +14,9 @@ */ class Auth0UserProvider implements UserProvider { + protected $userRepository; + protected $auth0; /** @@ -26,7 +28,7 @@ class Auth0UserProvider implements UserProvider public function __construct(Auth0UserRepository $userRepository, Auth0Service $auth0) { $this->userRepository = $userRepository; - $this->auth0 = $auth0; + $this->auth0 = $auth0; } /** @@ -45,11 +47,11 @@ public function retrieveByID($identifier) /** * @param array $credentials * - * @return bool|Authenticatable + * @return boolean|Authenticatable */ public function retrieveByCredentials(array $credentials) { - if (!isset($credentials['api_token'])) { + if (! isset($credentials['api_token'])) { return null; } diff --git a/src/Auth0/Login/Contract/Auth0UserRepository.php b/src/Auth0/Login/Contract/Auth0UserRepository.php index 439101e0..609c812b 100644 --- a/src/Auth0/Login/Contract/Auth0UserRepository.php +++ b/src/Auth0/Login/Contract/Auth0UserRepository.php @@ -21,7 +21,7 @@ public function getUserByDecodedJWT(array $decodedJwt) : Authenticatable; public function getUserByUserInfo(array $userInfo) : Authenticatable; /** - * @param string|int|null $identifier the user id + * @param string|integer|null $identifier the user id * * @return Authenticatable|null */ diff --git a/src/Auth0/Login/LaravelSessionStore.php b/src/Auth0/Login/LaravelSessionStore.php index 147e6e6d..3b8c13a2 100644 --- a/src/Auth0/Login/LaravelSessionStore.php +++ b/src/Auth0/Login/LaravelSessionStore.php @@ -23,7 +23,7 @@ public function set(string $key, $value) /** * @param string $key - * @param null $default + * @param null $default * * @return mixed */ diff --git a/src/Auth0/Login/LoginServiceProvider.php b/src/Auth0/Login/LoginServiceProvider.php index 67ec7a08..441a2377 100644 --- a/src/Auth0/Login/LoginServiceProvider.php +++ b/src/Auth0/Login/LoginServiceProvider.php @@ -14,7 +14,7 @@ class LoginServiceProvider extends ServiceProvider { - const SDK_VERSION = "6.1.0"; + const SDK_VERSION = '6.1.0'; /** * Bootstrap the application events. diff --git a/src/Auth0/Login/Repository/Auth0UserRepository.php b/src/Auth0/Login/Repository/Auth0UserRepository.php index c35a6a0a..8a0dc7a7 100644 --- a/src/Auth0/Login/Repository/Auth0UserRepository.php +++ b/src/Auth0/Login/Repository/Auth0UserRepository.php @@ -30,7 +30,7 @@ public function getUserByUserInfo(array $userInfo) : Authenticatable } /** - * @param string|int|null $identifier + * @param string|integer|null $identifier * * @return Authenticatable|null */ diff --git a/src/config/config.php b/src/config/config.php index 8706f5ba..9af9c0b9 100644 --- a/src/config/config.php +++ b/src/config/config.php @@ -3,51 +3,51 @@ return [ /* - |-------------------------------------------------------------------------- - | Your auth0 domain - |-------------------------------------------------------------------------- - | As set in the auth0 administration page - | + |-------------------------------------------------------------------------- + | Your auth0 domain + |-------------------------------------------------------------------------- + | As set in the auth0 administration page + | */ 'domain' => env( 'AUTH0_DOMAIN' ), /* - |-------------------------------------------------------------------------- - | Your APP id - |-------------------------------------------------------------------------- - | As set in the auth0 administration page - | + |-------------------------------------------------------------------------- + | Your APP id + |-------------------------------------------------------------------------- + | As set in the auth0 administration page + | */ 'client_id' => env( 'AUTH0_CLIENT_ID' ), /* - |-------------------------------------------------------------------------- - | Your APP secret - |-------------------------------------------------------------------------- - | As set in the auth0 administration page - | + |-------------------------------------------------------------------------- + | Your APP secret + |-------------------------------------------------------------------------- + | As set in the auth0 administration page + | */ 'client_secret' => env( 'AUTH0_CLIENT_SECRET' ), /* - |-------------------------------------------------------------------------- - | The redirect URI - |-------------------------------------------------------------------------- - | Should be the same that the one configure in the route to handle the - | 'Auth0\Login\Auth0Controller@callback' - | - */ - 'redirect_uri' => env( 'APP_URL' ) . '/auth0/callback', + |-------------------------------------------------------------------------- + | The redirect URI + |-------------------------------------------------------------------------- + | Should be the same that the one configure in the route to handle the + | 'Auth0\Login\Auth0Controller@callback' + | + */ + 'redirect_uri' => env( 'APP_URL' ).'/auth0/callback', /* - |-------------------------------------------------------------------------- - | Persistence Configuration - |-------------------------------------------------------------------------- - | persist_user (Boolean) Optional. Indicates if you want to persist the user info, default true - | persist_access_token (Boolean) Optional. Indicates if you want to persist the access token, default false - | persist_refresh_token (Boolean) Optional. Indicates if you want to persist the refresh token, default false - | persist_id_token (Boolean) Optional. Indicates if you want to persist the id token, default false - | + |-------------------------------------------------------------------------- + | Persistence Configuration + |-------------------------------------------------------------------------- + | persist_user (Boolean) Optional. Indicates if you want to persist the user info, default true + | persist_access_token (Boolean) Optional. Indicates if you want to persist the access token, default false + | persist_refresh_token (Boolean) Optional. Indicates if you want to persist the refresh token, default false + | persist_id_token (Boolean) Optional. Indicates if you want to persist the id token, default false + | */ 'persist_user' => true, 'persist_access_token' => false, @@ -55,37 +55,36 @@ 'persist_id_token' => false, /* - |-------------------------------------------------------------------------- - | The authorized token audiences - |-------------------------------------------------------------------------- - | + |-------------------------------------------------------------------------- + | The authorized token audiences + |-------------------------------------------------------------------------- + | */ // 'api_identifier' => '', - /* - |-------------------------------------------------------------------------- - | The secret format - |-------------------------------------------------------------------------- - | Used to know if it should decode the secret when using HS256 - | + |-------------------------------------------------------------------------- + | The secret format + |-------------------------------------------------------------------------- + | Used to know if it should decode the secret when using HS256 + | */ 'secret_base64_encoded' => false, /* - |-------------------------------------------------------------------------- - | Supported algorithms - |-------------------------------------------------------------------------- - | Token decoding algorithms supported by your API - | + |-------------------------------------------------------------------------- + | Supported algorithms + |-------------------------------------------------------------------------- + | Token decoding algorithms supported by your API + | */ 'supported_algs' => [ 'RS256' ], /* - |-------------------------------------------------------------------------- - | Guzzle Options - |-------------------------------------------------------------------------- - | guzzle_options (array) optional. Used to specify additional connection options e.g. proxy settings - | + |-------------------------------------------------------------------------- + | Guzzle Options + |-------------------------------------------------------------------------- + | guzzle_options (array) optional. Used to specify additional connection options e.g. proxy settings + | */ // 'guzzle_options' => [] ]; diff --git a/src/controllers/Auth0Controller.php b/src/controllers/Auth0Controller.php index caf608ea..f7e2a25f 100644 --- a/src/controllers/Auth0Controller.php +++ b/src/controllers/Auth0Controller.php @@ -7,6 +7,7 @@ class Auth0Controller extends Controller { + /** * @var Auth0UserRepository */ @@ -46,6 +47,7 @@ public function callback() // If not, the user will be fine $user = $auth0User; } + \Auth::login($user, $service->rememberUser()); } From 970bba3a4c2f2ea465b2889a2acf3dd137f8a0e1 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 4 Jan 2021 14:23:38 -0500 Subject: [PATCH 020/525] Update composer.json --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index a97efed7..4db24a82 100644 --- a/composer.json +++ b/composer.json @@ -26,12 +26,12 @@ "nunomaduro/larastan": "^0.6.11" }, "scripts": { - "test": "SHELL_INTERACTIVE=1 \"vendor/bin/phpunit\" --coverage-text ", - "analyze": "\"vendor/bin/phpstan\" analyze", + "test": "SHELL_INTERACTIVE=1 \"./vendor/bin/phpunit\" --coverage-text ", + "analyze": "@php ./vendor/bin/phpstan analyze", "compat": "@php ./vendor/bin/phpcs --standard=.phpcs-compat.xml.dist", "format": "@php ./vendor/bin/phpcbf", "lint": "@php ./vendor/bin/phpcs", - "sniffs": "\"vendor/bin/phpcs\" -e", + "sniffs": "@php ./vendor/bin/phpcs -e", "config-phpcs": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run", "pre-commit": [ "@analyze", From e560b7993e8017ec20a4cb97ccb0eb2a40beb130 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 4 Jan 2021 14:23:53 -0500 Subject: [PATCH 021/525] Docblock fix for code analyzer --- src/Auth0/Login/Auth0Service.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Auth0/Login/Auth0Service.php b/src/Auth0/Login/Auth0Service.php index 9ac0ccb2..ba3bcb7f 100644 --- a/src/Auth0/Login/Auth0Service.php +++ b/src/Auth0/Login/Auth0Service.php @@ -130,7 +130,7 @@ public function getUser() /** * Sets a callback to be called when the user is logged in. * - * @param $cb A function that receives an auth0User and receives a Laravel user + * @param mixed $cb A function that receives an auth0User and receives a Laravel user */ public function onLogin($cb) { From 118e1bb26652f9bfc53bdbe8e83411179075230a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 4 Jan 2021 16:57:07 -0500 Subject: [PATCH 022/525] Remove obsolete dependency --- composer.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/composer.json b/composer.json index 4db24a82..5e2d1109 100644 --- a/composer.json +++ b/composer.json @@ -2,18 +2,11 @@ "name": "auth0/login", "description": "Laravel plugin that helps authenticate with the Auth0 service", "license": "MIT", - "repositories": [ - { - "type": "git", - "url": "https://github.com/auth0/php-jwt.git" - } - ], "require": { "php": "^7.3 | ^8.0", "ext-json": "*", "ext-openssl": "*", "auth0/auth0-php": "^7.6", - "lcobucci/jwt": "dev-3.3-php8-compatibility#daa6aff67a22bf737504143ae55a6913d9ff484d", "illuminate/support": " ^6.0 | ^7.0 | ^8.0", "illuminate/contracts": "^6.0 | ^7.0 | ^8.0" }, From bec93e20afd39b28a25df87d9ac8413a73962c0f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 4 Jan 2021 17:01:25 -0500 Subject: [PATCH 023/525] Remove unnecessary slashes on use classes --- src/Auth0/Login/Auth0Service.php | 2 +- src/Auth0/Login/Contract/Auth0UserRepository.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Auth0/Login/Auth0Service.php b/src/Auth0/Login/Auth0Service.php index ba3bcb7f..7845eb94 100644 --- a/src/Auth0/Login/Auth0Service.php +++ b/src/Auth0/Login/Auth0Service.php @@ -12,7 +12,7 @@ use Illuminate\Contracts\Config\Repository as ConfigRepository; use Illuminate\Http\RedirectResponse; use Psr\SimpleCache\CacheInterface; -use \Illuminate\Contracts\Auth\Authenticatable; +use Illuminate\Contracts\Auth\Authenticatable; /** * Service that provides access to the Auth0 SDK. diff --git a/src/Auth0/Login/Contract/Auth0UserRepository.php b/src/Auth0/Login/Contract/Auth0UserRepository.php index 609c812b..746182a2 100644 --- a/src/Auth0/Login/Contract/Auth0UserRepository.php +++ b/src/Auth0/Login/Contract/Auth0UserRepository.php @@ -2,7 +2,7 @@ namespace Auth0\Login\Contract; -use \Illuminate\Contracts\Auth\Authenticatable; +use Illuminate\Contracts\Auth\Authenticatable; interface Auth0UserRepository { From f463d01082580b893fc16e9d0772beba790bc6ad Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 4 Jan 2021 17:21:51 -0500 Subject: [PATCH 024/525] Update README.md --- README.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 305841fa..6585669e 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,19 @@ # Laravel Auth0 Plugin -This plugin helps you integrate your [Laravel](https://laravel.com/) WebApp with [Auth0](https://auth0.com/) to achieve Single Sign On with a few simple steps. - -- Master targets compatibility with Laravel 5.7 and above. -- The 3.x branch (not maintained) targets Laravel 5.2 compatibility. -- The 2.x branch (not maintained) targets Laravel 5.0 and 5.1 compatibility. -- If you are working with an older version (Laravel 4.x), use version 1.0.* (not maintained) - [![CircleCI](https://img.shields.io/circleci/project/github/auth0/laravel-auth0/master.svg)](https://circleci.com/gh/auth0/laravel-auth0) [![Latest Stable Version](https://poser.pugx.org/auth0/login/v/stable)](https://packagist.org/packages/auth0/login) [![License](https://poser.pugx.org/auth0/login/license)](https://packagist.org/packages/auth0/login) [![Total Downloads](https://poser.pugx.org/auth0/login/downloads)](https://packagist.org/packages/auth0/login) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0?ref=badge_shield) +This plugin helps you integrate your [Laravel](https://laravel.com/) WebApp with [Auth0](https://auth0.com/) to achieve Single Sign On with a few simple steps. + +## Supported Framework Versions + +Our plugin maintains support for [all actively supported versions](https://laravel.com/docs/8.x/releases#support-policy) of the Laravel framework, including [6.X (LTS)](https://laravel.com/docs/8.x/releases), [7.X](https://laravel.com/docs/7.x/releases) and [8.X](https://laravel.com/docs/8.x/releases). + +Past releases of our plugin may potentially run on earlier, now unsupported versions of the Laravel framework, but these releases are not maintained. The final release of our plugin to support the Laravel 5.X series was 6.1.0. + ## Documentation Please see the [Laravel webapp quickstart](https://auth0.com/docs/quickstart/webapp/laravel) for a complete guide on how to install this in an existing project or to download a pre-configured sample project. Additional documentation on specific scenarios is below. @@ -50,6 +51,7 @@ You can customize the way you handle the users in your application by creating y ### Using auth guard To protect APIs using an access token generated by Auth0, there is an `auth0` API guard provided ([Laravel documentation on guards](https://laravel.com/docs/7.x/authentication#adding-custom-guards)). To use this guard, add it to `config/auth.php` with the driver `auth0`: + ``` 'guards' => [ ... @@ -68,6 +70,7 @@ To protect APIs using an access token generated by Auth0, there is an `auth0` AP ``` Once that has been added, add the guard to the middleware of any API route and check authentication during the request: + ``` // get user auth('auth0')->user(); @@ -118,5 +121,4 @@ Auth0 helps you to easily: The Auth0 Laravel Login plugin is licensed under MIT - [LICENSE](LICENSE.txt) - -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0?ref=badge_large) \ No newline at end of file +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0?ref=badge_large) From d996040b727d279de218eeec102cb2429814d2a3 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 14 Jan 2021 23:55:11 -0500 Subject: [PATCH 025/525] Reinsert missing line break --- src/config/config.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config/config.php b/src/config/config.php index 9af9c0b9..567baca8 100644 --- a/src/config/config.php +++ b/src/config/config.php @@ -61,6 +61,7 @@ | */ // 'api_identifier' => '', + /* |-------------------------------------------------------------------------- | The secret format From d8ccc2797ad1105c22bd32b7f52d354729ce2cbe Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 15 Jan 2021 00:00:47 -0500 Subject: [PATCH 026/525] Bump SDK version to 6.2 --- src/Auth0/Login/LoginServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Auth0/Login/LoginServiceProvider.php b/src/Auth0/Login/LoginServiceProvider.php index 441a2377..6bc9e3e6 100644 --- a/src/Auth0/Login/LoginServiceProvider.php +++ b/src/Auth0/Login/LoginServiceProvider.php @@ -14,7 +14,7 @@ class LoginServiceProvider extends ServiceProvider { - const SDK_VERSION = '6.1.0'; + const SDK_VERSION = '6.2.0'; /** * Bootstrap the application events. From 6e4c8e9c8814a56e22a9232f60bcf49bd4f50ac9 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 15 Jan 2021 00:04:12 -0500 Subject: [PATCH 027/525] Update CHANGELOG.md --- CHANGELOG.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97e68f32..7da0c3fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,80 +1,115 @@ # Change Log +## [6.2.0](https://github.com/auth0/laravel-auth0/tree/6.2.0) (2020-01-15) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.1.0...6.2.0) + +**Added** + +- Support PHP 8.0 [\#200](https://github.com/auth0/laravel-auth0/pull/200) ([evansims](https://github.com/evansims)) + +**Fixed** + +- Fix the missing `return null;` in `getUserByIdentifier` [\#201](https://github.com/auth0/laravel-auth0/pull/201) ([sebwas](https://github.com/sebwas)) + ## [6.1.0](https://github.com/auth0/laravel-auth0/tree/6.1.0) (2020-09-17) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.0.1...6.1.0) **Added** -- Support Laravel 8 [\#190](https://github.com/auth0/laravel-auth0/pull/190) ([giannidhooge](hhttps://github.com/giannidhooge)) + +- Support Laravel 8 [\#190](https://github.com/auth0/laravel-auth0/pull/190) ([giannidhooge](https://github.com/giannidhooge)) **Fixed** + - Fix composer.json whitespace issue [\#192](https://github.com/auth0/laravel-auth0/pull/192) ([jimmyjames](https://github.com/jimmyjames)) ## [6.0.1](https://github.com/auth0/laravel-auth0/tree/6.0.1) (2020-04-28) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.0.0...6.0.1) **Fixed** + - Fix access token decoding and validation [\#183](https://github.com/auth0/laravel-auth0/pull/183) ([jimmyjames](https://github.com/jimmyjames)) ## [6.0.0](https://github.com/auth0/laravel-auth0/tree/6.0.0) (2020-04-09) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.4.0...6.0.0) **This is a major release and includes breaking changes!** This release also includes a major version change for the PHP SDK that it relies on. Please see the [migration guide](https://github.com/auth0/auth0-PHP/blob/master/MIGRATE-v5-TO-v7.md) for the PHP SDK for more information. **Closed issues** + - auth0-PHP 7.0 - State and nonce handling [\#163](https://github.com/auth0/laravel-auth0/issues/163) - Cannot use actingAs unit tests functionality [\#161](https://github.com/auth0/laravel-auth0/issues/161) **Added** + - Implement auth0 guard [\#166](https://github.com/auth0/laravel-auth0/pull/166) ([Tamrael](https://github.com/Tamrael)) **Changed** + - Use array for Auth0JWTUser and add repo return types [\#176](https://github.com/auth0/laravel-auth0/pull/176) ([joshcanhelp](https://github.com/joshcanhelp)) - Update PHP SDK to v7.0.0 [\#162](https://github.com/auth0/laravel-auth0/pull/162) ([joshcanhelp](https://github.com/joshcanhelp)) - Bind SessionState handler interface in container [\#147](https://github.com/auth0/laravel-auth0/pull/147) ([nstapelbroek](https://github.com/nstapelbroek)) **Fixed** + - Fix Laravel session management [\#174](https://github.com/auth0/laravel-auth0/pull/174) ([joshcanhelp](https://github.com/joshcanhelp)) ## [5.4.0](https://github.com/auth0/laravel-auth0/tree/5.4.0) (2020-03-27) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.3.1...5.4.0) **Closed issues** + - Laravel 7.0 supported release. [\#171](https://github.com/auth0/laravel-auth0/issues/171) **Fixed** + - Fixed PHPDocs [\#170](https://github.com/auth0/laravel-auth0/pull/170) ([YAhiru](https://github.com/YAhiru)) **Added** + - Laravel 7 support [\#167](https://github.com/auth0/laravel-auth0/pull/167) ([giannidhooge](https://github.com/giannidhooge)) ## [5.3.1](https://github.com/auth0/laravel-auth0/tree/5.3.1) (2019-11-14) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.3.0...5.3.1) **Closed issues** + - Setting of state_handler in Auth0Service causes "Invalid state" error [\#154](https://github.com/auth0/laravel-auth0/issues/154) **Fixed** + - Allow store and state_handler to be passed in from config [\#156](https://github.com/auth0/laravel-auth0/pull/156) ([joshcanhelp](https://github.com/joshcanhelp)) - Add 'persist_refresh_token' key to laravel-auth0 configuration file. [\#152](https://github.com/auth0/laravel-auth0/pull/152) ([tpenaranda](https://github.com/tpenaranda)) - Replace `setEnvironment` with `setEnvProperty` [\#145](https://github.com/auth0/laravel-auth0/pull/145) ([nstapelbroek](https://github.com/nstapelbroek)) ## [5.3.0](https://github.com/auth0/laravel-auth0/tree/5.3.0) (2019-09-26) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.2.0...5.3.0) **Closed issues** + - Feature request: Add Laravel 6 support [\#138](https://github.com/auth0/laravel-auth0/issues/138) - SessionStateHandler should use LaravelSessionStore not SessionStore [\#125](https://github.com/auth0/laravel-auth0/issues/125) **Added** + - Support Laravel 6 [\#139](https://github.com/auth0/laravel-auth0/pull/139) ([FreekVR](https://github.com/FreekVR)) **Fixed** + - Use LaravelSessionStore in the SessionStateHandler. [\#135](https://github.com/auth0/laravel-auth0/pull/135) ([nstapelbroek](https://github.com/nstapelbroek)) ## [5.2.0](https://github.com/auth0/laravel-auth0/tree/5.2.0) (2019-06-27) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.1.0...5.2.0) **Closed issues** + - Authenticate as a Laravel API user using the Auth0 token [\#129](https://github.com/auth0/laravel-auth0/issues/129) - Redirect to previous page after login [\#122](https://github.com/auth0/laravel-auth0/issues/122) - Auth0User uses private variables so they cannot be accessed or overridden in child class [\#120](https://github.com/auth0/laravel-auth0/issues/120) @@ -89,9 +124,11 @@ - OnLogin callback question [\#97](https://github.com/auth0/laravel-auth0/issues/97) **Added** + - Add composer.lock file [\#123](https://github.com/auth0/laravel-auth0/pull/123) ([lbalmaceda](https://github.com/lbalmaceda)) **Changed** + - Change private properties to protected [\#132](https://github.com/auth0/laravel-auth0/pull/132) ([joshcanhelp](https://github.com/joshcanhelp)) - Return null instead of false in Auth0UserProvider. [\#128](https://github.com/auth0/laravel-auth0/pull/128) ([afreakk](https://github.com/afreakk)) - Change the visibility of the getter method from private to public [\#121](https://github.com/auth0/laravel-auth0/pull/121) ([irieznykov](https://github.com/irieznykov)) @@ -99,29 +136,36 @@ - Changed arrays to use short array syntax [\#110](https://github.com/auth0/laravel-auth0/pull/110) ([dmyers](https://github.com/dmyers)) **Fixed** + - Fix cachehandler resolving issues [\#131](https://github.com/auth0/laravel-auth0/pull/131) ([deviouspk](https://github.com/deviouspk)) - Added the Auth0Service as a singleton through the classname [\#107](https://github.com/auth0/laravel-auth0/pull/107) ([JCombee](https://github.com/JCombee)) - Fixed typo [\#106](https://github.com/auth0/laravel-auth0/pull/106) ([IvanArjona](https://github.com/IvanArjona)) ## [5.1.0](https://github.com/auth0/laravel-auth0/tree/5.1.0) (2018-03-20) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.0.2...5.1.0) **Closed issues** + - pls change config arg name [\#95](https://github.com/auth0/laravel-auth0/issues/95) **Added** + - AutoDiscovery [\#91](https://github.com/auth0/laravel-auth0/pull/91) ([m1guelpf](https://github.com/m1guelpf)) - Added guzzle options to config to allow for connection options [\#88](https://github.com/auth0/laravel-auth0/pull/88) ([mjmgooch](https://github.com/mjmgooch)) **Changed** + - Change default settings file [\#96](https://github.com/auth0/laravel-auth0/pull/96) ([joshcanhelp](https://github.com/joshcanhelp)) - Utilise Auth0->Login to ensure state validation [\#90](https://github.com/auth0/laravel-auth0/pull/90) ([cocojoe](https://github.com/cocojoe)) **Fixed** + - Make code comments gender neutral [\#98](https://github.com/auth0/laravel-auth0/pull/98) ([devjack](https://github.com/devjack)) - Fix README and CHANGELOG [\#99](https://github.com/auth0/laravel-auth0/pull/99) ([joshcanhelp](https://github.com/joshcanhelp)) ## [5.0.2](https://github.com/auth0/laravel-auth0/tree/5.0.2) (2017-08-30) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.0.1...5.0.2) **Merged pull requests:** @@ -129,11 +173,13 @@ - Use instead of to identify the Auth0 user [\#80](https://github.com/auth0/laravel-auth0/pull/80) ([glena](https://github.com/glena)) ## [5.0.1](https://github.com/auth0/laravel-auth0/tree/5.0.1) (2017-02-23) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.0.0...5.0.1) Fixed `supported_algs` configuration name ## [5.0.0](https://github.com/auth0/laravel-auth0/tree/5.0.0) (2017-02-22) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.8...5.0.0) **Merged pull requests:** @@ -141,6 +187,7 @@ Fixed `supported_algs` configuration name - V5: update to auth0 sdk v5 [\#69](https://github.com/auth0/laravel-auth0/pull/69) ([glena](https://github.com/glena)) ## [4.0.8](https://github.com/auth0/laravel-auth0/tree/4.0.8) (2017-01-27) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.7...4.0.8) **Closed issues** @@ -153,6 +200,7 @@ Fixed `supported_algs` configuration name - allow to configure the algorithm supported for token verification [\#65](https://github.com/auth0/laravel-auth0/pull/65) ([glena](https://github.com/glena)) ## [4.0.7](https://github.com/auth0/laravel-auth0/tree/4.0.7) (2017-01-02) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.6...4.0.7) **Merged pull requests:** @@ -160,6 +208,7 @@ Fixed `supported_algs` configuration name - it should pass all the configs to the oauth client [\#64](https://github.com/auth0/laravel-auth0/pull/64) ([glena](https://github.com/glena)) ## [4.0.6](https://github.com/auth0/laravel-auth0/tree/4.0.6) (2016-11-29) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.5...4.0.6) **Merged pull requests:** @@ -168,6 +217,7 @@ Fixed `supported_algs` configuration name - Adding accessor to retrieve JWT from Auth0Service [\#58](https://github.com/auth0/laravel-auth0/pull/58) ([ryantology](https://github.com/ryantology)) ## [4.0.5](https://github.com/auth0/laravel-auth0/tree/4.0.5) (2016-11-29) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.4...4.0.5) **Merged pull requests:** @@ -175,6 +225,7 @@ Fixed `supported_algs` configuration name - Added flag for not encoded tokens + removed example [\#57](https://github.com/auth0/laravel-auth0/pull/57) ([glena](https://github.com/glena)) ## [4.0.4](https://github.com/auth0/laravel-auth0/tree/4.0.4) (2016-11-25) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.2...4.0.4) **Merged pull requests:** @@ -182,6 +233,7 @@ Fixed `supported_algs` configuration name - Fixing config type [\#55](https://github.com/auth0/laravel-auth0/pull/55) ([adamgoose](https://github.com/adamgoose)) ## [4.0.2](https://github.com/auth0/laravel-auth0/tree/4.0.2) (2016-10-03) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.1...4.0.2) **Merged pull requests:** @@ -189,6 +241,7 @@ Fixed `supported_algs` configuration name - Fixing JWTVerifier [\#54](https://github.com/auth0/laravel-auth0/pull/54) ([adamgoose](https://github.com/adamgoose)) ## [4.0.1](https://github.com/auth0/laravel-auth0/tree/4.0.1) (2016-09-19) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.0...4.0.1) **Merged pull requests:** @@ -196,6 +249,7 @@ Fixed `supported_algs` configuration name - fix error becuase of contract and class with the same name [\#52](https://github.com/auth0/laravel-auth0/pull/52) ([glena](https://github.com/glena)) ## [4.0.0](https://github.com/auth0/laravel-auth0/tree/4.0.0) (2016-09-15) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.2.1...4.0.0) Better support for Laravel 5.3: Support for Laravel Passport for token verification @@ -206,6 +260,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - Merge pull request #50 from auth0/4.x.x-dev [\#50](https://github.com/auth0/laravel-auth0/pull/50) ([glena](https://github.com/glena)) ## [3.2.1](https://github.com/auth0/laravel-auth0/tree/3.2.1) (2016-09-12) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.2.0...3.2.1) **Merged pull requests:** @@ -213,6 +268,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - Fix for Laravel 5.2 [\#49](https://github.com/auth0/laravel-auth0/pull/49) ([dscafati](https://github.com/dscafati)) ## [3.2.0](https://github.com/auth0/laravel-auth0/tree/3.2.0) (2016-07-11) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.1.0...3.2.0) **Merged pull requests:** @@ -220,6 +276,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - New optional jwt middleware [\#40](https://github.com/auth0/laravel-auth0/pull/40) ([glena](https://github.com/glena)) ## [3.1.0](https://github.com/auth0/laravel-auth0/tree/3.1.0) (2016-05-02) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.3...3.1.0) **Merged pull requests:** @@ -227,6 +284,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - 3.1.0 [\#36](https://github.com/auth0/laravel-auth0/pull/36) ([glena](https://github.com/glena)) ## [3.0.3](https://github.com/auth0/laravel-auth0/tree/3.0.3) (2016-01-28) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.2...3.0.3) **Closed issues:** @@ -238,6 +296,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - Conform to 5.2's Authenticatable contract [\#31](https://github.com/auth0/laravel-auth0/pull/31) ([ryannjohnson](https://github.com/ryannjohnson)) ## [3.0.2](https://github.com/auth0/laravel-auth0/tree/3.0.2) (2016-01-25) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.2.1...3.0.2) **Merged pull requests:** @@ -245,6 +304,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - Added optional persistence configuration values [\#29](https://github.com/auth0/laravel-auth0/pull/29) ([carnevalle](https://github.com/carnevalle)) ## [2.2.1](https://github.com/auth0/laravel-auth0/tree/2.2.1) (2016-01-22) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.1...2.2.1) **Closed issues:** @@ -256,6 +316,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - Auth0 SDK checks for null values instead of false [\#27](https://github.com/auth0/laravel-auth0/pull/27) ([thijsvdanker](https://github.com/thijsvdanker)) ## [3.0.1](https://github.com/auth0/laravel-auth0/tree/3.0.1) (2016-01-18) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.0...3.0.1) **Merged pull requests:** @@ -263,6 +324,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - updated auth0-php dependency [\#24](https://github.com/auth0/laravel-auth0/pull/24) ([glena](https://github.com/glena)) ## [3.0.0](https://github.com/auth0/laravel-auth0/tree/3.0.0) (2016-01-06) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.2.0...3.0.0) **Closed issues:** @@ -274,6 +336,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - updated to be compatible with laravel 5.2 [\#23](https://github.com/auth0/laravel-auth0/pull/23) ([glena](https://github.com/glena)) ## [2.2.0](https://github.com/auth0/laravel-auth0/tree/2.2.0) (2015-11-30) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.4...2.2.0) **Merged pull requests:** @@ -282,6 +345,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - Update login.blade.php [\#20](https://github.com/auth0/laravel-auth0/pull/20) ([Annyv2](https://github.com/Annyv2)) ## [2.1.4](https://github.com/auth0/laravel-auth0/tree/2.1.4) (2015-10-27) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.3...2.1.4) **Merged pull requests:** @@ -293,6 +357,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - Use a tagged release of adoy/oauth2 [\#15](https://github.com/auth0/laravel-auth0/pull/15) ([thijsvdanker](https://github.com/thijsvdanker)) ## [2.1.3](https://github.com/auth0/laravel-auth0/tree/2.1.3) (2015-07-17) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.2...2.1.3) **Merged pull requests:** @@ -300,6 +365,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - updated jwt dependency [\#14](https://github.com/auth0/laravel-auth0/pull/14) ([glena](https://github.com/glena)) ## [2.1.2](https://github.com/auth0/laravel-auth0/tree/2.1.2) (2015-05-15) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.1...2.1.2) **Merged pull requests:** @@ -307,6 +373,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - Added override of info headers [\#13](https://github.com/auth0/laravel-auth0/pull/13) ([glena](https://github.com/glena)) ## [2.1.1](https://github.com/auth0/laravel-auth0/tree/2.1.1) (2015-05-12) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.0...2.1.1) **Closed issues:** @@ -319,6 +386,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - SDK Client headers spec compliant \#11 [\#12](https://github.com/auth0/laravel-auth0/pull/12) ([glena](https://github.com/glena)) ## [2.1.0](https://github.com/auth0/laravel-auth0/tree/2.1.0) (2015-05-07) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.0.0...2.1.0) **Merged pull requests:** @@ -326,6 +394,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - Upgrade to auth-php 1.0.0: Added support to API V2 [\#10](https://github.com/auth0/laravel-auth0/pull/10) ([glena](https://github.com/glena)) ## [2.0.0](https://github.com/auth0/laravel-auth0/tree/2.0.0) (2015-04-20) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.8...2.0.0) **Merged pull requests:** @@ -333,9 +402,11 @@ Support of auth0 PHP sdk v4 with JWKs cache - Package V2 for Laravel5 [\#9](https://github.com/auth0/laravel-auth0/pull/9) ([glena](https://github.com/glena)) ## [1.0.8](https://github.com/auth0/laravel-auth0/tree/1.0.8) (2015-04-14) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.7...1.0.8) ## [1.0.7](https://github.com/auth0/laravel-auth0/tree/1.0.7) (2015-04-13) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.6...1.0.7) **Merged pull requests:** @@ -344,9 +415,11 @@ Support of auth0 PHP sdk v4 with JWKs cache - Update README.md [\#5](https://github.com/auth0/laravel-auth0/pull/5) ([pose](https://github.com/pose)) ## [1.0.6](https://github.com/auth0/laravel-auth0/tree/1.0.6) (2014-08-01) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.5...1.0.6) ## [1.0.5](https://github.com/auth0/laravel-auth0/tree/1.0.5) (2014-08-01) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.4...1.0.5) **Closed issues:** @@ -358,6 +431,7 @@ Support of auth0 PHP sdk v4 with JWKs cache - Update README.md [\#3](https://github.com/auth0/laravel-auth0/pull/3) ([patekuru](https://github.com/patekuru)) ## [1.0.4](https://github.com/auth0/laravel-auth0/tree/1.0.4) (2014-05-07) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.3...1.0.4) ## [1.0.3](https://github.com/auth0/laravel-auth0/tree/1.0.3) (2014-04-21) From d51f7fe079ad5b862accdd61a32b7d74cc10d9d2 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 15 Jan 2021 00:15:42 -0500 Subject: [PATCH 028/525] Only mark stale if waiting for response --- .github/stale.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/stale.yml b/.github/stale.yml index b2e13fc7..bf9b1cf4 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,13 +1,14 @@ # Configuration for probot-stale - https://github.com/probot/stale # Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 90 +daysUntilStale: 120 # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. -daysUntilClose: 7 +daysUntilClose: 21 -# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable -exemptLabels: [] +# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) +onlyLabels: + - 'Waiting for Response' # Set to true to ignore issues with an assignee (defaults to false) exemptAssignees: true @@ -17,4 +18,4 @@ staleLabel: closed:stale # Comment to post when marking as stale. Set to `false` to disable markComment: > - This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you have not received a response for our team (apologies for the delay) and this is still a blocker, please reply with additional information or just a ping. Thank you for your contribution! 🙇‍♂️ \ No newline at end of file + This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you have not received a response for our team (apologies for the delay) and this is still a blocker, please reply with additional information or just a ping. Thank you for your contribution! 🙇‍♂️ From 7deed6da1489f58c4adbd16c2af442486ddc2c58 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 16 Feb 2021 16:50:53 -0500 Subject: [PATCH 029/525] feat: Allow updating user metadata during onLogin event hook --- src/Auth0/Login/Auth0Service.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Auth0/Login/Auth0Service.php b/src/Auth0/Login/Auth0Service.php index 7845eb94..40b17c60 100644 --- a/src/Auth0/Login/Auth0Service.php +++ b/src/Auth0/Login/Auth0Service.php @@ -152,7 +152,11 @@ public function hasOnLogin() */ public function callOnLogin($auth0User) { - return call_user_func($this->_onLoginCb, $auth0User); + $user = call_user_func($this->_onLoginCb, $auth0User); + + $this->getSDK()->setUser($user); + + return $user; } /** From 1ab914abc04241bc7a6746415d42a62ee558ea84 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 16 Feb 2021 18:10:54 -0500 Subject: [PATCH 030/525] fix: Avoid throwing an error when calling getUserByUserInfo() during login callback event when the supplied profile is empty/null --- src/controllers/Auth0Controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/Auth0Controller.php b/src/controllers/Auth0Controller.php index f7e2a25f..b097115d 100644 --- a/src/controllers/Auth0Controller.php +++ b/src/controllers/Auth0Controller.php @@ -35,7 +35,7 @@ public function callback() $profile = $service->getUser(); // Get the user related to the profile - $auth0User = $this->userRepository->getUserByUserInfo($profile); + $auth0User = $profile ? $this->userRepository->getUserByUserInfo($profile) : null; if ($auth0User) { // If we have a user, we are going to log them in, but if From 1b754c6d9b7266de411e901260523fed18aa29e5 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 19 Feb 2021 07:55:45 -0500 Subject: [PATCH 031/525] Release 6.3.0 (#208) --- CHANGELOG.md | 12 ++++++++++++ src/Auth0/Login/LoginServiceProvider.php | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7da0c3fd..b553b0d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Change Log +## [6.3.0](https://github.com/auth0/laravel-auth0/tree/6.3.0) (2020-02-18) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.2.0...6.3.0) + +**Changed** + +- Store changes made to the user object during the onLogin event hook [\#206](https://github.com/auth0/laravel-auth0/pull/206) ([evansims](https://github.com/evansims)) + +**Fixed** + +- Avoid throwing an error when calling getUserByUserInfo() during login callback event when the supplied profile is empty/null [\#207](https://github.com/auth0/laravel-auth0/pull/207) ([evansims](https://github.com/evansims)) + ## [6.2.0](https://github.com/auth0/laravel-auth0/tree/6.2.0) (2020-01-15) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.1.0...6.2.0) diff --git a/src/Auth0/Login/LoginServiceProvider.php b/src/Auth0/Login/LoginServiceProvider.php index 6bc9e3e6..e1789824 100644 --- a/src/Auth0/Login/LoginServiceProvider.php +++ b/src/Auth0/Login/LoginServiceProvider.php @@ -14,7 +14,7 @@ class LoginServiceProvider extends ServiceProvider { - const SDK_VERSION = '6.2.0'; + const SDK_VERSION = '6.3.0'; /** * Bootstrap the application events. From 24a4c6bd283d379edafc829ce505f566e5782afe Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 25 Mar 2021 10:41:44 -0400 Subject: [PATCH 032/525] [SDK-2375] Add Organizations Support (#209) * chore: Bump Auth0 PHP SDK dependency to 7.7 for Organizations support * feat: Add 'organization' option to config * feat: Expose handleInvitation() and getInvitationParameters() from Auth0 PHP SDK in Auth0 Laravel service * docs: Update README to include Organizations usage examples --- README.md | 80 ++++++++++++++++++++++++++++++++ composer.json | 2 +- src/Auth0/Login/Auth0Service.php | 16 +++++++ src/config/config.php | 9 ++++ 4 files changed, 106 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6585669e..f39872ea 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,86 @@ auth('auth0')->check(); Route::group(['middleware' => 'auth:auth0'], function () {}); ``` +## Examples + +### Organizations (Closed Beta) + +Organizations is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications. + +Using Organizations, you can: + +- Represent teams, business customers, partner companies, or any logical grouping of users that should have different ways of accessing your applications, as organizations. +- Manage their membership in a variety of ways, including user invitation. +- Configure branded, federated login flows for each organization. +- Implement role-based access control, such that users can have different roles when authenticating in the context of different organizations. +- Build administration capabilities into your products, using Organizations APIs, so that those businesses can manage their own organizations. + +Note that Organizations is currently only available to customers on our Enterprise and Startup subscription plans. + +#### Logging in with an Organization + +Open your Auth0 Laravel plugin configuration file (usually `config/laravel-auth0.php`) uncomment the `organization` optiion and specify the Id for your Organization (found in your Organization settings on the Auth0 Dashboard.) + +```php +// config/laravel-auth0.php +// ... + +/* +|-------------------------------------------------------------------------- +| Auth0 Organizations +|-------------------------------------------------------------------------- +| organization (string) Optional. Id of an Organization, if being used. Used when generating log in urls and validating token claims. +*/ + +'organization' => 'org_E6WbrPMQU2UJn6Rz', +``` + +From there, the Organization will automatically be used throughout your Laravel application's authentication login, including redirecting to the Universal Login page. + +```php +// Expects the Laravel plugin to be configured first, as demonstrated above. + +App::make('auth0')->login(); +``` + +#### Accepting user invitations + +Auth0 Organizations allow users to be invited using emailed links, which will direct a user back to your application. The URL the user will arrive at is based on your configured `Application Login URI`, which you can change from your Application's settings inside the Auth0 dashboard. + +When the user arrives at your application using an invite link, you can expect three query parameters to be provided: `invitation`, `organization`, and `organization_name`. These will always be delivered using a GET request. + +A helper function is provided to handle extracting these query parameters and automatically redirecting to the Universal Login page. Invoke this from your application's logic, such as a controller for an authentication route, to handle this process automatically. + +```php +// routes/example.php + +Route::get('/invite', [ExampleIndexController::class, 'invite'])->name('invite'); +``` + +```php +// Http/Controllers/Example/ExampleIndexController.php + +handleInvitation(); + } + +``` + ## Installation Install this plugin into a new or existing project using [Composer](https://getcomposer.org/doc/00-intro.md): diff --git a/composer.json b/composer.json index 5e2d1109..328629f5 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "php": "^7.3 | ^8.0", "ext-json": "*", "ext-openssl": "*", - "auth0/auth0-php": "^7.6", + "auth0/auth0-php": "^7.7", "illuminate/support": " ^6.0 | ^7.0 | ^8.0", "illuminate/contracts": "^6.0 | ^7.0 | ^8.0" }, diff --git a/src/Auth0/Login/Auth0Service.php b/src/Auth0/Login/Auth0Service.php index 40b17c60..f0f50a69 100644 --- a/src/Auth0/Login/Auth0Service.php +++ b/src/Auth0/Login/Auth0Service.php @@ -106,6 +106,22 @@ public function login($connection = null, $state = null, $additional_params = [' return new RedirectResponse($auth_url); } + /** + * If invitation parameters are present in the request, handle extraction and automatically redirect to Universal Login. + */ + public function handleInvitation() + { + $this->getSDK()->handleInvitation(); + } + + /** + * Extract invitation details from any incoming GET request. + */ + public function getInvitationParameters() + { + return $this->getSDK()->getInvitationParameters(); + } + /** * If the user is logged in, returns the user information. * diff --git a/src/config/config.php b/src/config/config.php index 567baca8..b3facc05 100644 --- a/src/config/config.php +++ b/src/config/config.php @@ -62,6 +62,15 @@ */ // 'api_identifier' => '', + + /* + |-------------------------------------------------------------------------- + | Auth0 Organizations + |-------------------------------------------------------------------------- + | organization (string) Optional. Id of an Organization, if being used. Used when generating log in urls and validating token claims. + */ + // 'organization' => '', + /* |-------------------------------------------------------------------------- | The secret format From 41eba218f0a7bd00e5ff50b0446a2e7ed9e474bd Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 25 Mar 2021 18:17:00 -0400 Subject: [PATCH 033/525] Release 6.4.0 (#210) * docs: Update CHANGELOG for 6.4 * chore: Bump SDK version to 6.4.0 --- CHANGELOG.md | 8 ++++++++ src/Auth0/Login/LoginServiceProvider.php | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b553b0d4..8b014525 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## [6.4.0](https://github.com/auth0/laravel-auth0/tree/6.4.0) (2021-03-25) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.3.0...6.4.0) + +**Changed** + +- Add support for Auth0 Organizations [\#209](https://github.com/auth0/laravel-auth0/pull/209) ([evansims](https://github.com/evansims)) + ## [6.3.0](https://github.com/auth0/laravel-auth0/tree/6.3.0) (2020-02-18) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.2.0...6.3.0) diff --git a/src/Auth0/Login/LoginServiceProvider.php b/src/Auth0/Login/LoginServiceProvider.php index e1789824..b785f340 100644 --- a/src/Auth0/Login/LoginServiceProvider.php +++ b/src/Auth0/Login/LoginServiceProvider.php @@ -14,7 +14,7 @@ class LoginServiceProvider extends ServiceProvider { - const SDK_VERSION = '6.3.0'; + const SDK_VERSION = '6.4.0'; /** * Bootstrap the application events. From ad6af7d5f71179374004681edc4c2e44753fa4a2 Mon Sep 17 00:00:00 2001 From: Adam Mcgrath Date: Thu, 8 Apr 2021 11:55:02 +0100 Subject: [PATCH 034/525] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f39872ea..8575e6c4 100644 --- a/README.md +++ b/README.md @@ -82,9 +82,9 @@ Route::group(['middleware' => 'auth:auth0'], function () {}); ## Examples -### Organizations (Closed Beta) +### Organizations -Organizations is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications. +[Organizations](https://auth0.com/docs/organizations) is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications. Using Organizations, you can: From 99153352a9901daef2f2822f97da28bb0d669b0e Mon Sep 17 00:00:00 2001 From: Ilyas Serter Date: Mon, 26 Apr 2021 02:01:15 +0300 Subject: [PATCH 035/525] Pass api_identifier config as audience to Auth0\SDK\Auth0 (#214) --- src/Auth0/Login/Auth0Service.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Auth0/Login/Auth0Service.php b/src/Auth0/Login/Auth0Service.php index f0f50a69..b61598dd 100644 --- a/src/Auth0/Login/Auth0Service.php +++ b/src/Auth0/Login/Auth0Service.php @@ -66,6 +66,11 @@ public function __construct( $auth0Config['cache_handler'] = $cache; + if(isset($auth0Config['api_identifier'])) { + // Auth0\SDK\Auth0 is using `audience` to create a login link. + $auth0Config['audience'] = $auth0Config['api_identifier']; + } + $this->auth0Config = $auth0Config; $this->auth0 = new Auth0($auth0Config); } From 48b5b0ce96f028e9408246e61f4093de0e7d7388 Mon Sep 17 00:00:00 2001 From: Rezouce Date: Fri, 30 Apr 2021 05:22:07 +0200 Subject: [PATCH 036/525] =?UTF-8?q?Remove=20the=20facade=20aliases=20usage?= =?UTF-8?q?=20since=20they=20can=20be=20removed/changed=20fro=E2=80=A6=20(?= =?UTF-8?q?#215)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove the facade aliases usage since they can be removed/changed from the Laravel configuration which will make impossible to install and use the plugin. * Import the facade using use statements and use the app function to avoid having the full classname. * Update PHPStan configuration to ignore the Event::listen error since we're not using the alias anymore --- phpstan.neon | 1 - src/Auth0/Login/LoginServiceProvider.php | 18 ++++++++++-------- .../Login/Repository/Auth0UserRepository.php | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 5cc39852..0bb82baa 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,7 +2,6 @@ parameters: checkGenericClassInNonGenericObjectType: false level: 2 ignoreErrors: - - '#Call to an undefined static method Event::listen#' - '#Call to static method#' paths: - src diff --git a/src/Auth0/Login/LoginServiceProvider.php b/src/Auth0/Login/LoginServiceProvider.php index b785f340..b5f65987 100644 --- a/src/Auth0/Login/LoginServiceProvider.php +++ b/src/Auth0/Login/LoginServiceProvider.php @@ -9,6 +9,8 @@ use Auth0\SDK\Store\StoreInterface; use Illuminate\Auth\RequestGuard; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Event; use Illuminate\Support\ServiceProvider; class LoginServiceProvider extends ServiceProvider @@ -21,11 +23,11 @@ class LoginServiceProvider extends ServiceProvider */ public function boot() { - \Auth::provider('auth0', function ($app, array $config) { + Auth::provider('auth0', function ($app, array $config) { return $app->make(Auth0UserProvider::class); }); - \Auth::extend('auth0', function ($app, $name, $config) { + Auth::extend('auth0', function ($app, $name, $config) { return new RequestGuard(function (Request $request, Auth0UserProvider $provider) { return $provider->retrieveByCredentials(['api_token' => $request->bearerToken()]); }, $app['request'], $app['auth']->createUserProvider($config['provider'])); @@ -73,14 +75,14 @@ public function register() }); // When Laravel logs out, logout the auth0 SDK trough the service - \Event::listen('auth.logout', function () { - \App::make('auth0')->logout(); + Event::listen('auth.logout', function () { + app('auth0')->logout(); }); - \Event::listen('user.logout', function () { - \App::make('auth0')->logout(); + Event::listen('user.logout', function () { + app('auth0')->logout(); }); - \Event::listen('Illuminate\Auth\Events\Logout', function () { - \App::make('auth0')->logout(); + Event::listen('Illuminate\Auth\Events\Logout', function () { + app('auth0')->logout(); }); } } diff --git a/src/Auth0/Login/Repository/Auth0UserRepository.php b/src/Auth0/Login/Repository/Auth0UserRepository.php index 8a0dc7a7..a71d75f3 100644 --- a/src/Auth0/Login/Repository/Auth0UserRepository.php +++ b/src/Auth0/Login/Repository/Auth0UserRepository.php @@ -37,7 +37,7 @@ public function getUserByUserInfo(array $userInfo) : Authenticatable public function getUserByIdentifier($identifier) : ?Authenticatable { // Get the user info of the user logged in (probably in session) - $user = \App::make('auth0')->getUser(); + $user = app('auth0')->getUser(); if ($user === null) { return null; From 8377bd09644de60d5a8688653589ea299ccd2969 Mon Sep 17 00:00:00 2001 From: tomdot <82123860+tomdot-dev@users.noreply.github.com> Date: Tue, 25 May 2021 03:47:48 +0200 Subject: [PATCH 037/525] Fixed typo in README.md (#217) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8575e6c4..2f6ea71c 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ Note that Organizations is currently only available to customers on our Enterpri #### Logging in with an Organization -Open your Auth0 Laravel plugin configuration file (usually `config/laravel-auth0.php`) uncomment the `organization` optiion and specify the Id for your Organization (found in your Organization settings on the Auth0 Dashboard.) +Open your Auth0 Laravel plugin configuration file (usually `config/laravel-auth0.php`) uncomment the `organization` option and specify the Id for your Organization (found in your Organization settings on the Auth0 Dashboard.) ```php // config/laravel-auth0.php From 3ed13e0f6a2808bec6de69e7724a68f434154995 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 27 Jul 2021 09:59:11 -0400 Subject: [PATCH 038/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f6ea71c..89cefb00 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Laravel Auth0 Plugin -[![CircleCI](https://img.shields.io/circleci/project/github/auth0/laravel-auth0/master.svg)](https://circleci.com/gh/auth0/laravel-auth0) +[![CircleCI](https://img.shields.io/circleci/project/github/auth0/laravel-auth0/main.svg)](https://circleci.com/gh/auth0/laravel-auth0) [![Latest Stable Version](https://poser.pugx.org/auth0/login/v/stable)](https://packagist.org/packages/auth0/login) [![License](https://poser.pugx.org/auth0/login/license)](https://packagist.org/packages/auth0/login) [![Total Downloads](https://poser.pugx.org/auth0/login/downloads)](https://packagist.org/packages/auth0/login) From ac6047686d264b94c37d83e2cecd3191be5d95fd Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 2 Aug 2021 15:27:56 -0400 Subject: [PATCH 039/525] Update to latest auth0-PHP dependency (#222) --- .circleci/config.yml | 156 +++++++--- .phpcs-compat.xml.dist | 16 - .phpcs.xml.dist | 276 +++++++++++------- composer.json | 70 +++-- docker-compose.yml | 25 ++ phpstan.neon | 9 +- src/Auth0/Login/Auth0JWTUser.php | 2 + src/Auth0/Login/Auth0Service.php | 39 +-- src/Auth0/Login/Auth0User.php | 4 +- src/Auth0/Login/Auth0UserProvider.php | 12 +- .../Login/Contract/Auth0UserRepository.php | 10 +- src/Auth0/Login/LaravelSessionStore.php | 4 +- src/Auth0/Login/LoginServiceProvider.php | 21 +- .../Login/Repository/Auth0UserRepository.php | 14 +- src/config/config.php | 122 ++++---- src/controllers/Auth0Controller.php | 2 + src/facade/Auth0.php | 2 + ...rviceUnitTest.php => Auth0ServiceTest.php} | 6 +- 18 files changed, 487 insertions(+), 303 deletions(-) delete mode 100644 .phpcs-compat.xml.dist create mode 100644 docker-compose.yml rename tests/Unit/{Auth0ServiceUnitTest.php => Auth0ServiceTest.php} (93%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6e103b87..69889510 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,12 +4,31 @@ commands: prepare: steps: - checkout - - run: sudo composer self-update - - restore_cache: - keys: - - composer-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "composer.json" }} - - composer-v1-{{ .Environment.CIRCLE_JOB }} - - run: composer update --prefer-dist --no-interaction + - run: + name: Perform composer self-update + command: sudo composer self-update + - restore-cache + - run: + name: Enable code coverage + command: | + sudo apt update + sudo apt install libonig-dev + sudo pecl install pcov + sudo docker-php-ext-enable pcov + sudo rm /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini + sudo docker-php-ext-install posix + sudo docker-php-ext-install pcntl + sudo docker-php-ext-install mbstring + - run: + name: Install composer dependencies + command: composer install --no-interaction --prefer-dist + - run: + name: Update composer dependencies + command: composer update --prefer-dist --no-interaction + - save-cache + + save-cache: + steps: - persist_to_workspace: root: . paths: @@ -19,42 +38,55 @@ commands: key: composer-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "composer.json" }} paths: - vendor - run-php-compatibility: - steps: - - run: composer compat - run-static-analysis: + + restore-cache: steps: - - run: composer analyze - run-unit-tests: + - restore_cache: + keys: + - composer-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "composer.json" }} + - composer-v1-{{ .Environment.CIRCLE_JOB }} + + run-php-codesniffer: steps: - - run: composer test - - store_artifacts: - path: build/coverage.xml + - run: + name: Run code quality analysis (PHP CodeSniffer) + command: php ./vendor/bin/phpcs -jobs: - php_7_3: - docker: - - image: circleci/php:7.3 + run-phpstan: steps: - - prepare - - run-php-compatibility - - run-static-analysis - - run-unit-tests - php_7_4: - docker: - - image: circleci/php:7.4 + - run: + name: Run static code analysis (PHPStan) + command: php ./vendor/bin/phpstan analyze + + run-phpunit: steps: - - prepare - - run-static-analysis - - run-unit-tests - php_8_0: + - run: + name: Run unit tests (PHPUnit) + command: php ./vendor/bin/phpunit --stop-on-failure --coverage-clover=build/coverage/coverage.xml --coverage-xml=build/coverage/coverage-xml --log-junit=build/coverage/junit.xml + - persist_to_workspace: + root: . + paths: + - src + - tests + - infection.json.dist + - phpunit.xml.dist + - build + - vendor + +jobs: + run-unit-tests: + parameters: + php: + type: string docker: - - image: circleci/php:8.0 + - image: circleci/php:<< parameters.php >> steps: - prepare - - run-static-analysis - - run-unit-tests - snyk: + - run-php-codesniffer + - run-phpstan + - run-phpunit + + run-security-tests: docker: - image: snyk/snyk-cli:composer steps: @@ -62,20 +94,52 @@ jobs: at: . - run: snyk test - run: - command: | - if [[ "${CIRCLE_BRANCH}" == "master" ]] - then - snyk monitor --org=auth0-sdks --project-name=laravel-auth0 - fi + command: snyk monitor --org=auth0-sdks --project-name=laravel-auth0 when: always + run-codecov-uploader: + docker: + - image: circleci/php:7.4 + steps: + - attach_workspace: + at: . + - restore-cache + - run: + name: Download and validate Codecov uploader + command: | + curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --import + curl -Os https://uploader.codecov.io/latest/linux/codecov + curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM + curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM.sig + gpg --verify codecov.SHA256SUM.sig codecov.SHA256SUM + shasum -a 256 -c codecov.SHA256SUM + chmod +x codecov + - run: + name: Upload coverage reports to Codecov + command: ./codecov -t ${CODECOV_TOKEN} -f ./build/coverage/coverage.xml + workflows: - build-and-test: + run-tests: jobs: - - php_7_3 - - php_7_4 - - php_8_0 - - snyk: + - run-unit-tests: + name: run-phpunit-7.3 + php: "7.3" + - run-unit-tests: + name: run-phpunit-7.4 + php: "7.4" + - run-unit-tests: + name: run-phpunit-8.0 + php: "8.0" + - run-security-tests: + filters: + branches: + only: + - main context: snyk-env - requires: - - php_7_3 + requires: [run-phpunit-7.3] + - run-codecov-uploader: + filters: + branches: + only: + - main + requires: [run-phpunit-7.4] diff --git a/.phpcs-compat.xml.dist b/.phpcs-compat.xml.dist deleted file mode 100644 index 816c94c8..00000000 --- a/.phpcs-compat.xml.dist +++ /dev/null @@ -1,16 +0,0 @@ - - - PHPCompatibility check for Auth0 Laravel SDK - ./src - - - - - - - - - diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index b5f52d09..8a537ea2 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -1,118 +1,188 @@ - - - A custom coding standard for the Laravel Auth0 package + + Auth0 PHP coding standard - ./src + + src - - + + vendor/ - - - - + - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - tests/*\.php + + + error - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/composer.json b/composer.json index 328629f5..29408206 100644 --- a/composer.json +++ b/composer.json @@ -1,37 +1,51 @@ { "name": "auth0/login", "description": "Laravel plugin that helps authenticate with the Auth0 service", + "type": "library", + "keywords": [ + "laravel", + "auth0", + "authentication", + "authorization", + "login", + "auth", + "jwt", + "json web token", + "jwk", + "json web key", + "oauth", + "openid", + "secure", + "protect", + "api" + ], + "homepage": "https://github.com/auth0/laravel-auth0", "license": "MIT", + "authors": [ + { + "name": "Auth0", + "email": "support@auth0.com", + "homepage": "https://auth0.com/" + } + ], "require": { - "php": "^7.3 | ^8.0", + "php": "^7.3 || ^8.0", "ext-json": "*", "ext-openssl": "*", - "auth0/auth0-php": "^7.7", - "illuminate/support": " ^6.0 | ^7.0 | ^8.0", - "illuminate/contracts": "^6.0 | ^7.0 | ^8.0" + "ext-filter": "*", + "ext-mbstring": "*", + "auth0/auth0-php": "^7.9", + "illuminate/support": " ^6.0 || ^7.0 || ^8.0", + "illuminate/contracts": "^6.0 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^9.3", - "squizlabs/php_codesniffer": "^3.2", - "phpcompatibility/php-compatibility": "^8.1", - "dealerdirect/phpcodesniffer-composer-installer": "^0.7", - "orchestra/testbench": "^4.0 | ^5.0", - "nunomaduro/larastan": "^0.6.11" + "nunomaduro/phpinsights": "^1.13 || ^2.0", + "phpunit/phpunit": "^9.5", + "orchestra/testbench": "^4.0 || ^5.0", + "nunomaduro/larastan": "^0.7" }, - "scripts": { - "test": "SHELL_INTERACTIVE=1 \"./vendor/bin/phpunit\" --coverage-text ", - "analyze": "@php ./vendor/bin/phpstan analyze", - "compat": "@php ./vendor/bin/phpcs --standard=.phpcs-compat.xml.dist", - "format": "@php ./vendor/bin/phpcbf", - "lint": "@php ./vendor/bin/phpcs", - "sniffs": "@php ./vendor/bin/phpcs -e", - "config-phpcs": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run", - "pre-commit": [ - "@analyze", - "@test", - "@format", - "@compat" - ] + "conflict": { + "lcobucci/jwt": "*" }, "autoload": { "classmap": [ @@ -56,5 +70,13 @@ "Auth0": "Auth0\\Login\\Facade\\Auth0" } } + }, + "config": { + "optimize-autoloader": true, + "sort-packages": true + }, + "scripts": { + "format": "docker compose run --rm format", + "tests": "docker compose run --rm tests" } } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..9da6c4c8 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +version: "3.9" + +services: + tests: + image: composer:2.1 + volumes: + - ./:/app + working_dir: /app + command: > + sh -c "rm -f ./composer.lock && + composer validate && + composer install && + php ./vendor/bin/phpstan analyze --ansi --debug --memory-limit 512M && + php ./vendor/bin/phpunit --coverage-text && + php ./vendor/bin/phpcs" + + format: + image: composer:2.1 + volumes: + - ./:/app + working_dir: /app + command: > + sh -c "rm -f ./composer.lock && + composer install && + php ./vendor/bin/phpcbf" diff --git a/phpstan.neon b/phpstan.neon index 0bb82baa..56a236c5 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,7 +1,10 @@ parameters: - checkGenericClassInNonGenericObjectType: false level: 2 - ignoreErrors: - - '#Call to static method#' + paths: - src + + ignoreErrors: + - '#Call to static method#' + + reportUnmatchedIgnoredErrors: false diff --git a/src/Auth0/Login/Auth0JWTUser.php b/src/Auth0/Login/Auth0JWTUser.php index 6c59ec2d..f242062f 100644 --- a/src/Auth0/Login/Auth0JWTUser.php +++ b/src/Auth0/Login/Auth0JWTUser.php @@ -1,5 +1,7 @@ 'openid profile email'], $response_type = 'code') { - if ($connection && empty( $additional_params['connection'] )) { + if ($connection && ! isset( $additional_params['connection'] )) { $additional_params['connection'] = $connection; } - if ($state && empty( $additional_params['state'] )) { + if ($state && ! isset( $additional_params['state'] )) { $additional_params['state'] = $state; } $additional_params['response_type'] = $response_type; - $auth_url = $this->auth0->getLoginUrl($additional_params); + $auth_url = $this->auth0->getLoginUrl($additional_params); return new RedirectResponse($auth_url); } @@ -155,25 +155,25 @@ public function getUser() */ public function onLogin($cb) { - $this->_onLoginCb = $cb; + $this->onLoginCb = $cb; } /** - * @return boolean + * @return bool */ public function hasOnLogin() { - return $this->_onLoginCb !== null; + return $this->onLoginCb !== null; } /** - * @param Authenticatable $auth0User + * @param \Illuminate\Contracts\Auth\Authenticatable $auth0User * * @return mixed */ public function callOnLogin($auth0User) { - $user = call_user_func($this->_onLoginCb, $auth0User); + $user = call_user_func($this->onLoginCb, $auth0User); $this->getSDK()->setUser($user); @@ -185,7 +185,7 @@ public function callOnLogin($auth0User) * * @param null $value * - * @return boolean|null + * @return bool|null */ public function rememberUser($value = null) { @@ -201,6 +201,7 @@ public function rememberUser($value = null) * @param array $verifierOptions * * @return array + * * @throws \Auth0\SDK\Exception\InvalidTokenException */ public function decodeJWT($encUser, array $verifierOptions = []) @@ -210,15 +211,15 @@ public function decodeJWT($encUser, array $verifierOptions = []) $idTokenAlg = $this->auth0Config['supported_algs'][0] ?? 'RS256'; $signature_verifier = null; - if ('RS256' === $idTokenAlg) { + if ($idTokenAlg === 'RS256') { $jwksUri = $this->auth0Config['jwks_uri'] ?? 'https://'.$this->auth0Config['domain'].'/.well-known/jwks.json'; $jwks_fetcher = new JWKFetcher($this->auth0Config['cache_handler']); $jwks = $jwks_fetcher->getKeys($jwksUri); $signature_verifier = new AsymmetricVerifier($jwks); - } else if ('HS256' === $idTokenAlg) { + } elseif ($idTokenAlg === 'HS256') { $signature_verifier = new SymmetricVerifier($this->auth0Config['client_secret']); } else { - throw new InvalidTokenException('Unsupported token signing algorithm configured. Must be either RS256 or HS256.'); + throw new \Auth0\SDK\Exception\InvalidTokenException('Unsupported token signing algorithm configured. Must be either RS256 or HS256.'); } // Use IdTokenVerifier since Auth0-issued JWTs contain the 'sub' claim, which is used by the Laravel user model diff --git a/src/Auth0/Login/Auth0User.php b/src/Auth0/Login/Auth0User.php index fa108f9a..6d78295e 100644 --- a/src/Auth0/Login/Auth0User.php +++ b/src/Auth0/Login/Auth0User.php @@ -1,5 +1,7 @@ auth0->decodeJWT($encUser); - } catch (CoreException $e) { + } catch (\Auth0\SDK\Exception\CoreException $e) { return null; - } catch (InvalidTokenException $e) { + } catch (\Auth0\SDK\Exception\InvalidTokenException $e) { return null; } diff --git a/src/Auth0/Login/Contract/Auth0UserRepository.php b/src/Auth0/Login/Contract/Auth0UserRepository.php index 746182a2..92f79740 100644 --- a/src/Auth0/Login/Contract/Auth0UserRepository.php +++ b/src/Auth0/Login/Contract/Auth0UserRepository.php @@ -1,5 +1,7 @@ make(Auth0UserProvider::class); }); - Auth::extend('auth0', function ($app, $name, $config) { - return new RequestGuard(function (Request $request, Auth0UserProvider $provider) { + Auth::extend('auth0', static function ($app, $name, $config) { + return new RequestGuard(static function (Request $request, Auth0UserProvider $provider) { return $provider->retrieveByCredentials(['api_token' => $request->bearerToken()]); }, $app['request'], $app['auth']->createUserProvider($config['provider'])); }); @@ -56,14 +57,14 @@ public function boot() */ public function register() { - $this->app->bind(StoreInterface::class, function () { + $this->app->bind(StoreInterface::class, static function () { return new LaravelSessionStore(); }); $this->app->bind(Auth0UserRepositoryContract::class, Auth0UserRepository::class); // Bind the auth0 name to a singleton instance of the Auth0 Service - $this->app->singleton(Auth0Service::class, function ($app) { + $this->app->singleton(Auth0Service::class, static function ($app) { return new Auth0Service( $app->make('config')->get('laravel-auth0'), $app->make(StoreInterface::class), @@ -75,13 +76,13 @@ public function register() }); // When Laravel logs out, logout the auth0 SDK trough the service - Event::listen('auth.logout', function () { + Event::listen('auth.logout', static function () { app('auth0')->logout(); }); - Event::listen('user.logout', function () { + Event::listen('user.logout', static function () { app('auth0')->logout(); }); - Event::listen('Illuminate\Auth\Events\Logout', function () { + Event::listen('Illuminate\Auth\Events\Logout', static function () { app('auth0')->logout(); }); } diff --git a/src/Auth0/Login/Repository/Auth0UserRepository.php b/src/Auth0/Login/Repository/Auth0UserRepository.php index a71d75f3..94439e5e 100644 --- a/src/Auth0/Login/Repository/Auth0UserRepository.php +++ b/src/Auth0/Login/Repository/Auth0UserRepository.php @@ -1,9 +1,11 @@ getUser(); @@ -47,7 +49,7 @@ public function getUserByIdentifier($identifier) : ?Authenticatable $auth0User = $this->getUserByUserInfo($user); // It is not the same user as logged in, it is not valid - if ($auth0User && $auth0User->getAuthIdentifier() == $identifier) { + if ($auth0User && $auth0User->getAuthIdentifier() === $identifier) { return $auth0User; } diff --git a/src/config/config.php b/src/config/config.php index b3facc05..16b1dc6f 100644 --- a/src/config/config.php +++ b/src/config/config.php @@ -1,53 +1,54 @@ env( 'AUTH0_DOMAIN' ), + 'domain' => env( 'AUTH0_DOMAIN' ), /* - |-------------------------------------------------------------------------- - | Your APP id - |-------------------------------------------------------------------------- - | As set in the auth0 administration page - | + |-------------------------------------------------------------------------- + | Your APP id + |-------------------------------------------------------------------------- + | As set in the auth0 administration page + |-------------------------------------------------------------------------- */ - 'client_id' => env( 'AUTH0_CLIENT_ID' ), + 'client_id' => env( 'AUTH0_CLIENT_ID' ), /* - |-------------------------------------------------------------------------- - | Your APP secret - |-------------------------------------------------------------------------- - | As set in the auth0 administration page - | + |-------------------------------------------------------------------------- + | Your APP secret + |-------------------------------------------------------------------------- + | As set in the auth0 administration page + |-------------------------------------------------------------------------- */ 'client_secret' => env( 'AUTH0_CLIENT_SECRET' ), /* - |-------------------------------------------------------------------------- - | The redirect URI - |-------------------------------------------------------------------------- - | Should be the same that the one configure in the route to handle the - | 'Auth0\Login\Auth0Controller@callback' - | + |-------------------------------------------------------------------------- + | The redirect URI + |-------------------------------------------------------------------------- + | Should be the same that the one configure in the route to handle the + | 'Auth0\Login\Auth0Controller@callback' + |-------------------------------------------------------------------------- */ - 'redirect_uri' => env( 'APP_URL' ).'/auth0/callback', + 'redirect_uri' => env( 'APP_URL' ).'/auth0/callback', /* - |-------------------------------------------------------------------------- - | Persistence Configuration - |-------------------------------------------------------------------------- - | persist_user (Boolean) Optional. Indicates if you want to persist the user info, default true - | persist_access_token (Boolean) Optional. Indicates if you want to persist the access token, default false - | persist_refresh_token (Boolean) Optional. Indicates if you want to persist the refresh token, default false - | persist_id_token (Boolean) Optional. Indicates if you want to persist the id token, default false - | + |-------------------------------------------------------------------------- + | Persistence Configuration + |-------------------------------------------------------------------------- + | persist_user (Boolean) Optional. Indicates if you want to persist the user info, default true + | persist_access_token (Boolean) Optional. Indicates if you want to persist the access token, default false + | persist_refresh_token (Boolean) Optional. Indicates if you want to persist the refresh token, default false + | persist_id_token (Boolean) Optional. Indicates if you want to persist the id token, default false + |-------------------------------------------------------------------------- */ 'persist_user' => true, 'persist_access_token' => false, @@ -55,46 +56,45 @@ 'persist_id_token' => false, /* - |-------------------------------------------------------------------------- - | The authorized token audiences - |-------------------------------------------------------------------------- - | + |-------------------------------------------------------------------------- + | The authorized token audiences + |-------------------------------------------------------------------------- */ - // 'api_identifier' => '', - + // 'api_identifier' => '', /* - |-------------------------------------------------------------------------- - | Auth0 Organizations - |-------------------------------------------------------------------------- - | organization (string) Optional. Id of an Organization, if being used. Used when generating log in urls and validating token claims. + |-------------------------------------------------------------------------- + | Auth0 Organizations + |-------------------------------------------------------------------------- + | organization (string) Optional. Id of an Organization, if being used. Used when generating log in urls and validating token claims. + |-------------------------------------------------------------------------- */ - // 'organization' => '', + // 'organization' => '', /* - |-------------------------------------------------------------------------- - | The secret format - |-------------------------------------------------------------------------- - | Used to know if it should decode the secret when using HS256 - | + |-------------------------------------------------------------------------- + | The secret format + |-------------------------------------------------------------------------- + | Used to know if it should decode the secret when using HS256 + |-------------------------------------------------------------------------- */ - 'secret_base64_encoded' => false, + 'secret_base64_encoded' => false, /* - |-------------------------------------------------------------------------- - | Supported algorithms - |-------------------------------------------------------------------------- - | Token decoding algorithms supported by your API - | + |-------------------------------------------------------------------------- + | Supported algorithms + |-------------------------------------------------------------------------- + | Token decoding algorithms supported by your API + |-------------------------------------------------------------------------- */ - 'supported_algs' => [ 'RS256' ], + 'supported_algs' => [ 'RS256' ], /* - |-------------------------------------------------------------------------- - | Guzzle Options - |-------------------------------------------------------------------------- - | guzzle_options (array) optional. Used to specify additional connection options e.g. proxy settings - | + |-------------------------------------------------------------------------- + | Guzzle Options + |-------------------------------------------------------------------------- + | guzzle_options (array) optional. Used to specify additional connection options e.g. proxy settings + |-------------------------------------------------------------------------- */ // 'guzzle_options' => [] ]; diff --git a/src/controllers/Auth0Controller.php b/src/controllers/Auth0Controller.php index b097115d..63628060 100644 --- a/src/controllers/Auth0Controller.php +++ b/src/controllers/Auth0Controller.php @@ -1,5 +1,7 @@ 'https://example.com/callback', 'transient_store' => new SessionStore(), 'api_identifier' => '__test_api_identifier__', - 'supported_algs' => ['HS256'] + 'supported_algs' => ['HS256'] ]; } @@ -33,7 +33,7 @@ public function testDecodeJWTReturnsDecodedJWT() { $service = new Auth0Service(self::$defaultConfig); $token = self::getToken(); - + $this->assertNotEmpty($service->decodeJWT($token)); } @@ -62,6 +62,6 @@ private static function getToken() $builder->withClaim($claim, $value); } - return $builder->getToken(new HsSigner(), new Key('__test_secret__')); + return (string) $builder->getToken(new HsSigner(), new Key('__test_secret__')); } } From d662c83b68b62556f5401dfd41cd65226b48eee9 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 2 Aug 2021 15:47:21 -0400 Subject: [PATCH 040/525] Use new GitHub issue templates. --- .github/ISSUE_TEMPLATE/Bug Report.yml | 52 ++++++++++++++++++++ .github/ISSUE_TEMPLATE/Feature Request.yml | 14 ++++++ .github/ISSUE_TEMPLATE/config.yml | 12 +++-- .github/ISSUE_TEMPLATE/feature_request.md | 39 --------------- .github/ISSUE_TEMPLATE/report_a_bug.md | 55 ---------------------- 5 files changed, 75 insertions(+), 97 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/Bug Report.yml create mode 100644 .github/ISSUE_TEMPLATE/Feature Request.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md delete mode 100644 .github/ISSUE_TEMPLATE/report_a_bug.md diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml new file mode 100644 index 00000000..0d48c92e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -0,0 +1,52 @@ +name: laravel-auth0 Bug Report +description: Found a bug or issue? Let us know with a bug report. +labels: [triage] +body: + - type: markdown + attributes: + value: Thanks for taking the time to help us improve this project! + - type: textarea + id: bug-description + attributes: + label: What happened? + description: Also tell us, what did you expect to happen? + validations: + required: true + - type: dropdown + id: sdk + attributes: + label: SDK Version + description: What version of our Laravel plugin are you running? (`composer show | grep auth0/login`) + options: + - 7.x + - 6.4.1 + - 6.4.0 + - Other (please specify in 'additional context') + validations: + required: true + - type: dropdown + id: php + attributes: + label: PHP Version + description: What version of PHP are you running? (`php -v`) + options: + - PHP 8.0 + - PHP 7.4 + - PHP 7.3 + validations: + required: true + - type: dropdown + id: composer + attributes: + label: Composer Version + description: What version of Composer are you running? (`composer -v`) + options: + - 2.x + - 1.x + validations: + required: true + - type: textarea + id: context + attributes: + label: Additional context + description: Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/Feature Request.yml b/.github/ISSUE_TEMPLATE/Feature Request.yml new file mode 100644 index 00000000..95bc926c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature Request.yml @@ -0,0 +1,14 @@ +name: laravel-auth0 Feature Request +description: Suggest an idea or a feature for this project. +labels: [triage] +body: + - type: markdown + attributes: + value: Thanks for taking the time to help us improve this project! + - type: textarea + id: feature-description + attributes: + label: What should be added? + description: How do you think this feature will improve the developer experience? + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index b785e527..4a8f3e20 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,11 @@ blank_issues_enabled: false contact_links: - - name: Auth0 Community - url: https://community.auth0.com/c/sdks/5 - about: Discuss this SDK in the Auth0 Community forums \ No newline at end of file + - name: Auth0 PHP SDK Issues + url: https://github.com/auth0/auth0-PHP/ + about: For bug reports related to the PHP SDK itself, please report them in that repository. + - name: Auth0 Community Support + url: https://community.auth0.com/tags/c/sdks/5/laravel + about: Please ask general usage questions here. + - name: Auth0 Responsible Disclosure Program + url: https://auth0.com/whitehat + about: Please do not report security vulnerabilities on the public GitHub issue tracker. The Responsible Disclosure Program details the procedure for disclosing security issues. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 68352ba2..00000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -name: Feature request -about: Suggest an idea or a feature for this project -title: '' -labels: feature request -assignees: '' ---- - - - -### Describe the problem you'd like to have solved - - - -### Describe the ideal solution - - - -## Alternatives and current work-arounds - - - -### Additional information, if any - - \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/report_a_bug.md b/.github/ISSUE_TEMPLATE/report_a_bug.md deleted file mode 100644 index 50b9fa7e..00000000 --- a/.github/ISSUE_TEMPLATE/report_a_bug.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -name: Report a bug -about: Have you found a bug or issue? Create a bug report for this SDK -title: '' -labels: bug report -assignees: '' ---- - - - -### Describe the problem - - - -### What was the expected behavior? - - - -### Reproduction - - -- Step 1.. -- Step 2.. -- ... - -### Environment - - - -- **Version of this library used:** -- **Which framework are you using, if applicable:** -- **Other modules/plugins/libraries that might be involved:** -- **Any other relevant information you think would be useful:** \ No newline at end of file From b304fb8fd5b614bb605a51b3cb0e87c5c76bc810 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 2 Aug 2021 15:49:51 -0400 Subject: [PATCH 041/525] Use new GitHub issue templates. --- .github/ISSUE_TEMPLATE/Bug Report.yml | 2 +- .github/ISSUE_TEMPLATE/Feature Request.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index 0d48c92e..9ef3266e 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -1,4 +1,4 @@ -name: laravel-auth0 Bug Report +name: 🐛 Bug Report description: Found a bug or issue? Let us know with a bug report. labels: [triage] body: diff --git a/.github/ISSUE_TEMPLATE/Feature Request.yml b/.github/ISSUE_TEMPLATE/Feature Request.yml index 95bc926c..7013515e 100644 --- a/.github/ISSUE_TEMPLATE/Feature Request.yml +++ b/.github/ISSUE_TEMPLATE/Feature Request.yml @@ -1,4 +1,4 @@ -name: laravel-auth0 Feature Request +name: 💡 Feature Suggestion description: Suggest an idea or a feature for this project. labels: [triage] body: From 6c9224ab3eea47fc6cc7fb353e3cec78dfabdbb0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 2 Aug 2021 15:51:00 -0400 Subject: [PATCH 042/525] Use new GitHub issue templates. --- .github/ISSUE_TEMPLATE/Bug Report.yml | 2 +- .github/ISSUE_TEMPLATE/Feature Request.yml | 2 +- .github/ISSUE_TEMPLATE/config.yml | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index 9ef3266e..442295d6 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -1,4 +1,4 @@ -name: 🐛 Bug Report +name: Report a Bug description: Found a bug or issue? Let us know with a bug report. labels: [triage] body: diff --git a/.github/ISSUE_TEMPLATE/Feature Request.yml b/.github/ISSUE_TEMPLATE/Feature Request.yml index 7013515e..ecf3e049 100644 --- a/.github/ISSUE_TEMPLATE/Feature Request.yml +++ b/.github/ISSUE_TEMPLATE/Feature Request.yml @@ -1,4 +1,4 @@ -name: 💡 Feature Suggestion +name: Suggest a Feature description: Suggest an idea or a feature for this project. labels: [triage] body: diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 4a8f3e20..b921445c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,11 +1,11 @@ blank_issues_enabled: false contact_links: - - name: Auth0 PHP SDK Issues + - name: Report Auth0-PHP Issues url: https://github.com/auth0/auth0-PHP/ - about: For bug reports related to the PHP SDK itself, please report them in that repository. - - name: Auth0 Community Support + about: For issues relating to the Auth0-PHP SDK, please report them in that repository. + - name: Community Support url: https://community.auth0.com/tags/c/sdks/5/laravel about: Please ask general usage questions here. - - name: Auth0 Responsible Disclosure Program + - name: Responsible Disclosure Program url: https://auth0.com/whitehat about: Please do not report security vulnerabilities on the public GitHub issue tracker. The Responsible Disclosure Program details the procedure for disclosing security issues. From 0ed10b4427dc096fc10bac5cc8d85e705b756e2f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 2 Aug 2021 15:52:04 -0400 Subject: [PATCH 043/525] Use new GitHub issue templates. --- .github/ISSUE_TEMPLATE/Bug Report.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index 442295d6..a87fd920 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -21,7 +21,7 @@ body: - 7.x - 6.4.1 - 6.4.0 - - Other (please specify in 'additional context') + - Other (specify in 'additional context') validations: required: true - type: dropdown @@ -33,6 +33,7 @@ body: - PHP 8.0 - PHP 7.4 - PHP 7.3 + - Other (specify in 'additional context') validations: required: true - type: dropdown From 5b9a6a84fa20188873502e9c37f8cdc0be791445 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 2 Aug 2021 15:55:17 -0400 Subject: [PATCH 044/525] Use new GitHub issue templates. --- .github/ISSUE_TEMPLATE/Bug Report.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index a87fd920..1f829101 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -12,6 +12,13 @@ body: description: Also tell us, what did you expect to happen? validations: required: true + - type: textarea + id: bug-reproduction + attributes: + label: How can we reproduce this issue? + description: Detail the steps taken to reproduce this error, and whether this can be reproduced consistently or if it is intermittent. + validations: + required: true - type: dropdown id: sdk attributes: From ee336913ce45a0dc423d463a25ca93ee3bce55e8 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 2 Aug 2021 15:56:22 -0400 Subject: [PATCH 045/525] Use new GitHub issue templates. --- .github/ISSUE_TEMPLATE/Bug Report.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index 1f829101..d68d870a 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -25,7 +25,6 @@ body: label: SDK Version description: What version of our Laravel plugin are you running? (`composer show | grep auth0/login`) options: - - 7.x - 6.4.1 - 6.4.0 - Other (specify in 'additional context') From ebde74129c6d06c65e894e16d7089bb9b4926d6b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 2 Aug 2021 15:56:56 -0400 Subject: [PATCH 046/525] Use new GitHub issue templates. --- .github/ISSUE_TEMPLATE/Bug Report.yml | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index d68d870a..437f12fc 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -5,20 +5,6 @@ body: - type: markdown attributes: value: Thanks for taking the time to help us improve this project! - - type: textarea - id: bug-description - attributes: - label: What happened? - description: Also tell us, what did you expect to happen? - validations: - required: true - - type: textarea - id: bug-reproduction - attributes: - label: How can we reproduce this issue? - description: Detail the steps taken to reproduce this error, and whether this can be reproduced consistently or if it is intermittent. - validations: - required: true - type: dropdown id: sdk attributes: @@ -52,6 +38,20 @@ body: - 1.x validations: required: true + - type: textarea + id: bug-description + attributes: + label: What happened? + description: Also tell us, what did you expect to happen? + validations: + required: true + - type: textarea + id: bug-reproduction + attributes: + label: How can we reproduce this issue? + description: Detail the steps taken to reproduce this error, and whether this can be reproduced consistently or if it is intermittent. + validations: + required: true - type: textarea id: context attributes: From b3da7b985cbe22598596119b10bfaf4d83b96074 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 2 Aug 2021 15:57:48 -0400 Subject: [PATCH 047/525] Use new GitHub issue templates. --- .github/ISSUE_TEMPLATE/Bug Report.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index 437f12fc..42eb1344 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -11,6 +11,7 @@ body: label: SDK Version description: What version of our Laravel plugin are you running? (`composer show | grep auth0/login`) options: + - @dev - 6.4.1 - 6.4.0 - Other (specify in 'additional context') From 6446335c30207e38de9ffbbdbaf4e1aacdaf21a1 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 2 Aug 2021 15:58:36 -0400 Subject: [PATCH 048/525] Use new GitHub issue templates. --- .github/ISSUE_TEMPLATE/Bug Report.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index 42eb1344..437f12fc 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -11,7 +11,6 @@ body: label: SDK Version description: What version of our Laravel plugin are you running? (`composer show | grep auth0/login`) options: - - @dev - 6.4.1 - 6.4.0 - Other (specify in 'additional context') From 9473988bd8830b569f9ed0fb250f8d16d8ee0463 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 2 Aug 2021 16:20:24 -0400 Subject: [PATCH 049/525] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 33 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7f2aa50e..ac500dd9 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,29 +1,30 @@ -### Changes + -Please describe both what is changing and why this is important. Include: +### Changes -- Endpoints added, deleted, deprecated, or changed -- Classes and methods added, deleted, deprecated, or changed -- Screenshots of new or changed UI, if applicable -- A summary of usage if this is a new feature or change to a public API (this should also be added to relevant documentation once released) -- Any alternative designs or approaches considered + ### References -Please include relevant links supporting this change such as a: + -- support ticket -- community post -- StackOverflow post -- support forum thread +Resolves # ### Testing -Please describe how this can be tested by reviewers. Be specific about anything not tested and reasons why. If this library has unit and/or integration testing, tests should be added for new functionality and existing tests should complete without errors. - -[ ] This change has been tested on the latest version Laravel + -### Checklist +### Contributor Checklist [ ] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) From fd6aa7136beec09225bfe3c0a3d7f6aa3459eb09 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 2 Aug 2021 16:29:33 -0400 Subject: [PATCH 050/525] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ac500dd9..67deae3a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -26,6 +26,6 @@ Resolves # ### Contributor Checklist -[ ] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) +- [ ] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) -[ ] I have read the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) +- [ ] I have read the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) From ced39331a8ceaf813ca219cfddb9ccd06345eac1 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 3 Aug 2021 12:26:20 -0400 Subject: [PATCH 051/525] Release 6.4.1 (#223) --- CHANGELOG.md | 10 ++++++++++ src/Auth0/Login/LoginServiceProvider.php | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b014525..2c211194 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## [6.4.1](https://github.com/auth0/laravel-auth0/tree/6.4.0) (2021-08-02) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.4.0...6.4.1) + +**Fixed** + +- Use the fully qualified facade class names [\#215](https://github.com/auth0/laravel-auth0/pull/215) ([Rezouce](https://github.com/Rezouce)) +- Update auth0-PHP dependency [\#222](https://github.com/auth0/laravel-auth0/pull/222) ([evansims](https://github.com/evansims)) +- Pass api_identifier config as audience to Auth0\SDK\Auth0 [\#214](https://github.com/auth0/laravel-auth0/pull/214) ([iSerter](https://github.com/iSerter)) + ## [6.4.0](https://github.com/auth0/laravel-auth0/tree/6.4.0) (2021-03-25) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.3.0...6.4.0) diff --git a/src/Auth0/Login/LoginServiceProvider.php b/src/Auth0/Login/LoginServiceProvider.php index a2e434d8..65a4a52c 100644 --- a/src/Auth0/Login/LoginServiceProvider.php +++ b/src/Auth0/Login/LoginServiceProvider.php @@ -17,7 +17,7 @@ class LoginServiceProvider extends ServiceProvider { - public const SDK_VERSION = '6.4.0'; + public const SDK_VERSION = '6.4.1'; /** * Bootstrap the application events. From 3ba11791a5ac81391b2451c24a1b54c39ac5eb97 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 16 Sep 2021 09:13:47 -0400 Subject: [PATCH 052/525] Update README for PHP/Lara support cycles (#225) * docs: Update README for PHP/Lara support cycles * docs: Update links * Update README.md Co-authored-by: Steve Hobbs Co-authored-by: Steve Hobbs --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 89cefb00..86b1c52b 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,11 @@ This plugin helps you integrate your [Laravel](https://laravel.com/) WebApp with ## Supported Framework Versions -Our plugin maintains support for [all actively supported versions](https://laravel.com/docs/8.x/releases#support-policy) of the Laravel framework, including [6.X (LTS)](https://laravel.com/docs/8.x/releases), [7.X](https://laravel.com/docs/7.x/releases) and [8.X](https://laravel.com/docs/8.x/releases). +This library follows the [Laravel support](https://laravel.com/docs/releases#support-policy) and [PHP release support](https://www.php.net/supported-versions.php) schedules. We do not support Laravel or PHP releases after they reach end-of-life. At the time of writing this includes [Laravel 6](https://laravel.com/docs/6.x/) and [Laravel 8](https://laravel.com/docs/8.x) on PHP 7.3 or newer. -Past releases of our plugin may potentially run on earlier, now unsupported versions of the Laravel framework, but these releases are not maintained. The final release of our plugin to support the Laravel 5.X series was 6.1.0. +As Composer handles these deprecations safely, this is not considered a breaking change and we may drop version support with minor library releases. Please ensure you are always running the latest PHP version to keep your application up to date with PHP's security fixes, and continue to receive our latest library updates. + +Past releases of our plugin may potentially run on earlier, now unsupported versions of the Laravel framework, but these releases are not maintained. ## Documentation From 87ef20a2814ecf94ce94617e4bb960ffda6949c9 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 4 Oct 2021 08:01:00 -0400 Subject: [PATCH 053/525] feat: Add alias methods for SDK's Passwordless API methods. (#228) --- src/Auth0/Login/Auth0Service.php | 57 ++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/Auth0/Login/Auth0Service.php b/src/Auth0/Login/Auth0Service.php index 5777323b..5d5b28e9 100644 --- a/src/Auth0/Login/Auth0Service.php +++ b/src/Auth0/Login/Auth0Service.php @@ -33,6 +33,8 @@ class Auth0Service private $auth0Config = []; + private $singletons = []; + /** * Auth0Service constructor. * @@ -85,6 +87,26 @@ private function getSDK() return $this->auth0; } + /** + * Instantiate a singleton of the Auth0 Authentication class, using the provided configuration. + */ + private function getAuthenticationClass() + { + if (isset($this->singletons['authentication'])) { + return $this->singletons['authentication']; + } + + return $this->singletons['authentication'] = new \Auth0\SDK\API\Authentication( + $this->auth0Config['domain'] ?? null, + $this->auth0Config['client_id'] ?? null, + $this->auth0Config['client_secret'] ?? null, + $this->auth0Config['audience'] ?? null, + null, + [], + $this->auth0Config['organization'] ?? null, + ); + } + /** * Logs the user out from the SDK. */ @@ -108,9 +130,44 @@ public function login($connection = null, $state = null, $additional_params = [' $additional_params['response_type'] = $response_type; $auth_url = $this->auth0->getLoginUrl($additional_params); + return new RedirectResponse($auth_url); } + /** + * Start passwordless login process for email + * + * @param string $email Email address to use. + * @param string $type Use null or "link" to send a link, use "code" to send a verification code. + * @param array $authParams Optional. Link parameters (like scope, redirect_uri, protocol, response_type) to modify. + * @param string|null $forwardedFor Optional. Source IP address. requires Trust Token Endpoint IP Header + * + * @link https://auth0.com/docs/api/authentication#get-code-or-link + */ + public function emailPasswordlessStart( + string $email, + string $type, + array $authParams = [], + ?string $forwardedFor = null + ): array { + return $this->getAuthenticationClass()->email_passwordless_start($email, $type, $authParams, $forwardedFor); + } + + /** + * Start passwordless login process for SMS. + * + * @param string $phoneNumber Phone number to use. + * @param string|null $forwardedFor Optional. Source IP address. requires Trust Token Endpoint IP Header + * + * @link https://auth0.com/docs/api/authentication#get-code-or-link + */ + public function smsPasswordlessStart( + string $phoneNumber, + ?string $forwardedFor = null + ): array { + return $this->getAuthenticationClass()->sms_passwordless_start($phoneNumber, $forwardedFor); + } + /** * If invitation parameters are present in the request, handle extraction and automatically redirect to Universal Login. */ From a324411c5e85e05dfec21a683b84c1f8aca2a7bf Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 15 Oct 2021 08:55:15 -0400 Subject: [PATCH 054/525] Release 6.5.0 (#230) * chore: Bump to 6.5.0 * fix: Typo in CHANGELOG * chore: Updated CHANGELOG --- .github/ISSUE_TEMPLATE/Bug Report.yml | 4 ++-- CHANGELOG.md | 8 ++++++++ src/Auth0/Login/LoginServiceProvider.php | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index 437f12fc..3ec46e90 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -11,8 +11,8 @@ body: label: SDK Version description: What version of our Laravel plugin are you running? (`composer show | grep auth0/login`) options: - - 6.4.1 - - 6.4.0 + - 6.5 + - 6.4 - Other (specify in 'additional context') validations: required: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c211194..95b68395 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## [6.5.0](https://github.com/auth0/laravel-auth0/tree/6.5.0) (2021-10-15) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.4.1...6.5.0) + +**Added** + +- Add SDK alias methods for passwordless endpoints [\#228](https://github.com/auth0/laravel-auth0/pull/228) ([evansims](https://github.com/evansims)) + ## [6.4.1](https://github.com/auth0/laravel-auth0/tree/6.4.0) (2021-08-02) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.4.0...6.4.1) diff --git a/src/Auth0/Login/LoginServiceProvider.php b/src/Auth0/Login/LoginServiceProvider.php index 65a4a52c..df71b58a 100644 --- a/src/Auth0/Login/LoginServiceProvider.php +++ b/src/Auth0/Login/LoginServiceProvider.php @@ -17,7 +17,7 @@ class LoginServiceProvider extends ServiceProvider { - public const SDK_VERSION = '6.4.1'; + public const SDK_VERSION = '6.5.0'; /** * Bootstrap the application events. From 6436962dbe062464a8e60be6367b84e5ab416645 Mon Sep 17 00:00:00 2001 From: Joel Bradbury Date: Wed, 20 Oct 2021 23:41:00 +0100 Subject: [PATCH 055/525] Add an array type check within the callOnLogin callback (#232) * Add an array type check within the callOnLogin callback Fixes #227 Adds an explict check to see if the object returned from a custom onLogin callback is an array, or an object that can be converted to an array, before calling setUser() Returns the object returned from the callback directly to the parent service regardless. * tests: Fix code styling to resolve linter warning Co-authored-by: Evan Sims --- src/Auth0/Login/Auth0Service.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Auth0/Login/Auth0Service.php b/src/Auth0/Login/Auth0Service.php index 5d5b28e9..4e6eae2d 100644 --- a/src/Auth0/Login/Auth0Service.php +++ b/src/Auth0/Login/Auth0Service.php @@ -232,7 +232,15 @@ public function callOnLogin($auth0User) { $user = call_user_func($this->onLoginCb, $auth0User); - $this->getSDK()->setUser($user); + if(is_array($user) || method_exists($user, 'toArray')) { + if(! is_array($user)) { + $array = $user->toArray(); + } else { + $array = $user; + } + + $this->getSDK()->setUser($array); + } return $user; } From 7a1e85400da716ff1f052e7cd4f728b83d7ac785 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 3 Jan 2022 13:28:46 -0500 Subject: [PATCH 056/525] Disable obsolete tests for v7 development (#239) --- .circleci/config.yml | 57 --------------- tests/Auth0ServiceTest.php | 123 -------------------------------- tests/Unit/Auth0JWTUserTest.php | 55 -------------- tests/Unit/Auth0ServiceTest.php | 67 ----------------- 4 files changed, 302 deletions(-) delete mode 100644 tests/Auth0ServiceTest.php delete mode 100644 tests/Unit/Auth0JWTUserTest.php delete mode 100644 tests/Unit/Auth0ServiceTest.php diff --git a/.circleci/config.yml b/.circleci/config.yml index 69889510..644c757b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -46,33 +46,6 @@ commands: - composer-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "composer.json" }} - composer-v1-{{ .Environment.CIRCLE_JOB }} - run-php-codesniffer: - steps: - - run: - name: Run code quality analysis (PHP CodeSniffer) - command: php ./vendor/bin/phpcs - - run-phpstan: - steps: - - run: - name: Run static code analysis (PHPStan) - command: php ./vendor/bin/phpstan analyze - - run-phpunit: - steps: - - run: - name: Run unit tests (PHPUnit) - command: php ./vendor/bin/phpunit --stop-on-failure --coverage-clover=build/coverage/coverage.xml --coverage-xml=build/coverage/coverage-xml --log-junit=build/coverage/junit.xml - - persist_to_workspace: - root: . - paths: - - src - - tests - - infection.json.dist - - phpunit.xml.dist - - build - - vendor - jobs: run-unit-tests: parameters: @@ -82,9 +55,6 @@ jobs: - image: circleci/php:<< parameters.php >> steps: - prepare - - run-php-codesniffer - - run-phpstan - - run-phpunit run-security-tests: docker: @@ -97,27 +67,6 @@ jobs: command: snyk monitor --org=auth0-sdks --project-name=laravel-auth0 when: always - run-codecov-uploader: - docker: - - image: circleci/php:7.4 - steps: - - attach_workspace: - at: . - - restore-cache - - run: - name: Download and validate Codecov uploader - command: | - curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --import - curl -Os https://uploader.codecov.io/latest/linux/codecov - curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM - curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM.sig - gpg --verify codecov.SHA256SUM.sig codecov.SHA256SUM - shasum -a 256 -c codecov.SHA256SUM - chmod +x codecov - - run: - name: Upload coverage reports to Codecov - command: ./codecov -t ${CODECOV_TOKEN} -f ./build/coverage/coverage.xml - workflows: run-tests: jobs: @@ -137,9 +86,3 @@ workflows: - main context: snyk-env requires: [run-phpunit-7.3] - - run-codecov-uploader: - filters: - branches: - only: - - main - requires: [run-phpunit-7.4] diff --git a/tests/Auth0ServiceTest.php b/tests/Auth0ServiceTest.php deleted file mode 100644 index 3e3031de..00000000 --- a/tests/Auth0ServiceTest.php +++ /dev/null @@ -1,123 +0,0 @@ - 'test.auth0.com', - 'client_id' => '__test_client_id__', - 'client_secret' => '__test_client_secret__', - 'redirect_uri' => 'https://example.com/callback', - 'transient_store' => new SessionStore(), - 'api_identifier' => 'https://example-audience.com/' - ]; - } - - public function tearDown() : void - { - Cache::flush(); - } - - public function testThatServiceUsesSessionStoreByDefault() - { - session(['auth0__user' => '__test_user__']); - $service = new Auth0Service(self::$defaultConfig); - $user = $service->getUser(); - - $this->assertArrayHasKey('profile', $user); - $this->assertEquals('__test_user__', $user['profile']); - } - - public function testThatServiceSetsEmptyStoreFromConfigAndConstructor() - { - session(['auth0__user' => '__test_user__']); - - $service = new Auth0Service(self::$defaultConfig + ['store' => false]); - $this->assertNull($service->getUser()); - - $service = new Auth0Service(self::$defaultConfig); - $this->assertIsArray($service->getUser()); - } - - public function testThatServiceLoginReturnsRedirect() - { - $service = new Auth0Service(self::$defaultConfig); - $redirect = $service->login(); - - $this->assertInstanceOf( RedirectResponse::class, $redirect ); - - $targetUrl = parse_url(http://github.com/$redirect-%3EgetTargetUrl()); - - $this->assertEquals('test.auth0.com', $targetUrl['host']); - - $targetUrlQuery = explode('&', $targetUrl['query']); - - $this->assertContains('redirect_uri=https%3A%2F%2Fexample.com%2Fcallback', $targetUrlQuery); - $this->assertContains('client_id=__test_client_id__', $targetUrlQuery); - } - - /** - * @throws InvalidTokenException - */ - public function testThatServiceCanUseLaravelCache() - { - $cache_key = md5('https://__invalid_domain__/.well-known/jwks.json'); - cache([$cache_key => [uniqid()]], 10); - session(['auth0__nonce' => uniqid()]); - - $service = new Auth0Service(['domain' => '__invalid_domain__'] + self::$defaultConfig); - - // Without the cache set above, would expect a cURL error for a bad domain. - $this->expectException(InvalidTokenException::class); - $service->decodeJWT(uniqid()); - } - - public function testThatGuardAuthenticatesUsers() - { - $this->assertTrue(\Auth('auth0')->guest()); - - $user = new Auth0JWTUser(['sub' => 'x']); - - \Auth('auth0')->setUser($user); - - $this->assertTrue(\Auth('auth0')->check()); - } - - /* - * Test suite helpers - */ - - protected function getPackageProviders($app) - { - return [Auth0ServiceProvider::class]; - } - - protected function getPackageAliases($app) - { - return [ - 'Auth0' => Auth0Facade::class, - ]; - } - - protected function getEnvironmentSetUp($app) - { - $app['config']->set('auth.guards.auth0', ['driver' => 'auth0', 'provider' => 'auth0']); - $app['config']->set('auth.providers.auth0', ['driver' => 'auth0']); - $app['config']->set('laravel-auth0', self::$defaultConfig); - } -} diff --git a/tests/Unit/Auth0JWTUserTest.php b/tests/Unit/Auth0JWTUserTest.php deleted file mode 100644 index e96cea7d..00000000 --- a/tests/Unit/Auth0JWTUserTest.php +++ /dev/null @@ -1,55 +0,0 @@ -auth0JwtUser = new Auth0JWTUser([ - "name" => "John Doe", - "iss" => "http://auth0.com/", - "sub" => "someone@example.com", - "aud" => "http://example.com/", - "exp" => 1357000000 - ]); - } - - public function testAuthIdentifierNameIsSubjectOfJWTToken() - { - $this->assertEquals('someone@example.com', $this->auth0JwtUser->getAuthIdentifierName()); - } - - public function testAuthIdentifierIsSubjectOfJWTToken() - { - $this->assertEquals('someone@example.com', $this->auth0JwtUser->getAuthIdentifier()); - } - - public function testGetAuthPasswordWillNotReturnAnything() - { - $this->assertEquals('', $this->auth0JwtUser->getAuthPassword()); - } - - public function testObjectHoldsNoRememberTokenInformation() - { - $this->auth0JwtUser->setRememberToken('testing123'); - - $this->assertEquals('', $this->auth0JwtUser->getRememberToken()); - $this->assertEquals('', $this->auth0JwtUser->getRememberTokenName()); - } - - public function testGettersCanReturnTokenClaims() - { - // Retrieve issuer claim - $this->assertEquals('http://auth0.com/', $this->auth0JwtUser->iss); - } -} diff --git a/tests/Unit/Auth0ServiceTest.php b/tests/Unit/Auth0ServiceTest.php deleted file mode 100644 index 8f8e26e4..00000000 --- a/tests/Unit/Auth0ServiceTest.php +++ /dev/null @@ -1,67 +0,0 @@ - '__test_domain__', - 'client_id' => '__test_client_id__', - 'client_secret' => '__test_secret__', - 'redirect_uri' => 'https://example.com/callback', - 'transient_store' => new SessionStore(), - 'api_identifier' => '__test_api_identifier__', - 'supported_algs' => ['HS256'] - ]; - } - - public function testDecodeJWTReturnsDecodedJWT() - { - $service = new Auth0Service(self::$defaultConfig); - $token = self::getToken(); - - $this->assertNotEmpty($service->decodeJWT($token)); - } - - public function testThatInvalidTokenExceptionThrownForUnsupportedAlg() - { - $service = new Auth0Service(['supported_algs' => ['HS512']] + self::$defaultConfig); - $token = self::getToken(); - - $this->expectException(InvalidTokenException::class); - $service->decodeJWT($token); - } - - private static function getToken() - { - $builder = new Builder(); - $defaultClaims = [ - 'sub' => '__test_sub__', - 'iss' => 'https://__test_domain__/', - 'aud' => '__test_api_identifier__', - 'azp' => '__test_azp__', - 'exp' => time() + 1000, - 'iat' => time() - 1000, - ]; - - foreach ($defaultClaims as $claim => $value) { - $builder->withClaim($claim, $value); - } - - return (string) $builder->getToken(new HsSigner(), new Key('__test_secret__')); - } -} From 3b67e9cd85ce671933a2008157f4c93c79e1bd0c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 5 Jan 2022 10:53:43 -0500 Subject: [PATCH 057/525] Upgrade project from PSR-0 to PSR-4 (#240) --- composer.json | 10 +++------- {src/config => config}/config.php | 0 src/{Auth0/Login => }/Auth0JWTUser.php | 0 src/{Auth0/Login => }/Auth0Service.php | 0 src/{Auth0/Login => }/Auth0User.php | 0 src/{Auth0/Login => }/Auth0UserProvider.php | 0 src/{Auth0/Login => }/Contract/Auth0UserRepository.php | 0 src/{Auth0/Login => }/LaravelSessionStore.php | 0 src/{Auth0/Login => }/LoginServiceProvider.php | 0 .../Login => }/Repository/Auth0UserRepository.php | 0 10 files changed, 3 insertions(+), 7 deletions(-) rename {src/config => config}/config.php (100%) rename src/{Auth0/Login => }/Auth0JWTUser.php (100%) rename src/{Auth0/Login => }/Auth0Service.php (100%) rename src/{Auth0/Login => }/Auth0User.php (100%) rename src/{Auth0/Login => }/Auth0UserProvider.php (100%) rename src/{Auth0/Login => }/Contract/Auth0UserRepository.php (100%) rename src/{Auth0/Login => }/LaravelSessionStore.php (100%) rename src/{Auth0/Login => }/LoginServiceProvider.php (100%) rename src/{Auth0/Login => }/Repository/Auth0UserRepository.php (100%) diff --git a/composer.json b/composer.json index 29408206..0c6cc280 100644 --- a/composer.json +++ b/composer.json @@ -48,17 +48,13 @@ "lcobucci/jwt": "*" }, "autoload": { - "classmap": [ - "src/controllers", - "src/facade" - ], - "psr-0": { - "Auth0\\Login\\": "src/" + "psr-4": { + "Auth0\\Laravel\\": "src" } }, "autoload-dev": { "psr-4": { - "Auth0\\Login\\Tests\\": "tests" + "Auth0\\Laravel\\Tests\\": "tests" } }, "extra": { diff --git a/src/config/config.php b/config/config.php similarity index 100% rename from src/config/config.php rename to config/config.php diff --git a/src/Auth0/Login/Auth0JWTUser.php b/src/Auth0JWTUser.php similarity index 100% rename from src/Auth0/Login/Auth0JWTUser.php rename to src/Auth0JWTUser.php diff --git a/src/Auth0/Login/Auth0Service.php b/src/Auth0Service.php similarity index 100% rename from src/Auth0/Login/Auth0Service.php rename to src/Auth0Service.php diff --git a/src/Auth0/Login/Auth0User.php b/src/Auth0User.php similarity index 100% rename from src/Auth0/Login/Auth0User.php rename to src/Auth0User.php diff --git a/src/Auth0/Login/Auth0UserProvider.php b/src/Auth0UserProvider.php similarity index 100% rename from src/Auth0/Login/Auth0UserProvider.php rename to src/Auth0UserProvider.php diff --git a/src/Auth0/Login/Contract/Auth0UserRepository.php b/src/Contract/Auth0UserRepository.php similarity index 100% rename from src/Auth0/Login/Contract/Auth0UserRepository.php rename to src/Contract/Auth0UserRepository.php diff --git a/src/Auth0/Login/LaravelSessionStore.php b/src/LaravelSessionStore.php similarity index 100% rename from src/Auth0/Login/LaravelSessionStore.php rename to src/LaravelSessionStore.php diff --git a/src/Auth0/Login/LoginServiceProvider.php b/src/LoginServiceProvider.php similarity index 100% rename from src/Auth0/Login/LoginServiceProvider.php rename to src/LoginServiceProvider.php diff --git a/src/Auth0/Login/Repository/Auth0UserRepository.php b/src/Repository/Auth0UserRepository.php similarity index 100% rename from src/Auth0/Login/Repository/Auth0UserRepository.php rename to src/Repository/Auth0UserRepository.php From 268b50e43a7b58b5ba454b95da561e8c2fec0811 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 5 Jan 2022 15:01:20 -0500 Subject: [PATCH 058/525] Update to use PHP 7.4+ language features and support Laravel 9 (#241) --- config/auth0.php | 40 ++++ src/Auth/Guard.php | 225 ++++++++++++++++++ src/Auth/User/Provider.php | 107 +++++++++ src/Auth/User/Repository.php | 68 ++++++ src/Auth0.php | 58 +++++ src/Event/Stateful/AuthenticationFailed.php | 44 ++++ .../Stateful/AuthenticationSucceeded.php | 28 +++ src/Exception/Stateful/CallbackException.php | 20 ++ src/Http/Controller/Stateful/Callback.php | 61 +++++ src/Http/Controller/Stateful/Login.php | 26 ++ src/Http/Controller/Stateful/Logout.php | 23 ++ src/Http/Middleware/Stateful/Authenticate.php | 35 +++ .../Stateful/AuthenticateOptional.php | 34 +++ src/Http/Middleware/Stateless/Authorize.php | 34 +++ .../Stateless/AuthorizeOptional.php | 32 +++ src/Model/Stateful/User.php | 9 + src/Model/Stateless/User.php | 9 + src/Model/User.php | 153 ++++++++++++ src/ServiceProvider.php | 52 ++++ src/StateInstance.php | 22 ++ src/controllers/Auth0Controller.php | 58 ----- src/facade/Auth0.php | 4 +- 22 files changed, 1082 insertions(+), 60 deletions(-) create mode 100644 config/auth0.php create mode 100644 src/Auth/Guard.php create mode 100644 src/Auth/User/Provider.php create mode 100644 src/Auth/User/Repository.php create mode 100644 src/Auth0.php create mode 100644 src/Event/Stateful/AuthenticationFailed.php create mode 100644 src/Event/Stateful/AuthenticationSucceeded.php create mode 100644 src/Exception/Stateful/CallbackException.php create mode 100644 src/Http/Controller/Stateful/Callback.php create mode 100644 src/Http/Controller/Stateful/Login.php create mode 100644 src/Http/Controller/Stateful/Logout.php create mode 100644 src/Http/Middleware/Stateful/Authenticate.php create mode 100644 src/Http/Middleware/Stateful/AuthenticateOptional.php create mode 100644 src/Http/Middleware/Stateless/Authorize.php create mode 100644 src/Http/Middleware/Stateless/AuthorizeOptional.php create mode 100644 src/Model/Stateful/User.php create mode 100644 src/Model/Stateless/User.php create mode 100644 src/Model/User.php create mode 100644 src/ServiceProvider.php create mode 100644 src/StateInstance.php delete mode 100644 src/controllers/Auth0Controller.php diff --git a/config/auth0.php b/config/auth0.php new file mode 100644 index 00000000..6cae23c8 --- /dev/null +++ b/config/auth0.php @@ -0,0 +1,40 @@ + env('AUTH0_STRATEGY', 'api'), + + // Auth0 domain for your tenant, found in your Auth0 Application settings. + 'domain' => env('AUTH0_DOMAIN'), + + // If you have configured Auth0 to use a custom domain, configure it here. + 'customDomain' => env('AUTH0_CUSTOM_DOMAIN'), + + // Client ID, found in the Auth0 Application settings. + 'clientId' => env('AUTH0_CLIENT_ID'), + + // Authentication callback URI, as defined in your Auth0 Application settings. + 'redirectUri' => env('AUTH0_REDIRECT_URI', env('APP_URL') . '/callback'), + + // Client Secret, found in the Auth0 Application settings. + 'clientSecret' => env('AUTH0_CLIENT_SECRET'), + + // One or more API identifiers, found in your Auth0 API settings. The SDK uses the first value for building links. If provided, at least one of these values must match the 'aud' claim to validate an ID Token successfully. + 'audience' => env('AUTH0_AUDIENCE', []), + + // One or more Organization IDs, found in your Auth0 Organization settings. The SDK uses the first value for building links. If provided, at least one of these values must match the 'org_id' claim to validate an ID Token successfully. + 'organization' => env('AUTH0_ORGANIZATION', []), + + // The secret used to derive an encryption key for the user identity in a session cookie and to sign the transient cookies used by the login callback. + 'cookieSecret' => env('AUTH0_COOKIE_SECRET', env('APP_KEY')), + + // How long, in seconds, before cookies expire. If set to 0 the cookie will expire at the end of the session (when the browser closes). + 'cookieExpires' => env('COOKIE_EXPIRES', 0), + + // Named routes the SDK may call during stateful requests for redirections. + 'routeLogin' => 'login', + 'routeLogout' => 'logout', + 'routeCallback' => 'callback', +]; diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php new file mode 100644 index 00000000..e33df9bd --- /dev/null +++ b/src/Auth/Guard.php @@ -0,0 +1,225 @@ +provider = $provider; + $this->request = $request; + $this->inputKey = $inputKey; + $this->storageKey = $storageKey; + $this->hash = $hash; + } + + /** + * Set the current user. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + */ + public function login( + \Illuminate\Contracts\Auth\Authenticatable $user + ): self { + $this->getInstance()->setUser($user); + return $this; + } + + /** + * Clear the current user. + */ + public function logout(): self + { + $this->getInstance()->setUser(null); + app('auth0')->getSdk()->clear(); + return $this; + } + + /** + * Determine if the current user is authenticated. + * + * @return bool + */ + public function check(): bool + { + return $this->user() !== null; + } + + /** + * Determine if the current user is a guest. + * + * @return bool + */ + public function guest(): bool + { + return ! $this->check(); + } + + /** + * Get the ID for the currently authenticated user. + * + * @return int|string|null + */ + public function id() + { + return $this->user() !== null ? $this->user()->getAuthIdentifier() : null; + } + + /** + * Validate a user's credentials. + * + * @param array $credentials + */ + public function validate( + array $credentials = [] + ): bool { + if (! isset($credentials[$this->inputKey])) { + return false; + } + + $credentials = [$this->storageKey => $credentials[$this->inputKey]]; + + return $this->provider->retrieveByCredentials($credentials) !== null; + } + + /** + * Determine if the guard has a user instance. + */ + public function hasUser(): bool + { + return ! is_null($this->getInstance()->getUser()); + } + + /** + * Set the current user. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + */ + public function setUser( + \Illuminate\Contracts\Auth\Authenticatable $user + ): self { + $user = $this->getInstance()->setUser($user); + return $this; + } + + /** + * Set the current request instance. + * + * @param \Illuminate\Http\Request $request + */ + public function setRequest( + \Illuminate\Http\Request $request + ): self { + $this->request = $request; + return $this; + } + + /** + * Get the currently authenticated user. + */ + public function user(): ?\Illuminate\Contracts\Auth\Authenticatable + { + $instance = $this->getInstance(); + $user = $instance->getUser(); + + if ($user === null) { + $stateful = app('auth0')->getSdk()->getCredentials(); + + if ($stateful !== null) { + $user = $this->provider->retrieveByCredentials((array) $stateful); + } + } + + if ($user === null) { + $token = $this->getTokenForRequest(); + + if ($token !== null) { + $user = $this->provider->retrieveByToken([], $token); + } + } + + if ($user !== null) { + $instance->setUser($user); + } + + return $user; + } + + /** + * Get the token for the current request. + */ + public function getTokenForRequest(): ?string + { + $token = $this->request->query($this->inputKey); + + if ($token === null) { + $token = $this->request->input($this->inputKey); + } + + if ($token === null) { + $token = $this->request->bearerToken(); + } + + if ($token === null) { + $token = $this->request->getPassword(); + } + + return $token; + } + + private function getInstance(): \Auth0\Laravel\StateInstance + { + return app()->make(\Auth0\Laravel\StateInstance::class); + } +} diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php new file mode 100644 index 00000000..9d751db5 --- /dev/null +++ b/src/Auth/User/Provider.php @@ -0,0 +1,107 @@ +repository = $repository; + } + + /** + * Returns a \Auth0\Laravel\Model\Stateless\User instance from an Id Token. + */ + public function retrieveById( + $identifier + ): ?\Illuminate\Contracts\Auth\Authenticatable { + $decoded = app('auth0')->getSdk()->decode($identifier, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_ID_TOKEN)->toArray(); + $scope = $decoded['scope'] ?? ''; + + // Process $identifier here ... + return $this->repository->fromAccessToken( + $decoded, + null, + $identifier, + explode(' ', $scope), + null, + null, + null, + ); + } + + /** + * Returns a \Auth0\Laravel\Model\Stateless\User instance from an Access Token. + * + * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + */ + public function retrieveByToken( + $identifier, + $token + ): ?\Illuminate\Contracts\Auth\Authenticatable { + $decoded = app('auth0')->getSdk()->decode($token, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_TOKEN)->toArray(); + $scope = $decoded['scope'] ?? ''; + + return $this->repository->fromAccessToken( + $decoded, + null, + $token, + explode(' ', $scope), + null, + null, + null, + ); + } + + /** + * Returns a \Auth0\Laravel\Model\Stateless\User instance translated from an Auth0-PHP SDK session. + */ + public function retrieveByCredentials( + array $credentials + ): ?\Illuminate\Contracts\Auth\Authenticatable { + return $this->repository->fromSession( + $credentials['user'] ?? null, + $credentials['idToken'] ?? null, + $credentials['accessToken'] ?? null, + $credentials['accessTokenScope'] ?? null, + $credentials['accessTokenExpiration'] ?? null, + $credentials['accessTokenExpired'] ?? null, + $credentials['refreshToken'] ?? null, + ); + } + + /** + * Returns true if the provided $user's unique identifier matches the credentials payload. + * + * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + */ + public function validateCredentials( + \Illuminate\Contracts\Auth\Authenticatable $user, + array $credentials + ): bool { + return false; + } + + /** + * Method required by interface. Not supported. + * + * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + */ + public function updateRememberToken( + \Illuminate\Contracts\Auth\Authenticatable $user, + $token + ): void { + } +} diff --git a/src/Auth/User/Repository.php b/src/Auth/User/Repository.php new file mode 100644 index 00000000..78efe13a --- /dev/null +++ b/src/Auth/User/Repository.php @@ -0,0 +1,68 @@ +sdk === null) { + $this->sdk = new \Auth0\SDK\Auth0($this->getConfiguration()); + } + + return $this->sdk; + } + + /** + * Create/return instance of the Auth0-PHP SdkConfiguration. + */ + public function getConfiguration(): \Auth0\SDK\Configuration\SdkConfiguration + { + if ($this->configuration === null) { + $this->configuration = new \Auth0\SDK\Configuration\SdkConfiguration(app()->make('config')->get('auth0')); + } + + return $this->configuration; + } + + /** + * Create/create a request state instance, a storage singleton containing authenticated user data. + */ + public function getState(): \Auth0\Laravel\StateInstance + { + return app()->make(\Auth0\Laravel\StateInstance::class); + } +} diff --git a/src/Event/Stateful/AuthenticationFailed.php b/src/Event/Stateful/AuthenticationFailed.php new file mode 100644 index 00000000..70992db0 --- /dev/null +++ b/src/Event/Stateful/AuthenticationFailed.php @@ -0,0 +1,44 @@ +exception = $exception; + $this->throwException = $throwException; + } + + public function setException( + \Throwable $exception + ): self { + $this->exception = $exception; + return $this; + } + + public function getException(): \Throwable + { + return $this->exception; + } + + public function setThrowException( + bool $throwException + ): self { + $this->throwException = $throwException; + return $this; + } + + public function getThrowException(): bool + { + return $this->throwException; + } +} diff --git a/src/Event/Stateful/AuthenticationSucceeded.php b/src/Event/Stateful/AuthenticationSucceeded.php new file mode 100644 index 00000000..7e4651bd --- /dev/null +++ b/src/Event/Stateful/AuthenticationSucceeded.php @@ -0,0 +1,28 @@ +user = $user; + } + + public function setUser( + \Illuminate\Contracts\Auth\Authenticatable $user + ): self { + $this->user = $user; + return $this; + } + + public function getUser(): \Illuminate\Contracts\Auth\Authenticatable + { + return $this->user; + } +} diff --git a/src/Exception/Stateful/CallbackException.php b/src/Exception/Stateful/CallbackException.php new file mode 100644 index 00000000..8744ac4d --- /dev/null +++ b/src/Exception/Stateful/CallbackException.php @@ -0,0 +1,20 @@ +guard('auth0')->check()) { + // They do; redirect to homepage. + return redirect()->intended('/'); + } + + try { + if ($request->query('state') !== null && $request->query('code') !== null) { + app('auth0')->getSdk()->exchange(); + // var_dump(app('auth0')->getSdk()->getUser()); + } + } catch (\Throwable $exception) { + app('auth0')->getSdk()->clear(); + + // Throw hookable $event to allow custom error handling scenarios. + $event = new \Auth0\Laravel\Event\Stateful\AuthenticationFailed($exception, true); + event($event); + + // If the event was not hooked by the host application, throw an exception: + if ($event->getThrowException() === true) { + throw $exception; + } + } + + if ($request->query('error') !== null && $request->query('error_description') !== null) { + // Workaround to aid static analysis, due to the lax formatting of the query() response: + $error = $request->query('error') ?? ''; + $errorDescription = $request->query('error_description') ?? ''; + $error = is_string($error) ? $error : ''; + $errorDescription = is_string($errorDescription) ? $error : ''; + + // Clear the local session via the Auth0-PHP SDK: + app('auth0')->getSdk()->clear(); + + // Create a dynamic exception to report the API error response: + $exception = \Auth0\Laravel\Exception\Stateful\CallbackException::apiException($error, $errorDescription); + + // Throw hookable $event to allow custom error handling scenarios: + $event = new \Auth0\Laravel\Event\Stateful\AuthenticationFailed($exception, true); + event($event); + + // If the event was not hooked by the host application, throw an exception: + if ($event->getThrowException() === true) { + throw $exception; + } + } + + return redirect()->intended('/'); + } +} diff --git a/src/Http/Controller/Stateful/Login.php b/src/Http/Controller/Stateful/Login.php new file mode 100644 index 00000000..f9aff07d --- /dev/null +++ b/src/Http/Controller/Stateful/Login.php @@ -0,0 +1,26 @@ +guard('auth0')->check()) { + return redirect()->intended('/'); + } + + return redirect()->away(app('auth0')->getSdk()->login()); + } +} diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php new file mode 100644 index 00000000..af77c44f --- /dev/null +++ b/src/Http/Controller/Stateful/Logout.php @@ -0,0 +1,23 @@ +guard('auth0')->check()) { + auth()->guard('auth0')->logout(); + + $request->session()->invalidate(); + $request->session()->regenerateToken(); + + return redirect()->away(app('auth0')->getSdk()->authentication()->getLogoutLink()); + } + + return redirect()->intended('/'); + } +} diff --git a/src/Http/Middleware/Stateful/Authenticate.php b/src/Http/Middleware/Stateful/Authenticate.php new file mode 100644 index 00000000..b9c8bf69 --- /dev/null +++ b/src/Http/Middleware/Stateful/Authenticate.php @@ -0,0 +1,35 @@ +guard('auth0')->check()) { + auth()->guard('auth0')->login(auth()->guard('auth0')->user()); + return $next($request); + } + + return redirect('login'); + } +} diff --git a/src/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Http/Middleware/Stateful/AuthenticateOptional.php new file mode 100644 index 00000000..cc21fa50 --- /dev/null +++ b/src/Http/Middleware/Stateful/AuthenticateOptional.php @@ -0,0 +1,34 @@ +guard('auth0')->check()) { + auth()->guard('auth0')->login(auth()->guard('auth0')->user()); + } + + return $next($request); + } +} diff --git a/src/Http/Middleware/Stateless/Authorize.php b/src/Http/Middleware/Stateless/Authorize.php new file mode 100644 index 00000000..fad1a240 --- /dev/null +++ b/src/Http/Middleware/Stateless/Authorize.php @@ -0,0 +1,34 @@ +guard('auth0')->check()) { + auth()->login(auth()->guard('auth0')->user()); + return $next($request); + } + + return abort(403, 'Unauthorized'); + } +} diff --git a/src/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Http/Middleware/Stateless/AuthorizeOptional.php new file mode 100644 index 00000000..b6df87d0 --- /dev/null +++ b/src/Http/Middleware/Stateless/AuthorizeOptional.php @@ -0,0 +1,32 @@ +guard('auth0')->check()) { + auth()->guard('auth0')->login(auth()->guard('auth0')->user()); + } + + return $next($request); + } +} diff --git a/src/Model/Stateful/User.php b/src/Model/Stateful/User.php new file mode 100644 index 00000000..18a31b94 --- /dev/null +++ b/src/Model/Stateful/User.php @@ -0,0 +1,9 @@ +profile = $profile; + $this->idToken = $idToken; + $this->accessToken = $accessToken; + $this->accessTokenScope = $accessTokenScope; + $this->accessTokenExpiration = $accessTokenExpiration; + $this->accessTokenExpired = $accessTokenExpired; + $this->refreshToken = $refreshToken; + } + + /** + * Add a generic getter to get all the properties of the user. + * + * @return mixed|null Returns the related value, or null if not set. + */ + public function __get( + string $name + ) { + return array_key_exists($name, $this->profile) ? $this->profile[$name] : null; + } + + /** + * Return a JSON-encoded representation of the user. + */ + public function __toString(): string + { + return json_encode($this->profile, JSON_THROW_ON_ERROR, 512); + } + + /** + * Get the unique identifier for the user. + * + * @return mixed + */ + public function getAuthIdentifier() + { + if (isset($this->profile['sub'])) { + return $this->profile['sub']; + } + + return $this->profile['user_id']; + } + + /** + * Get the name of the unique identifier for the user. + * + * @return string + */ + public function getAuthIdentifierName() + { + return 'id'; + } + + /** + * Get the password for the user. + * + * @return string + */ + public function getAuthPassword(): string + { + return ''; + } + + /** + * Get the token value for the "remember me" session. + */ + public function getRememberToken(): string + { + return ''; + } + + /** + * Set the token value for the "remember me" session. + * + * @param string $value + * + * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + */ + public function setRememberToken( + $value + ): void { + } + + /** + * Get the column name for the "remember me" token. + */ + public function getRememberTokenName(): string + { + return ''; + } + + public function getProfile(): ?array + { + return $this->profile; + } + + public function getIdToken(): ?string + { + return $this->idToken; + } + + public function getAccessToken(): ?string + { + return $this->accessToken; + } + + public function getAccessTokenScope(): ?array + { + return $this->accessTokenScope; + } + + public function getAccessTokenExpiration(): ?int + { + return $this->accessTokenExpiration; + } + + public function getAccessTokenExpired(): ?bool + { + return $this->accessTokenExpired; + } + + public function getRefreshToken(): ?string + { + return $this->refreshToken; + } +} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php new file mode 100644 index 00000000..32a51434 --- /dev/null +++ b/src/ServiceProvider.php @@ -0,0 +1,52 @@ +name('auth0') + ->hasConfigFile(); + } + + /** + * Register application services. + */ + public function registeringPackage(): void + { + app()->singleton(Auth0::class, static function (): \Auth0\Laravel\Auth0 { + return new Auth0(); + }); + + app()->singleton('auth0', static function (): \Auth0\Laravel\Auth0 { + return app()->make(Auth0::class); + }); + + app()->singleton(StateInstance::class, static function (): \Auth0\Laravel\StateInstance { + return new StateInstance(); + }); + + app()->singleton(\Auth0\Laravel\Auth\User\Repository::class, static function (): \Auth0\Laravel\Auth\User\Repository { + return new \Auth0\Laravel\Auth\User\Repository(); + }); + } + + /** + * Register middleware and guard. + */ + public function bootingPackage(): void + { + auth()->provider('auth0', static function ($app, array $config): \Auth0\Laravel\Auth\User\Provider { + return new \Auth0\Laravel\Auth\User\Provider(app()->make($config['repository'])); + }); + + auth()->extend('auth0', static function ($app, $name, array $config): \Auth0\Laravel\Auth\Guard { + return new \Auth0\Laravel\Auth\Guard(auth()->createUserProvider($config['provider']), $app->make('request')); + }); + } +} diff --git a/src/StateInstance.php b/src/StateInstance.php new file mode 100644 index 00000000..faa3b819 --- /dev/null +++ b/src/StateInstance.php @@ -0,0 +1,22 @@ +user = $user; + return $this; + } + + public function getUser(): ?\Illuminate\Contracts\Auth\Authenticatable + { + return $this->user; + } +} diff --git a/src/controllers/Auth0Controller.php b/src/controllers/Auth0Controller.php deleted file mode 100644 index 63628060..00000000 --- a/src/controllers/Auth0Controller.php +++ /dev/null @@ -1,58 +0,0 @@ -userRepository = $userRepository; - } - - /** - * Callback action that should be called by auth0, logs the user in. - */ - public function callback() - { - // Get a handle of the Auth0 service (we don't know if it has an alias) - $service = \App::make('auth0'); - - // Try to get the user information - $profile = $service->getUser(); - - // Get the user related to the profile - $auth0User = $profile ? $this->userRepository->getUserByUserInfo($profile) : null; - - if ($auth0User) { - // If we have a user, we are going to log them in, but if - // there is an onLogin defined we need to allow the Laravel developer - // to implement the user as they want an also let them store it. - if ($service->hasOnLogin()) { - $user = $service->callOnLogin($auth0User); - } else { - // If not, the user will be fine - $user = $auth0User; - } - - \Auth::login($user, $service->rememberUser()); - } - - return \Redirect::intended('/'); - } -} diff --git a/src/facade/Auth0.php b/src/facade/Auth0.php index ff6f799b..f2e8d8ee 100644 --- a/src/facade/Auth0.php +++ b/src/facade/Auth0.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace Auth0\Login\Facade; +namespace Auth0\Laravel\Facade; -class Auth0 extends \Illuminate\Support\Facades\Facade +final class Auth0 extends \Illuminate\Support\Facades\Facade { /** * Get the registered name of the component. From ac0efbd8e4ebdad52413adb97ae5eb41c30671dd Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Jan 2022 09:29:54 -0500 Subject: [PATCH 059/525] Remove obsolete code/files (#243) --- .phpcs.xml.dist | 188 --------------- config/config.php | 100 -------- phpstan.neon | 10 - src/Auth0JWTUser.php | 103 -------- src/Auth0Service.php | 320 ------------------------- src/Auth0User.php | 114 --------- src/Auth0UserProvider.php | 93 ------- src/Contract/Auth0UserRepository.php | 31 --- src/LaravelSessionStore.php | 64 ----- src/LoginServiceProvider.php | 89 ------- src/Repository/Auth0UserRepository.php | 58 ----- 11 files changed, 1170 deletions(-) delete mode 100644 .phpcs.xml.dist delete mode 100644 config/config.php delete mode 100644 phpstan.neon delete mode 100644 src/Auth0JWTUser.php delete mode 100644 src/Auth0Service.php delete mode 100644 src/Auth0User.php delete mode 100644 src/Auth0UserProvider.php delete mode 100644 src/Contract/Auth0UserRepository.php delete mode 100644 src/LaravelSessionStore.php delete mode 100644 src/LoginServiceProvider.php delete mode 100644 src/Repository/Auth0UserRepository.php diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist deleted file mode 100644 index 8a537ea2..00000000 --- a/.phpcs.xml.dist +++ /dev/null @@ -1,188 +0,0 @@ - - Auth0 PHP coding standard - - - src - - - vendor/ - - - - - - - - - - - - - - - error - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/config.php b/config/config.php deleted file mode 100644 index 16b1dc6f..00000000 --- a/config/config.php +++ /dev/null @@ -1,100 +0,0 @@ - env( 'AUTH0_DOMAIN' ), - - /* - |-------------------------------------------------------------------------- - | Your APP id - |-------------------------------------------------------------------------- - | As set in the auth0 administration page - |-------------------------------------------------------------------------- - */ - 'client_id' => env( 'AUTH0_CLIENT_ID' ), - - /* - |-------------------------------------------------------------------------- - | Your APP secret - |-------------------------------------------------------------------------- - | As set in the auth0 administration page - |-------------------------------------------------------------------------- - */ - 'client_secret' => env( 'AUTH0_CLIENT_SECRET' ), - - /* - |-------------------------------------------------------------------------- - | The redirect URI - |-------------------------------------------------------------------------- - | Should be the same that the one configure in the route to handle the - | 'Auth0\Login\Auth0Controller@callback' - |-------------------------------------------------------------------------- - */ - 'redirect_uri' => env( 'APP_URL' ).'/auth0/callback', - - /* - |-------------------------------------------------------------------------- - | Persistence Configuration - |-------------------------------------------------------------------------- - | persist_user (Boolean) Optional. Indicates if you want to persist the user info, default true - | persist_access_token (Boolean) Optional. Indicates if you want to persist the access token, default false - | persist_refresh_token (Boolean) Optional. Indicates if you want to persist the refresh token, default false - | persist_id_token (Boolean) Optional. Indicates if you want to persist the id token, default false - |-------------------------------------------------------------------------- - */ - 'persist_user' => true, - 'persist_access_token' => false, - 'persist_refresh_token' => false, - 'persist_id_token' => false, - - /* - |-------------------------------------------------------------------------- - | The authorized token audiences - |-------------------------------------------------------------------------- - */ - // 'api_identifier' => '', - - /* - |-------------------------------------------------------------------------- - | Auth0 Organizations - |-------------------------------------------------------------------------- - | organization (string) Optional. Id of an Organization, if being used. Used when generating log in urls and validating token claims. - |-------------------------------------------------------------------------- - */ - // 'organization' => '', - - /* - |-------------------------------------------------------------------------- - | The secret format - |-------------------------------------------------------------------------- - | Used to know if it should decode the secret when using HS256 - |-------------------------------------------------------------------------- - */ - 'secret_base64_encoded' => false, - - /* - |-------------------------------------------------------------------------- - | Supported algorithms - |-------------------------------------------------------------------------- - | Token decoding algorithms supported by your API - |-------------------------------------------------------------------------- - */ - 'supported_algs' => [ 'RS256' ], - - /* - |-------------------------------------------------------------------------- - | Guzzle Options - |-------------------------------------------------------------------------- - | guzzle_options (array) optional. Used to specify additional connection options e.g. proxy settings - |-------------------------------------------------------------------------- - */ - // 'guzzle_options' => [] -]; diff --git a/phpstan.neon b/phpstan.neon deleted file mode 100644 index 56a236c5..00000000 --- a/phpstan.neon +++ /dev/null @@ -1,10 +0,0 @@ -parameters: - level: 2 - - paths: - - src - - ignoreErrors: - - '#Call to static method#' - - reportUnmatchedIgnoredErrors: false diff --git a/src/Auth0JWTUser.php b/src/Auth0JWTUser.php deleted file mode 100644 index f242062f..00000000 --- a/src/Auth0JWTUser.php +++ /dev/null @@ -1,103 +0,0 @@ -userInfo = $userInfo; - } - - /** - * Get the unique identifier for the user. - * - * @return mixed - */ - public function getAuthIdentifierName() - { - return $this->userInfo['sub']; - } - - /** - * Get the unique identifier for the user. - * - * @return mixed - */ - public function getAuthIdentifier() - { - return $this->userInfo['sub']; - } - - /** - * @return void - */ - public function getAuthPassword() - { - } - - /** - * @return void - */ - public function getRememberToken() - { - } - - /** - * @param string $value - */ - public function setRememberToken($value) - { - } - - /** - * @return void - */ - public function getRememberTokenName() - { - } - - /** - * Add a generic getter to get all the properties of the userInfo. - * - * @return mixed the related value or null if it is not set - */ - public function __get($name) - { - if (! array_key_exists($name, $this->userInfo)) { - return; - } - - return $this->userInfo[$name]; - } - - /** - * @return array - */ - public function getUserInfo() - { - return $this->userInfo; - } - - /** - * @return string - */ - public function __toString() - { - return json_encode($this->userInfo); - } -} diff --git a/src/Auth0Service.php b/src/Auth0Service.php deleted file mode 100644 index 4e6eae2d..00000000 --- a/src/Auth0Service.php +++ /dev/null @@ -1,320 +0,0 @@ -make('cache.store'); - } - - $auth0Config['cache_handler'] = $cache; - - if (isset($auth0Config['api_identifier'])) { - // Auth0\SDK\Auth0 is using `audience` to create a login link. - $auth0Config['audience'] = $auth0Config['api_identifier']; - } - - $this->auth0Config = $auth0Config; - $this->auth0 = new Auth0($auth0Config); - } - - /** - * Creates an instance of the Auth0 SDK using - * the config set in the laravel way and using a LaravelSession - * as a store mechanism. - */ - private function getSDK() - { - return $this->auth0; - } - - /** - * Instantiate a singleton of the Auth0 Authentication class, using the provided configuration. - */ - private function getAuthenticationClass() - { - if (isset($this->singletons['authentication'])) { - return $this->singletons['authentication']; - } - - return $this->singletons['authentication'] = new \Auth0\SDK\API\Authentication( - $this->auth0Config['domain'] ?? null, - $this->auth0Config['client_id'] ?? null, - $this->auth0Config['client_secret'] ?? null, - $this->auth0Config['audience'] ?? null, - null, - [], - $this->auth0Config['organization'] ?? null, - ); - } - - /** - * Logs the user out from the SDK. - */ - public function logout() - { - $this->getSDK()->logout(); - } - - /** - * Redirects the user to the hosted login page - */ - public function login($connection = null, $state = null, $additional_params = ['scope' => 'openid profile email'], $response_type = 'code') - { - if ($connection && ! isset( $additional_params['connection'] )) { - $additional_params['connection'] = $connection; - } - - if ($state && ! isset( $additional_params['state'] )) { - $additional_params['state'] = $state; - } - - $additional_params['response_type'] = $response_type; - $auth_url = $this->auth0->getLoginUrl($additional_params); - - return new RedirectResponse($auth_url); - } - - /** - * Start passwordless login process for email - * - * @param string $email Email address to use. - * @param string $type Use null or "link" to send a link, use "code" to send a verification code. - * @param array $authParams Optional. Link parameters (like scope, redirect_uri, protocol, response_type) to modify. - * @param string|null $forwardedFor Optional. Source IP address. requires Trust Token Endpoint IP Header - * - * @link https://auth0.com/docs/api/authentication#get-code-or-link - */ - public function emailPasswordlessStart( - string $email, - string $type, - array $authParams = [], - ?string $forwardedFor = null - ): array { - return $this->getAuthenticationClass()->email_passwordless_start($email, $type, $authParams, $forwardedFor); - } - - /** - * Start passwordless login process for SMS. - * - * @param string $phoneNumber Phone number to use. - * @param string|null $forwardedFor Optional. Source IP address. requires Trust Token Endpoint IP Header - * - * @link https://auth0.com/docs/api/authentication#get-code-or-link - */ - public function smsPasswordlessStart( - string $phoneNumber, - ?string $forwardedFor = null - ): array { - return $this->getAuthenticationClass()->sms_passwordless_start($phoneNumber, $forwardedFor); - } - - /** - * If invitation parameters are present in the request, handle extraction and automatically redirect to Universal Login. - */ - public function handleInvitation() - { - $this->getSDK()->handleInvitation(); - } - - /** - * Extract invitation details from any incoming GET request. - */ - public function getInvitationParameters() - { - return $this->getSDK()->getInvitationParameters(); - } - - /** - * If the user is logged in, returns the user information. - * - * @return array with the User info as described in https://docs.auth0.com/user-profile and the user access token - */ - public function getUser() - { - // Get the user info from auth0 - $auth0 = $this->getSDK(); - $user = $auth0->getUser(); - - if ($user === null) { - return; - } - - return [ - 'profile' => $user, - 'accessToken' => $auth0->getAccessToken(), - ]; - } - - /** - * Sets a callback to be called when the user is logged in. - * - * @param mixed $cb A function that receives an auth0User and receives a Laravel user - */ - public function onLogin($cb) - { - $this->onLoginCb = $cb; - } - - /** - * @return bool - */ - public function hasOnLogin() - { - return $this->onLoginCb !== null; - } - - /** - * @param \Illuminate\Contracts\Auth\Authenticatable $auth0User - * - * @return mixed - */ - public function callOnLogin($auth0User) - { - $user = call_user_func($this->onLoginCb, $auth0User); - - if(is_array($user) || method_exists($user, 'toArray')) { - if(! is_array($user)) { - $array = $user->toArray(); - } else { - $array = $user; - } - - $this->getSDK()->setUser($array); - } - - return $user; - } - - /** - * Use this to either enable or disable the "remember" function for users. - * - * @param null $value - * - * @return bool|null - */ - public function rememberUser($value = null) - { - if ($value !== null) { - $this->rememberUser = $value; - } - - return $this->rememberUser; - } - - /** - * @param string $encUser - * @param array $verifierOptions - * - * @return array - * - * @throws \Auth0\SDK\Exception\InvalidTokenException - */ - public function decodeJWT($encUser, array $verifierOptions = []) - { - $token_issuer = 'https://'.$this->auth0Config['domain'].'/'; - $apiIdentifier = $this->auth0Config['api_identifier']; - $idTokenAlg = $this->auth0Config['supported_algs'][0] ?? 'RS256'; - - $signature_verifier = null; - if ($idTokenAlg === 'RS256') { - $jwksUri = $this->auth0Config['jwks_uri'] ?? 'https://'.$this->auth0Config['domain'].'/.well-known/jwks.json'; - $jwks_fetcher = new JWKFetcher($this->auth0Config['cache_handler']); - $jwks = $jwks_fetcher->getKeys($jwksUri); - $signature_verifier = new AsymmetricVerifier($jwks); - } elseif ($idTokenAlg === 'HS256') { - $signature_verifier = new SymmetricVerifier($this->auth0Config['client_secret']); - } else { - throw new \Auth0\SDK\Exception\InvalidTokenException('Unsupported token signing algorithm configured. Must be either RS256 or HS256.'); - } - - // Use IdTokenVerifier since Auth0-issued JWTs contain the 'sub' claim, which is used by the Laravel user model - $token_verifier = new TokenVerifier( - $token_issuer, - $apiIdentifier, - $signature_verifier - ); - - $this->apiuser = $token_verifier->verify($encUser, $verifierOptions); - return $this->apiuser; - } - - public function getIdToken() - { - return $this->getSDK()->getIdToken(); - } - - public function getAccessToken() - { - return $this->getSDK()->getAccessToken(); - } - - public function getRefreshToken() - { - return $this->getSDK()->getRefreshToken(); - } - - public function jwtuser() - { - return $this->apiuser; - } -} diff --git a/src/Auth0User.php b/src/Auth0User.php deleted file mode 100644 index 6d78295e..00000000 --- a/src/Auth0User.php +++ /dev/null @@ -1,114 +0,0 @@ -userInfo = $userInfo; - $this->accessToken = $accessToken; - } - - /** - * Get the unique identifier for the user. - * - * @return mixed - */ - public function getAuthIdentifier() - { - if (isset($this->userInfo['sub'])) { - return $this->userInfo['sub']; - } - - return $this->userInfo['user_id']; - } - - /** - * Get id field name. - * - * @return string - */ - public function getAuthIdentifierName() - { - return 'id'; - } - - /** - * Get the password for the user. - * - * @return string - */ - public function getAuthPassword() - { - return $this->accessToken; - } - - /** - * @return void - */ - public function getRememberToken() - { - } - - /** - * @param string $value - */ - public function setRememberToken($value) - { - } - - /** - * @return void - */ - public function getRememberTokenName() - { - } - - /** - * Add a generic getter to get all the properties of the userInfo. - * - * @return mixed|null Returns the related value, or null if not set. - */ - public function __get($name) - { - if (! array_key_exists($name, $this->userInfo)) { - return; - } - - return $this->userInfo[$name]; - } - - /** - * @return mixed - */ - public function getUserInfo() - { - return $this->userInfo; - } - - /** - * @return string - */ - public function __toString() - { - return json_encode($this->userInfo); - } -} diff --git a/src/Auth0UserProvider.php b/src/Auth0UserProvider.php deleted file mode 100644 index 2bd60a7e..00000000 --- a/src/Auth0UserProvider.php +++ /dev/null @@ -1,93 +0,0 @@ -userRepository = $userRepository; - $this->auth0 = $auth0; - } - - /** - * Lets make the repository take care of returning the user related to the - * identifier. - * - * @param mixed $identifier - * - * @return Authenticatable - */ - public function retrieveByID($identifier) - { - return $this->userRepository->getUserByIdentifier($identifier); - } - - /** - * @param array $credentials - * - * @return bool|Authenticatable - */ - public function retrieveByCredentials(array $credentials) - { - if (! isset($credentials['api_token'])) { - return null; - } - - $encUser = $credentials['api_token']; - - try { - $decodedJWT = $this->auth0->decodeJWT($encUser); - } catch (\Auth0\SDK\Exception\CoreException $e) { - return null; - } catch (\Auth0\SDK\Exception\InvalidTokenException $e) { - return null; - } - - return $this->userRepository->getUserByDecodedJWT($decodedJWT); - } - - /** - * Required method by the UserProviderInterface, we don't implement it. - */ - public function retrieveByToken($identifier, $token) - { - return null; - } - - /** - * Required method by the UserProviderInterface, we don't implement it. - */ - public function updateRememberToken(Authenticatable $user, $token) - { - } - - /** - * Required method by the UserProviderInterface, we don't implement it. - */ - public function validateCredentials(Authenticatable $user, array $credentials) - { - return null; - } -} diff --git a/src/Contract/Auth0UserRepository.php b/src/Contract/Auth0UserRepository.php deleted file mode 100644 index 92f79740..00000000 --- a/src/Contract/Auth0UserRepository.php +++ /dev/null @@ -1,31 +0,0 @@ -getSessionKeyName($key); - - \session([$key_name => $value]); - } - - /** - * @param string $key - * @param null $default - * - * @return mixed - */ - public function get(string $key, $default = null) - { - $key_name = $this->getSessionKeyName($key); - - return \session($key_name, $default); - } - - /** - * Removes a persisted value identified by $key. - * - * @see Auth0SDK\BaseAuth0 - * - * @param string $key - */ - public function delete(string $key) - { - $key_name = $this->getSessionKeyName($key); - - \session([$key_name => null]); - } - - /** - * Constructs a session var name. - * - * @param string $key - * - * @return string - */ - public function getSessionKeyName($key) - { - return self::BASE_NAME.'_'.$key; - } -} diff --git a/src/LoginServiceProvider.php b/src/LoginServiceProvider.php deleted file mode 100644 index df71b58a..00000000 --- a/src/LoginServiceProvider.php +++ /dev/null @@ -1,89 +0,0 @@ -make(Auth0UserProvider::class); - }); - - Auth::extend('auth0', static function ($app, $name, $config) { - return new RequestGuard(static function (Request $request, Auth0UserProvider $provider) { - return $provider->retrieveByCredentials(['api_token' => $request->bearerToken()]); - }, $app['request'], $app['auth']->createUserProvider($config['provider'])); - }); - - $this->publishes([ - __DIR__.'/../../config/config.php' => config_path('laravel-auth0.php'), - ]); - - $laravel = app(); - - $oldInfoHeaders = ApiClient::getInfoHeadersData(); - - if ($oldInfoHeaders) { - $infoHeaders = InformationHeaders::Extend($oldInfoHeaders); - - $infoHeaders->setEnvProperty('Laravel', $laravel::VERSION); - $infoHeaders->setPackage('laravel-auth0', self::SDK_VERSION); - - ApiClient::setInfoHeadersData($infoHeaders); - } - } - - /** - * Register the service provider. - */ - public function register() - { - $this->app->bind(StoreInterface::class, static function () { - return new LaravelSessionStore(); - }); - - $this->app->bind(Auth0UserRepositoryContract::class, Auth0UserRepository::class); - - // Bind the auth0 name to a singleton instance of the Auth0 Service - $this->app->singleton(Auth0Service::class, static function ($app) { - return new Auth0Service( - $app->make('config')->get('laravel-auth0'), - $app->make(StoreInterface::class), - $app->make('cache.store') - ); - }); - $this->app->singleton('auth0', function () { - return $this->app->make(Auth0Service::class); - }); - - // When Laravel logs out, logout the auth0 SDK trough the service - Event::listen('auth.logout', static function () { - app('auth0')->logout(); - }); - Event::listen('user.logout', static function () { - app('auth0')->logout(); - }); - Event::listen('Illuminate\Auth\Events\Logout', static function () { - app('auth0')->logout(); - }); - } -} diff --git a/src/Repository/Auth0UserRepository.php b/src/Repository/Auth0UserRepository.php deleted file mode 100644 index 94439e5e..00000000 --- a/src/Repository/Auth0UserRepository.php +++ /dev/null @@ -1,58 +0,0 @@ -getUser(); - - if ($user === null) { - return null; - } - - // Build the user - $auth0User = $this->getUserByUserInfo($user); - - // It is not the same user as logged in, it is not valid - if ($auth0User && $auth0User->getAuthIdentifier() === $identifier) { - return $auth0User; - } - - return null; - } -} From e490b88faa5f557a600d4a968b743600b2b28808 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Jan 2022 14:37:12 -0500 Subject: [PATCH 060/525] Setup test suite environment (#244) --- .editorconfig | 12 ++++++++ infection.json.dist | 15 ++++++++++ phpinsights.php | 69 +++++++++++++++++++++++++++++++++++++++++++++ phpstan.neon.dist | 30 ++++++++++++++++++++ phpunit.xml.dist | 42 +++++++++++---------------- psalm.xml.dist | 26 +++++++++++++++++ tests/constants.php | 18 ++++++++++++ 7 files changed, 187 insertions(+), 25 deletions(-) create mode 100644 .editorconfig create mode 100644 infection.json.dist create mode 100644 phpinsights.php create mode 100644 phpstan.neon.dist create mode 100644 psalm.xml.dist create mode 100644 tests/constants.php diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..6471f462 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true + +# We use 4 space indentation for PHP +[*.php] +indent_style = space +indent_size = 4 diff --git a/infection.json.dist b/infection.json.dist new file mode 100644 index 00000000..e3bfe945 --- /dev/null +++ b/infection.json.dist @@ -0,0 +1,15 @@ +{ + "source": { + "directories": [ + "src" + ] + }, + "logs": { + "text": "infection.log", + "perMutator": "infection.mutators.md" + }, + "mutators": { + "@default": true + }, + "testFramework": "pest" +} diff --git a/phpinsights.php b/phpinsights.php new file mode 100644 index 00000000..f637e740 --- /dev/null +++ b/phpinsights.php @@ -0,0 +1,69 @@ + 'default', + 'ide' => null, + + 'exclude' => [ + // 'path/to/directory-or-file' + ], + + 'add' => [ + \NunoMaduro\PhpInsights\Domain\Metrics\Code\Comments::class => [ + \SlevomatCodingStandard\Sniffs\Classes\RequireMultiLineMethodSignatureSniff::class, + ], + ], + + 'remove' => [ + \NunoMaduro\PhpInsights\Domain\Insights\CyclomaticComplexityIsHigh::class, + \NunoMaduro\PhpInsights\Domain\Insights\ForbiddenGlobals::class, + \NunoMaduro\PhpInsights\Domain\Insights\ForbiddenNormalClasses::class, + \NunoMaduro\PhpInsights\Domain\Insights\ForbiddenTraits::class, + \NunoMaduro\PhpInsights\Domain\Sniffs\ForbiddenSetterSniff::class, + \ObjectCalisthenics\Sniffs\Files\ClassTraitAndInterfaceLengthSniff::class, + \ObjectCalisthenics\Sniffs\Files\FunctionLengthSniff::class, + \ObjectCalisthenics\Sniffs\Metrics\MethodPerClassLimitSniff::class, + \ObjectCalisthenics\Sniffs\Metrics\MaxNestingLevelSniff::class, + \PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff::class, + \PHP_CodeSniffer\Standards\Generic\Sniffs\Commenting\TodoSniff::class, + \SlevomatCodingStandard\Sniffs\Classes\SuperfluousExceptionNamingSniff::class, + \SlevomatCodingStandard\Sniffs\Classes\SuperfluousInterfaceNamingSniff::class, + \SlevomatCodingStandard\Sniffs\Classes\UnusedPrivateElementsSniff::class, + \SlevomatCodingStandard\Sniffs\Functions\FunctionLengthSniff::class, + \SlevomatCodingStandard\Sniffs\TypeHints\DisallowMixedTypeHintSniff::class, + \SlevomatCodingStandard\Sniffs\TypeHints\ParameterTypeHintSniff::class, + \SlevomatCodingStandard\Sniffs\TypeHints\PropertyTypeHintSniff::class, + \SlevomatCodingStandard\Sniffs\TypeHints\ReturnTypeHintSniff::class, + ], + + 'config' => [ + \PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\DeprecatedFunctionsSniff::class => [ + 'exclude' => [ + // 'src/Token/Verifier.php', + ], + ], + \SlevomatCodingStandard\Sniffs\Functions\UnusedParameterSniff::class => [ + 'exclude' => [ + 'src/ServiceProvider.php', + ], + ], + \SlevomatCodingStandard\Sniffs\Classes\ModernClassNameReferenceSniff::class => [ + 'exclude' => [ + // 'src/Mixins/ConfigurableMixin.php', + ], + ], + \SlevomatCodingStandard\Sniffs\Classes\RequireMultiLineMethodSignatureSniff::class => [ + 'minLineLength' => '0', + ], + ], + + 'requirements' => [ + 'min-quality' => 100, + 'min-complexity' => 50, + 'min-architecture' => 100, + 'min-style' => 100, + 'disable-security-check' => false, + ], +]; diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 00000000..55191b64 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,30 @@ +includes: + - vendor/phpstan/phpstan-strict-rules/rules.neon + - vendor/ergebnis/phpstan-rules/rules.neon + - vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon + +parameters: + level: max + + paths: + - src + + bootstrapFiles: + - tests/constants.php + + ignoreErrors: + - '#Function (app|auth|event|redirect) not found.#' + - '#Constructor in (.*) has parameter (.*) with default value.#' + - '#Constructor in (.*) has parameter (.*) with null as default value.#' + - '#Method (.*) has parameter (.*) with a nullable type declaration.#' + - '#Method (.*) has parameter (.*) with null as default value.#' + - '#Method (.*) has a nullable return type declaration.#' + - '#Language construct isset\(\) should not be used.#' + - '#Method (.*) has parameter (.*) with no value type specified in iterable type array.#' + - '#not allowed to extend#' + - '#no value type specified in iterable type array.#' + - '#is not final, but since the containing class is abstract, it should be.#' + - '#Class "Auth0\\Login\\Exception\\(.*)" is not allowed to extend "Exception".#' + - '#Class "Auth0\\Laravel\\Exception\\(.*)" is not allowed to extend "Exception".#' + + reportUnmatchedIgnoredErrors: false diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 9228d485..ba93708e 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,26 +1,18 @@ - - - - - tests - - - - - src/ - - - - - - + + + + + ./src/ + + + + + tests/Unit + + + + + + + diff --git a/psalm.xml.dist b/psalm.xml.dist new file mode 100644 index 00000000..9f21c863 --- /dev/null +++ b/psalm.xml.dist @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/tests/constants.php b/tests/constants.php new file mode 100644 index 00000000..c826ac9b --- /dev/null +++ b/tests/constants.php @@ -0,0 +1,18 @@ + Date: Mon, 10 Jan 2022 15:45:28 -0500 Subject: [PATCH 061/525] Composer package manifest updates (#245) --- .circleci/config.yml | 5 +---- composer.json | 42 ++++++++++++++++++++++++++---------------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 644c757b..00438d42 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -70,9 +70,6 @@ jobs: workflows: run-tests: jobs: - - run-unit-tests: - name: run-phpunit-7.3 - php: "7.3" - run-unit-tests: name: run-phpunit-7.4 php: "7.4" @@ -85,4 +82,4 @@ workflows: only: - main context: snyk-env - requires: [run-phpunit-7.3] + requires: [run-phpunit-7.4] diff --git a/composer.json b/composer.json index 0c6cc280..23456dec 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "auth0/login", - "description": "Laravel plugin that helps authenticate with the Auth0 service", + "description": "Auth0 Laravel SDK. Straight-forward and tested methods for implementing authentication, and accessing Auth0's Management API endpoints.", "type": "library", "keywords": [ "laravel", @@ -29,23 +29,33 @@ } ], "require": { - "php": "^7.3 || ^8.0", - "ext-json": "*", - "ext-openssl": "*", + "php": "^7.4 || ^8.0, <8.2", "ext-filter": "*", + "ext-json": "*", "ext-mbstring": "*", - "auth0/auth0-php": "^7.9", - "illuminate/support": " ^6.0 || ^7.0 || ^8.0", - "illuminate/contracts": "^6.0 || ^7.0 || ^8.0" + "ext-openssl": "*", + "auth0/auth0-php": "^8.0", + "illuminate/contracts": "^8.0 || ^9.0", + "illuminate/http": "^8.0 || ^9.0", + "illuminate/support": " ^8.0 || ^9.0", + "spatie/laravel-package-tools": "^1.9" }, "require-dev": { - "nunomaduro/phpinsights": "^1.13 || ^2.0", - "phpunit/phpunit": "^9.5", - "orchestra/testbench": "^4.0 || ^5.0", - "nunomaduro/larastan": "^0.7" - }, - "conflict": { - "lcobucci/jwt": "*" + "ergebnis/phpstan-rules": "^0.15", + "firebase/php-jwt": "^5.0", + "hyperf/event": "^2.2", + "infection/infection": "^0.23", + "mockery/mockery": "^1.4", + "nunomaduro/phpinsights": "^2.0", + "nyholm/psr7": "^1.4", + "pestphp/pest": "^1.18", + "pestphp/pest-plugin-parallel": "^0.2", + "php-http/mock-client": "^1.4", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "symfony/cache": "^4.4 || ^5.2", + "thecodingmachine/phpstan-strict-rules": "^0.12", + "vimeo/psalm": "^4.10" }, "autoload": { "psr-4": { @@ -60,10 +70,10 @@ "extra": { "laravel": { "providers": [ - "Auth0\\Login\\LoginServiceProvider" + "Auth0\\Laravel\\ServiceProvider" ], "aliases": { - "Auth0": "Auth0\\Login\\Facade\\Auth0" + "Auth0": "Auth0\\Laravel\\Facade\\Auth0" } } }, From ab636f3f2f46e5f8e692d9afc0c896c698d8c69e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 14 Jan 2022 16:40:02 -0500 Subject: [PATCH 062/525] Configure PHPInsights and PHPStan, remove Psalm (#246) --- composer.json | 42 ++++++++++++++++++++++++++---------------- docker-compose.yml | 25 ------------------------- phpinsights.php | 8 ++------ phpstan.neon.dist | 3 +++ psalm.xml.dist | 26 -------------------------- 5 files changed, 31 insertions(+), 73 deletions(-) delete mode 100644 docker-compose.yml delete mode 100644 psalm.xml.dist diff --git a/composer.json b/composer.json index 23456dec..35e4c274 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ } ], "require": { - "php": "^7.4 || ^8.0, <8.2", + "php": "^7.4 || ^8.0", "ext-filter": "*", "ext-json": "*", "ext-mbstring": "*", @@ -41,21 +41,16 @@ "spatie/laravel-package-tools": "^1.9" }, "require-dev": { - "ergebnis/phpstan-rules": "^0.15", - "firebase/php-jwt": "^5.0", - "hyperf/event": "^2.2", - "infection/infection": "^0.23", - "mockery/mockery": "^1.4", + "ergebnis/phpstan-rules": "^1.0", + "nunomaduro/larastan": "^1.0", "nunomaduro/phpinsights": "^2.0", "nyholm/psr7": "^1.4", - "pestphp/pest": "^1.18", - "pestphp/pest-plugin-parallel": "^0.2", - "php-http/mock-client": "^1.4", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-strict-rules": "^0.12", - "symfony/cache": "^4.4 || ^5.2", - "thecodingmachine/phpstan-strict-rules": "^0.12", - "vimeo/psalm": "^4.10" + "orchestra/testbench": "6.0", + "pestphp/pest": "^1.21", + "pestphp/pest-plugin-laravel": "^1.2", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^9.5", + "thecodingmachine/phpstan-strict-rules": "^1.0" }, "autoload": { "psr-4": { @@ -82,7 +77,22 @@ "sort-packages": true }, "scripts": { - "format": "docker compose run --rm format", - "tests": "docker compose run --rm tests" + "tests": [ + "@tests:phpinsights", + "@tests:phpstan", + "@tests:pest" + ], + "tests:phpinsights": [ + "Composer\\Config::disableProcessTimeout", + "@php ./vendor/bin/phpinsights -v --no-interaction" + ], + "tests:phpstan": [ + "Composer\\Config::disableProcessTimeout", + "@php ./vendor/bin/phpstan analyse --ansi --memory-limit 512M" + ], + "tests:pest": [ + "Composer\\Config::disableProcessTimeout", + "@php ./vendor/bin/pest --stop-on-failure --coverage" + ] } } diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 9da6c4c8..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,25 +0,0 @@ -version: "3.9" - -services: - tests: - image: composer:2.1 - volumes: - - ./:/app - working_dir: /app - command: > - sh -c "rm -f ./composer.lock && - composer validate && - composer install && - php ./vendor/bin/phpstan analyze --ansi --debug --memory-limit 512M && - php ./vendor/bin/phpunit --coverage-text && - php ./vendor/bin/phpcs" - - format: - image: composer:2.1 - volumes: - - ./:/app - working_dir: /app - command: > - sh -c "rm -f ./composer.lock && - composer install && - php ./vendor/bin/phpcbf" diff --git a/phpinsights.php b/phpinsights.php index f637e740..b8eed12a 100644 --- a/phpinsights.php +++ b/phpinsights.php @@ -3,12 +3,10 @@ declare(strict_types=1); return [ - 'preset' => 'default', + 'preset' => 'laravel', 'ide' => null, - 'exclude' => [ - // 'path/to/directory-or-file' - ], + 'exclude' => [], 'add' => [ \NunoMaduro\PhpInsights\Domain\Metrics\Code\Comments::class => [ @@ -41,7 +39,6 @@ 'config' => [ \PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\DeprecatedFunctionsSniff::class => [ 'exclude' => [ - // 'src/Token/Verifier.php', ], ], \SlevomatCodingStandard\Sniffs\Functions\UnusedParameterSniff::class => [ @@ -51,7 +48,6 @@ ], \SlevomatCodingStandard\Sniffs\Classes\ModernClassNameReferenceSniff::class => [ 'exclude' => [ - // 'src/Mixins/ConfigurableMixin.php', ], ], \SlevomatCodingStandard\Sniffs\Classes\RequireMultiLineMethodSignatureSniff::class => [ diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 55191b64..6e534aa6 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -22,9 +22,12 @@ parameters: - '#Language construct isset\(\) should not be used.#' - '#Method (.*) has parameter (.*) with no value type specified in iterable type array.#' - '#not allowed to extend#' + - '#Cannot call method (.*) on mixed#' - '#no value type specified in iterable type array.#' - '#is not final, but since the containing class is abstract, it should be.#' - '#Class "Auth0\\Login\\Exception\\(.*)" is not allowed to extend "Exception".#' - '#Class "Auth0\\Laravel\\Exception\\(.*)" is not allowed to extend "Exception".#' + - '#Call to an undefined method Illuminate\\(.*).#' + - '#\$hash is never read, only written.#' reportUnmatchedIgnoredErrors: false diff --git a/psalm.xml.dist b/psalm.xml.dist deleted file mode 100644 index 9f21c863..00000000 --- a/psalm.xml.dist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - From ade8bcb2e66b0eae3a73f4387e1965ecce6fd75d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 14 Jan 2022 16:46:48 -0500 Subject: [PATCH 063/525] Docblock updates and minor code quality improvements (#247) --- src/Auth/Guard.php | 18 ++++++- src/Auth/User/Provider.php | 6 ++- src/Auth/User/Repository.php | 33 +++++++++++++ src/Event/Auth0Event.php | 21 ++++++++ src/Event/Stateful/AuthenticationFailed.php | 33 ++++++++++++- .../Stateful/AuthenticationSucceeded.php | 21 +++++++- src/Http/Controller/Stateful/Callback.php | 24 ++++++++-- src/Http/Controller/Stateful/Logout.php | 6 +++ src/Model/User.php | 48 +++++++++++++++++++ src/StateInstance.php | 13 +++++ 10 files changed, 213 insertions(+), 10 deletions(-) create mode 100644 src/Event/Auth0Event.php diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index e33df9bd..03c4d415 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -113,7 +113,17 @@ public function guest(): bool */ public function id() { - return $this->user() !== null ? $this->user()->getAuthIdentifier() : null; + $response = null; + + if ($this->user() !== null) { + $id = $this->user()->getAuthIdentifier(); + + if (is_string($id) || is_int($id)) { + $response = $id; + } + } + + return $response; } /** @@ -215,7 +225,11 @@ public function getTokenForRequest(): ?string $token = $this->request->getPassword(); } - return $token; + if ($token !== null && is_string($token)) { + return $token; + } + + return null; } private function getInstance(): \Auth0\Laravel\StateInstance diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php index 9d751db5..f46ef267 100644 --- a/src/Auth/User/Provider.php +++ b/src/Auth/User/Provider.php @@ -8,8 +8,6 @@ final class Provider implements \Illuminate\Contracts\Auth\UserProvider { private Repository $repository; - private \Auth0\Laravel\Auth0 $service; - /** * Auth0UserProvider constructor. * @@ -27,6 +25,10 @@ public function __construct( public function retrieveById( $identifier ): ?\Illuminate\Contracts\Auth\Authenticatable { + if (! is_string($identifier)) { + return null; + } + $decoded = app('auth0')->getSdk()->decode($identifier, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_ID_TOKEN)->toArray(); $scope = $decoded['scope'] ?? ''; diff --git a/src/Auth/User/Repository.php b/src/Auth/User/Repository.php index 78efe13a..41005f72 100644 --- a/src/Auth/User/Repository.php +++ b/src/Auth/User/Repository.php @@ -6,6 +6,17 @@ final class Repository { + /** + * Generate a \Auth0\Laravel\Model\Stateful\User instance from an available Auth0-PHP user session. + * + * @param array $profile An array containing the raw Auth0 user data. + * @param string|null $idToken An ID Token used by the user context. Null when unavailable. + * @param string|null $accessToken An Access Token used by the user context. Null when unavailable. + * @param array|null $accessTokenScope An array of scopes requested/returned during authentication for the user context. Null when unavailable. + * @param int|null $accessTokenExpiration A unix timestamp representing when an access token expires, if available. + * @param bool|null $accessTokenExpired Returns true if the access token has expired, if an expiration timestamp was available. + * @param string|null $refreshToken A Refresh Token used by the user context. Null when unavailable. + */ public function fromSession( array $profile, ?string $idToken, @@ -26,6 +37,17 @@ public function fromSession( ); } + /** + * Generate a \Auth0\Laravel\Model\Stateful\User instance from a parsed Access Token. + * + * @param array $profile An array containing the raw Auth0 user data. + * @param string|null $idToken An ID Token used by the user context. Null when unavailable. + * @param string|null $accessToken An Access Token used by the user context. Null when unavailable. + * @param array|null $accessTokenScope An array of scopes requested/returned during authentication for the user context. Null when unavailable. + * @param int|null $accessTokenExpiration A unix timestamp representing when an access token expires, if available. + * @param bool|null $accessTokenExpired Returns true if the access token has expired, if an expiration timestamp was available. + * @param string|null $refreshToken A Refresh Token used by the user context. Null when unavailable. + */ public function fromAccessToken( array $profile, ?string $idToken, @@ -46,6 +68,17 @@ public function fromAccessToken( ); } + /** + * Generate a \Auth0\Laravel\Model\Stateful\User instance from a parsed ID Token. + * + * @param array $profile An array containing the raw Auth0 user data. + * @param string|null $idToken An ID Token used by the user context. Null when unavailable. + * @param string|null $accessToken An Access Token used by the user context. Null when unavailable. + * @param array|null $accessTokenScope An array of scopes requested/returned during authentication for the user context. Null when unavailable. + * @param int|null $accessTokenExpiration A unix timestamp representing when an access token expires, if available. + * @param bool|null $accessTokenExpired Returns true if the access token has expired, if an expiration timestamp was available. + * @param string|null $refreshToken A Refresh Token used by the user context. Null when unavailable. + */ public function fromIdToken( array $profile, ?string $idToken, diff --git a/src/Event/Auth0Event.php b/src/Event/Auth0Event.php new file mode 100644 index 00000000..df04dded --- /dev/null +++ b/src/Event/Auth0Event.php @@ -0,0 +1,21 @@ +mutated; + } +} diff --git a/src/Event/Stateful/AuthenticationFailed.php b/src/Event/Stateful/AuthenticationFailed.php index 70992db0..9b49d642 100644 --- a/src/Event/Stateful/AuthenticationFailed.php +++ b/src/Event/Stateful/AuthenticationFailed.php @@ -4,12 +4,26 @@ namespace Auth0\Laravel\Event\Stateful; -final class AuthenticationFailed +use Throwable; + +final class AuthenticationFailed extends \Auth0\Laravel\Event\Auth0Event { + /** + * An exception instance in which to throw for the authentication failure. + */ private \Throwable $exception; + /** + * Whether or not $exception will be thrown. + */ private bool $throwException = true; + /** + * AuthenticationFailed constructor. + * + * @param Throwable $exception An exception instance in which to throw for the authentication failure. + * @param bool $throwException Whether or not $exception will be thrown. + */ public function __construct( \Throwable $exception, bool $throwException = true @@ -18,18 +32,32 @@ public function __construct( $this->throwException = $throwException; } + /** + * Overwrite the exception to be thrown. + * + * @param Throwable $exception An exception instance in which to throw for the authentication failure. + */ public function setException( \Throwable $exception ): self { $this->exception = $exception; + $this->mutated = true; return $this; } + /** + * Returns the exception to be thrown. + */ public function getException(): \Throwable { return $this->exception; } + /** + * Determine whether the provided exception will be thrown by the SDK. + * + * @param bool $throwException Whether or not $exception will be thrown. + */ public function setThrowException( bool $throwException ): self { @@ -37,6 +65,9 @@ public function setThrowException( return $this; } + /** + * Returns whether the provided exception will be thrown by the SDK. + */ public function getThrowException(): bool { return $this->throwException; diff --git a/src/Event/Stateful/AuthenticationSucceeded.php b/src/Event/Stateful/AuthenticationSucceeded.php index 7e4651bd..1257e316 100644 --- a/src/Event/Stateful/AuthenticationSucceeded.php +++ b/src/Event/Stateful/AuthenticationSucceeded.php @@ -4,23 +4,42 @@ namespace Auth0\Laravel\Event\Stateful; -final class AuthenticationSucceeded +use Illuminate\Contracts\Auth\Authenticatable; + +final class AuthenticationSucceeded extends \Auth0\Laravel\Event\Auth0Event { + /** + * An instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user. + */ private \Illuminate\Contracts\Auth\Authenticatable $user; + /** + * AuthenticationSucceeded constructor. + * + * @param Authenticatable $user An instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user. + */ public function __construct( \Illuminate\Contracts\Auth\Authenticatable $user ) { $this->user = $user; } + /** + * Overwrite the authenticated user. + * + * @param Authenticatable $user An instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user. + */ public function setUser( \Illuminate\Contracts\Auth\Authenticatable $user ): self { $this->user = $user; + $this->mutated = true; return $this; } + /** + * Return the authenticated user. + */ public function getUser(): \Illuminate\Contracts\Auth\Authenticatable { return $this->user; diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index cd0d5ea0..a9ae780a 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -6,6 +6,11 @@ final class Callback { + /** + * Process the session for the end user after returning from authenticating with Auth0. + * + * @param \Illuminate\Http\Request $request The incoming request instance. + */ public function __invoke( \Illuminate\Http\Request $request ): \Illuminate\Http\RedirectResponse { @@ -18,7 +23,6 @@ public function __invoke( try { if ($request->query('state') !== null && $request->query('code') !== null) { app('auth0')->getSdk()->exchange(); - // var_dump(app('auth0')->getSdk()->getUser()); } } catch (\Throwable $exception) { app('auth0')->getSdk()->clear(); @@ -34,9 +38,9 @@ public function __invoke( } if ($request->query('error') !== null && $request->query('error_description') !== null) { - // Workaround to aid static analysis, due to the lax formatting of the query() response: - $error = $request->query('error') ?? ''; - $errorDescription = $request->query('error_description') ?? ''; + // Workaround to aid static analysis, due to the mixed formatting of the query() response: + $error = $request->query('error', ''); + $errorDescription = $request->query('error_description', ''); $error = is_string($error) ? $error : ''; $errorDescription = is_string($errorDescription) ? $error : ''; @@ -56,6 +60,18 @@ public function __invoke( } } + // Ensure we have a valid user: + $user = auth()->guard('auth0')->user(); + + if ($user !== null) { + // Throw hookable event to allow custom application logic for successful logins: + $event = new \Auth0\Laravel\Event\Stateful\AuthenticationSucceeded($user); + event($event); + + // Apply any mutations to the user object: + auth()->guard('auth0')->setUser($event->getUser()); + } + return redirect()->intended('/'); } } diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index af77c44f..9a19a96e 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -6,6 +6,12 @@ final class Logout { + /** + * Redirect to Auth0's logout endpoint if a session is available. + * Otherwise, redirect to the "/" route. + * + * @param \Illuminate\Http\Request $request The incoming request instance. + */ public function __invoke( \Illuminate\Http\Request $request ): \Illuminate\Http\RedirectResponse { diff --git a/src/Model/User.php b/src/Model/User.php index 2c809926..0a8d6a8b 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -6,12 +6,39 @@ abstract class User implements \Illuminate\Contracts\Auth\Authenticatable { + /** + * Profile data for the user context, when available. + */ private array $profile; + + /** + * ID Token for the user context, when available. + */ private ?string $idToken; + + /** + * Access Token for the user context, when available. + */ private ?string $accessToken; + + /** + * Access Token scopes for the user context, when available. + */ private ?array $accessTokenScope; + + /** + * Access Token expiration timestamp for the user context, when available. + */ private ?int $accessTokenExpiration; + + /** + * Access Token expiration indicator for the user context, when available. + */ private ?bool $accessTokenExpired; + + /** + * Refresh Token for the user context, when available. + */ private ?string $refreshToken; /** @@ -116,36 +143,57 @@ public function getRememberTokenName(): string return ''; } + /** + * Return the profile data for the user context. Null when unavailable. + */ public function getProfile(): ?array { return $this->profile; } + /** + * Return the ID Token for the user context. Null when unavailable. + */ public function getIdToken(): ?string { return $this->idToken; } + /** + * Return the Access Token for the user context. Null when unavailable. + */ public function getAccessToken(): ?string { return $this->accessToken; } + /** + * Return the Access Token's scope for the user context. Null when unavailable. + */ public function getAccessTokenScope(): ?array { return $this->accessTokenScope; } + /** + * Return the Access Token's expiration (represented as a unix timestamp) for the user context. Null when unavailable. + */ public function getAccessTokenExpiration(): ?int { return $this->accessTokenExpiration; } + /** + * Return true if the Access Token has expired for the user context. Null when unavailable. + */ public function getAccessTokenExpired(): ?bool { return $this->accessTokenExpired; } + /** + * Return the Refresh Token for the user context. Null when unavailable. + */ public function getRefreshToken(): ?string { return $this->refreshToken; diff --git a/src/StateInstance.php b/src/StateInstance.php index faa3b819..ba42d68e 100644 --- a/src/StateInstance.php +++ b/src/StateInstance.php @@ -4,10 +4,20 @@ namespace Auth0\Laravel; +use Illuminate\Contracts\Auth\Authenticatable; + final class StateInstance { + /** + * An authenticated user context for the current request. + */ private ?\Illuminate\Contracts\Auth\Authenticatable $user = null; + /** + * Set the authenticated user context for the current request. + * + * @param Authenticatable|null $user An authenticated user context. + */ public function setUser( ?\Illuminate\Contracts\Auth\Authenticatable $user ): self { @@ -15,6 +25,9 @@ public function setUser( return $this; } + /** + * Return the authenticated user context for the current request. + */ public function getUser(): ?\Illuminate\Contracts\Auth\Authenticatable { return $this->user; From d5c656a3ae924126b24cdc99d72656ef28fec23d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 17 Jan 2022 12:05:36 -0500 Subject: [PATCH 064/525] Introduce Interfaces for library classes (#248) --- src/Auth/Guard.php | 69 ++++------- src/Auth/User/Provider.php | 21 ++-- src/Auth/User/Repository.php | 32 +---- src/Auth0.php | 28 ++++- src/Contract/Auth/Guard.php | 102 ++++++++++++++++ src/Contract/Auth/User/Provider.php | 63 ++++++++++ src/Contract/Auth/User/Repository.php | 71 +++++++++++ src/Contract/Auth0.php | 37 ++++++ src/Contract/Event/Auth0Event.php | 13 +++ .../Event/Stateful/AuthenticationFailed.php | 47 ++++++++ .../Stateful/AuthenticationSucceeded.php | 31 +++++ .../Exception/Stateful/CallbackException.php | 19 +++ .../Http/Controller/Stateful/Callback.php | 17 +++ .../Http/Controller/Stateful/Login.php | 18 +++ .../Http/Controller/Stateful/Logout.php | 18 +++ .../Http/Middleware/Stateful/Authenticate.php | 21 ++++ .../Stateful/AuthenticateOptional.php | 21 ++++ .../Http/Middleware/Stateless/Authorize.php | 21 ++++ .../Stateless/AuthorizeOptional.php | 21 ++++ src/Contract/Model/Stateful/User.php | 9 ++ src/Contract/Model/Stateless/User.php | 9 ++ src/Contract/Model/User.php | 110 ++++++++++++++++++ src/Contract/ServiceProvider.php | 25 ++++ src/Contract/StateInstance.php | 22 ++++ src/Event/Auth0Event.php | 5 +- src/Event/Stateful/AuthenticationFailed.php | 21 +--- .../Stateful/AuthenticationSucceeded.php | 14 +-- src/Exception/Stateful/CallbackException.php | 5 +- src/Http/Controller/Stateful/Callback.php | 6 +- src/Http/Controller/Stateful/Login.php | 7 +- src/Http/Controller/Stateful/Logout.php | 7 +- src/Http/Middleware/Stateful/Authenticate.php | 9 +- .../Stateful/AuthenticateOptional.php | 9 +- src/Http/Middleware/Stateless/Authorize.php | 9 +- .../Stateless/AuthorizeOptional.php | 9 +- src/Model/Stateful/User.php | 2 +- src/Model/Stateless/User.php | 2 +- src/Model/User.php | 44 +++---- src/ServiceProvider.php | 9 +- src/StateInstance.php | 8 +- src/facade/Auth0.php | 3 + 41 files changed, 817 insertions(+), 197 deletions(-) create mode 100644 src/Contract/Auth/Guard.php create mode 100644 src/Contract/Auth/User/Provider.php create mode 100644 src/Contract/Auth/User/Repository.php create mode 100644 src/Contract/Auth0.php create mode 100644 src/Contract/Event/Auth0Event.php create mode 100644 src/Contract/Event/Stateful/AuthenticationFailed.php create mode 100644 src/Contract/Event/Stateful/AuthenticationSucceeded.php create mode 100644 src/Contract/Exception/Stateful/CallbackException.php create mode 100644 src/Contract/Http/Controller/Stateful/Callback.php create mode 100644 src/Contract/Http/Controller/Stateful/Login.php create mode 100644 src/Contract/Http/Controller/Stateful/Logout.php create mode 100644 src/Contract/Http/Middleware/Stateful/Authenticate.php create mode 100644 src/Contract/Http/Middleware/Stateful/AuthenticateOptional.php create mode 100644 src/Contract/Http/Middleware/Stateless/Authorize.php create mode 100644 src/Contract/Http/Middleware/Stateless/AuthorizeOptional.php create mode 100644 src/Contract/Model/Stateful/User.php create mode 100644 src/Contract/Model/Stateless/User.php create mode 100644 src/Contract/Model/User.php create mode 100644 src/Contract/ServiceProvider.php create mode 100644 src/Contract/StateInstance.php diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 03c4d415..dd1af2f5 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -4,51 +4,35 @@ namespace Auth0\Laravel\Auth; -final class Guard implements \Illuminate\Contracts\Auth\Guard +final class Guard implements \Illuminate\Contracts\Auth\Guard, \Auth0\Laravel\Contract\Auth\Guard { /** * The user provider implementation. - * - * @var \Illuminate\Contracts\Auth\UserProvider */ - private $provider; + private \Illuminate\Contracts\Auth\UserProvider $provider; /** * The request instance. - * - * @var \Illuminate\Http\Request */ - private $request; + private \Illuminate\Http\Request $request; /** * The name of the query string item from the request containing the API token. - * - * @var string */ - private $inputKey; + private string $inputKey; /** * The name of the token "column" in persistent storage. - * - * @var string */ - private $storageKey; + private string $storageKey; /** * Indicates if the API token is hashed in storage. - * - * @var bool */ - private $hash = false; + private bool $hash = false; /** - * Create a new authentication guard. - * - * @param \Illuminate\Contracts\Auth\UserProvider $provider - * @param \Illuminate\Http\Request $request - * @param string $inputKey - * @param string $storageKey - * @param bool $hash + * @inheritdoc */ public function __construct( \Illuminate\Contracts\Auth\UserProvider $provider, @@ -65,9 +49,7 @@ public function __construct( } /** - * Set the current user. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @inheritdoc */ public function login( \Illuminate\Contracts\Auth\Authenticatable $user @@ -77,7 +59,7 @@ public function login( } /** - * Clear the current user. + * @inheritdoc */ public function logout(): self { @@ -87,9 +69,7 @@ public function logout(): self } /** - * Determine if the current user is authenticated. - * - * @return bool + * @inheritdoc */ public function check(): bool { @@ -97,9 +77,7 @@ public function check(): bool } /** - * Determine if the current user is a guest. - * - * @return bool + * @inheritdoc */ public function guest(): bool { @@ -107,9 +85,7 @@ public function guest(): bool } /** - * Get the ID for the currently authenticated user. - * - * @return int|string|null + * @inheritdoc */ public function id() { @@ -127,9 +103,7 @@ public function id() } /** - * Validate a user's credentials. - * - * @param array $credentials + * @inheritdoc */ public function validate( array $credentials = [] @@ -144,7 +118,7 @@ public function validate( } /** - * Determine if the guard has a user instance. + * @inheritdoc */ public function hasUser(): bool { @@ -152,9 +126,7 @@ public function hasUser(): bool } /** - * Set the current user. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @inheritdoc */ public function setUser( \Illuminate\Contracts\Auth\Authenticatable $user @@ -164,9 +136,7 @@ public function setUser( } /** - * Set the current request instance. - * - * @param \Illuminate\Http\Request $request + * @inheritdoc */ public function setRequest( \Illuminate\Http\Request $request @@ -176,7 +146,7 @@ public function setRequest( } /** - * Get the currently authenticated user. + * @inheritdoc */ public function user(): ?\Illuminate\Contracts\Auth\Authenticatable { @@ -207,7 +177,7 @@ public function user(): ?\Illuminate\Contracts\Auth\Authenticatable } /** - * Get the token for the current request. + * @inheritdoc */ public function getTokenForRequest(): ?string { @@ -232,6 +202,9 @@ public function getTokenForRequest(): ?string return null; } + /** + * Return the current request's StateInstance singleton. + */ private function getInstance(): \Auth0\Laravel\StateInstance { return app()->make(\Auth0\Laravel\StateInstance::class); diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php index f46ef267..bcfe4682 100644 --- a/src/Auth/User/Provider.php +++ b/src/Auth/User/Provider.php @@ -4,23 +4,24 @@ namespace Auth0\Laravel\Auth\User; -final class Provider implements \Illuminate\Contracts\Auth\UserProvider +final class Provider implements \Illuminate\Contracts\Auth\UserProvider, \Auth0\Laravel\Contract\Auth\User\Provider { + /** + * A repository instance. + */ private Repository $repository; /** - * Auth0UserProvider constructor. - * - * @param \Auth0\Laravel\Auth\User\Repository $repository + * @inheritdoc */ public function __construct( - Repository $repository + \Auth0\Laravel\Auth\User\Repository $repository ) { $this->repository = $repository; } /** - * Returns a \Auth0\Laravel\Model\Stateless\User instance from an Id Token. + * @inheritdoc */ public function retrieveById( $identifier @@ -45,7 +46,7 @@ public function retrieveById( } /** - * Returns a \Auth0\Laravel\Model\Stateless\User instance from an Access Token. + * @inheritdoc * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ @@ -68,7 +69,7 @@ public function retrieveByToken( } /** - * Returns a \Auth0\Laravel\Model\Stateless\User instance translated from an Auth0-PHP SDK session. + * @inheritdoc */ public function retrieveByCredentials( array $credentials @@ -85,7 +86,7 @@ public function retrieveByCredentials( } /** - * Returns true if the provided $user's unique identifier matches the credentials payload. + * @inheritdoc * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ @@ -97,7 +98,7 @@ public function validateCredentials( } /** - * Method required by interface. Not supported. + * @inheritdoc * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ diff --git a/src/Auth/User/Repository.php b/src/Auth/User/Repository.php index 41005f72..9245c84c 100644 --- a/src/Auth/User/Repository.php +++ b/src/Auth/User/Repository.php @@ -4,18 +4,10 @@ namespace Auth0\Laravel\Auth\User; -final class Repository +final class Repository implements \Auth0\Laravel\Contract\Auth\User\Repository { /** - * Generate a \Auth0\Laravel\Model\Stateful\User instance from an available Auth0-PHP user session. - * - * @param array $profile An array containing the raw Auth0 user data. - * @param string|null $idToken An ID Token used by the user context. Null when unavailable. - * @param string|null $accessToken An Access Token used by the user context. Null when unavailable. - * @param array|null $accessTokenScope An array of scopes requested/returned during authentication for the user context. Null when unavailable. - * @param int|null $accessTokenExpiration A unix timestamp representing when an access token expires, if available. - * @param bool|null $accessTokenExpired Returns true if the access token has expired, if an expiration timestamp was available. - * @param string|null $refreshToken A Refresh Token used by the user context. Null when unavailable. + * @inheritdoc */ public function fromSession( array $profile, @@ -38,15 +30,7 @@ public function fromSession( } /** - * Generate a \Auth0\Laravel\Model\Stateful\User instance from a parsed Access Token. - * - * @param array $profile An array containing the raw Auth0 user data. - * @param string|null $idToken An ID Token used by the user context. Null when unavailable. - * @param string|null $accessToken An Access Token used by the user context. Null when unavailable. - * @param array|null $accessTokenScope An array of scopes requested/returned during authentication for the user context. Null when unavailable. - * @param int|null $accessTokenExpiration A unix timestamp representing when an access token expires, if available. - * @param bool|null $accessTokenExpired Returns true if the access token has expired, if an expiration timestamp was available. - * @param string|null $refreshToken A Refresh Token used by the user context. Null when unavailable. + * @inheritdoc */ public function fromAccessToken( array $profile, @@ -69,15 +53,7 @@ public function fromAccessToken( } /** - * Generate a \Auth0\Laravel\Model\Stateful\User instance from a parsed ID Token. - * - * @param array $profile An array containing the raw Auth0 user data. - * @param string|null $idToken An ID Token used by the user context. Null when unavailable. - * @param string|null $accessToken An Access Token used by the user context. Null when unavailable. - * @param array|null $accessTokenScope An array of scopes requested/returned during authentication for the user context. Null when unavailable. - * @param int|null $accessTokenExpiration A unix timestamp representing when an access token expires, if available. - * @param bool|null $accessTokenExpired Returns true if the access token has expired, if an expiration timestamp was available. - * @param string|null $refreshToken A Refresh Token used by the user context. Null when unavailable. + * @inheritdoc */ public function fromIdToken( array $profile, diff --git a/src/Auth0.php b/src/Auth0.php index b2862860..ee5bf04f 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -7,7 +7,7 @@ /** * Service that provides access to the Auth0 SDK. */ -final class Auth0 +final class Auth0 implements \Auth0\Laravel\Contract\Auth0 { /** * The Laravel-Auth0 SDK version: @@ -25,7 +25,7 @@ final class Auth0 private ?\Auth0\SDK\Configuration\SdkConfiguration $configuration = null; /** - * Create/return instance of the Auth0-PHP SDK. + * @inheritdoc */ public function getSdk(): \Auth0\SDK\Auth0 { @@ -37,7 +37,17 @@ public function getSdk(): \Auth0\SDK\Auth0 } /** - * Create/return instance of the Auth0-PHP SdkConfiguration. + * @inheritdoc + */ + public function setSdk( + \Auth0\SDK\Auth0 $sdk + ): self { + $this->sdk = $sdk; + return $this; + } + + /** + * @inheritdoc */ public function getConfiguration(): \Auth0\SDK\Configuration\SdkConfiguration { @@ -49,7 +59,17 @@ public function getConfiguration(): \Auth0\SDK\Configuration\SdkConfiguration } /** - * Create/create a request state instance, a storage singleton containing authenticated user data. + * @inheritdoc + */ + public function setConfiguration( + \Auth0\SDK\Configuration\SdkConfiguration $configuration + ): self { + $this->configuration = $configuration; + return $this; + } + + /** + * @inheritdoc */ public function getState(): \Auth0\Laravel\StateInstance { diff --git a/src/Contract/Auth/Guard.php b/src/Contract/Auth/Guard.php new file mode 100644 index 00000000..43175680 --- /dev/null +++ b/src/Contract/Auth/Guard.php @@ -0,0 +1,102 @@ + Date: Mon, 17 Jan 2022 12:05:51 -0500 Subject: [PATCH 065/525] Introduce PEST unit testing (#249) --- .circleci/config.yml | 171 ++++++++++++++++++++++------------ composer.json | 1 + phpinsights.php | 1 + tests/Pest.php | 39 ++++++++ tests/TestCase.php | 27 ++++++ tests/Unit/Auth/GuardTest.php | 3 + tests/Unit/Auth0Test.php | 54 +++++++++++ tests/constants.php | 2 + 8 files changed, 240 insertions(+), 58 deletions(-) create mode 100644 tests/Pest.php create mode 100644 tests/TestCase.php create mode 100644 tests/Unit/Auth/GuardTest.php create mode 100644 tests/Unit/Auth0Test.php diff --git a/.circleci/config.yml b/.circleci/config.yml index 00438d42..4ee64cde 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,85 +1,140 @@ version: 2.1 commands: - prepare: + setup: steps: + - run: + name: Configure environment + command: | + apk update + - checkout + - run: - name: Perform composer self-update - command: sudo composer self-update - - restore-cache + name: Install dependencies + command: | + EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')" + php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" + ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")" + + if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then + >&2 echo 'ERROR: Invalid installer checksum' + rm composer-setup.php + exit 1 + fi + + php composer-setup.php --quiet + RESULT=$? + rm composer-setup.php + + php composer.phar install --no-interaction --prefer-dist + + setup-pcov: + steps: - run: - name: Enable code coverage + name: Configure pcov command: | - sudo apt update - sudo apt install libonig-dev - sudo pecl install pcov - sudo docker-php-ext-enable pcov - sudo rm /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini - sudo docker-php-ext-install posix - sudo docker-php-ext-install pcntl - sudo docker-php-ext-install mbstring + apk add autoconf gcc make musl-dev + pecl install pcov + docker-php-ext-enable pcov + + run-phpinsights: + steps: - run: - name: Install composer dependencies - command: composer install --no-interaction --prefer-dist + name: Run code quality analysis (PHP Insights) + command: php -d memory-limit=-1 ./vendor/bin/phpinsights -v --no-interaction --min-quality=100 --min-complexity=50 --min-architecture=100 --min-style=100 + + run-phpstan: + steps: - run: - name: Update composer dependencies - command: composer update --prefer-dist --no-interaction - - save-cache + name: Run static code analysis (PHPStan) + command: php -d memory_limit=-1 ./vendor/bin/phpstan analyse --ansi - save-cache: + run-pest: steps: - - persist_to_workspace: - root: . - paths: - - composer.* - - .snyk - - save_cache: - key: composer-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "composer.json" }} - paths: - - vendor + - run: + name: Run unit tests (Pest) + command: php -d memory_limit=-1 ./vendor/bin/pest --stop-on-failure --min=100 - restore-cache: + run-snyk: steps: - - restore_cache: - keys: - - composer-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "composer.json" }} - - composer-v1-{{ .Environment.CIRCLE_JOB }} + - run: + name: Run vulnerabilities tests (Snyk) + command: | + apk add npm + npm install -g snyk + snyk test --dev --org=auth0-sdks --project-name=auth0-PHP jobs: - run-unit-tests: + phpinsights: parameters: php: type: string docker: - - image: circleci/php:<< parameters.php >> + - image: php:<< parameters.php >>-cli-alpine steps: - - prepare - - run-security-tests: + - setup + - run-phpinsights + phpstan: + parameters: + php: + type: string docker: - - image: snyk/snyk-cli:composer + - image: php:<< parameters.php >>-cli-alpine steps: - - attach_workspace: - at: . - - run: snyk test + - setup + - run-phpstan + semgrep: + docker: + - image: returntocorp/semgrep:latest + steps: + - checkout - run: - command: snyk monitor --org=auth0-sdks --project-name=laravel-auth0 - when: always + name: Run static code analysis (Semgrep) + command: semgrep --config auto + pest: + parameters: + php: + type: string + docker: + - image: php:<< parameters.php >>-cli-alpine + steps: + - setup + - setup-pcov + - run-pest + snyk: + parameters: + php: + type: string + docker: + - image: php:<< parameters.php >>-cli-alpine + steps: + - setup + - run-snyk workflows: - run-tests: + test: jobs: - - run-unit-tests: - name: run-phpunit-7.4 - php: "7.4" - - run-unit-tests: - name: run-phpunit-8.0 - php: "8.0" - - run-security-tests: - filters: - branches: - only: - - main - context: snyk-env - requires: [run-phpunit-7.4] + - semgrep + - phpinsights: + matrix: + parameters: + php: ["7.4", "8.0", "8.1"] + - phpstan: + matrix: + parameters: + php: ["7.4", "8.0", "8.1"] + - pest: + matrix: + parameters: + php: ["7.4", "8.0", "8.1"] + - hold: + type: approval + - snyk: + matrix: + parameters: + php: ["7.4", "8.0", "8.1"] + context: + - snyk-env + requires: + - hold diff --git a/composer.json b/composer.json index 35e4c274..a7f7d5c2 100644 --- a/composer.json +++ b/composer.json @@ -41,6 +41,7 @@ "spatie/laravel-package-tools": "^1.9" }, "require-dev": { + "laravel/laravel": "^8.4.4 || ^9.0", "ergebnis/phpstan-rules": "^1.0", "nunomaduro/larastan": "^1.0", "nunomaduro/phpinsights": "^2.0", diff --git a/phpinsights.php b/phpinsights.php index b8eed12a..4760026b 100644 --- a/phpinsights.php +++ b/phpinsights.php @@ -34,6 +34,7 @@ \SlevomatCodingStandard\Sniffs\TypeHints\ParameterTypeHintSniff::class, \SlevomatCodingStandard\Sniffs\TypeHints\PropertyTypeHintSniff::class, \SlevomatCodingStandard\Sniffs\TypeHints\ReturnTypeHintSniff::class, + \SlevomatCodingStandard\Sniffs\Commenting\UselessInheritDocCommentSniff::class, ], 'config' => [ diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 00000000..c560eadc --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,39 @@ +beforeEach(function () { + $this->service = createService(); + }) + ->in(__DIR__); + +function createServiceConfiguration( + array $configuration = [] +): \Auth0\SDK\Configuration\SdkConfiguration { + $defaults = [ + 'strategy' => 'none' + ]; + + return new \Auth0\SDK\Configuration\SdkConfiguration(array_merge($defaults, $configuration)); +} + +function createService( + ?\Auth0\SDK\Configuration\SdkConfiguration $configuration = null +): \Auth0\Laravel\Auth0 { + if ($configuration === null) { + $configuration = createServiceConfiguration(); + } + + return (new \Auth0\Laravel\Auth0)->setConfiguration($configuration); +} + +function createSdk( + ?\Auth0\SDK\Configuration\SdkConfiguration $configuration = null +): \Auth0\SDK\Auth0 { + if ($configuration === null) { + $configuration = createServiceConfiguration(); + } + + return (new \Auth0\SDK\Auth0($configuration)); +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 00000000..1eb4c18f --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,27 @@ +app))->packageBooted(); + } +} diff --git a/tests/Unit/Auth/GuardTest.php b/tests/Unit/Auth/GuardTest.php new file mode 100644 index 00000000..174d7fd7 --- /dev/null +++ b/tests/Unit/Auth/GuardTest.php @@ -0,0 +1,3 @@ +service) + ->toBeInstanceOf(\Auth0\Laravel\Auth0::class); +}); + +test('the service instantiates it\'s own configuration if none is assigned', function() { + $service = new \Auth0\Laravel\Auth0; + + expect($service->getConfiguration()) + ->toBeInstanceOf(\Auth0\SDK\Configuration\SdkConfiguration::class); +})->throws(\Auth0\SDK\Exception\ConfigurationException::class); + +test('the service\'s getSdk() method returns an Auth0 SDK instance', function() { + expect($this->service->getSdk()) + ->toBeInstanceOf(\Auth0\SDK\Auth0::class); +}); + +test('the service\'s getConfiguration method returns an SdkConfiguration instance', function() { + expect($this->service->getConfiguration()) + ->toBeInstanceOf(\Auth0\SDK\Configuration\SdkConfiguration::class); +}); + +test('the service\'s getState method returns a StateInstance instance', function() { + expect($this->service->getState()) + ->toBeInstanceOf(\Auth0\Laravel\StateInstance::class); +}); + +test('the service\'s setSdk() method allows overwriting the Auth0 instance', function() { + $oldSdk = $this->service->getSdk(); + $newSdk = createSdk(); + + $this->service->setSdk($newSdk); + + expect($this->service->getSdk()) + ->toBe($newSdk) + ->not() + ->toBe($oldSdk); +}); + +test('the service\'s setConfiguration() method allows overwriting the SdkConfiguration instance', function() { + $oldConfiguration = $this->service->getConfiguration(); + $newConfiguration = createServiceConfiguration(); + + $this->service->setConfiguration($newConfiguration); + + expect($this->service->getConfiguration()) + ->toBe($newConfiguration) + ->not() + ->toBe($oldConfiguration); +}); diff --git a/tests/constants.php b/tests/constants.php index c826ac9b..d0505384 100644 --- a/tests/constants.php +++ b/tests/constants.php @@ -1,5 +1,7 @@ Date: Thu, 27 Jan 2022 11:03:12 -0500 Subject: [PATCH 066/525] Automatically handle refreshing tokens when a token expires (#250) --- config/auth0.php | 7 ++ src/Auth/Guard.php | 104 +++++++++++++++--- src/Auth/User/Provider.php | 72 +++++++----- src/Auth0.php | 15 ++- src/Contract/Event/Stateful/TokenExpired.php | 38 +++++++ .../Event/Stateful/TokenRefreshFailed.php | 9 ++ .../Event/Stateful/TokenRefreshSucceeded.php | 31 ++++++ .../Http/Middleware/Stateless/Authorize.php | 4 +- src/Event/Stateful/TokenExpired.php | 55 +++++++++ src/Event/Stateful/TokenRefreshFailed.php | 9 ++ src/Event/Stateful/TokenRefreshSucceeded.php | 41 +++++++ src/Http/Middleware/Stateful/Authenticate.php | 6 +- .../Stateful/AuthenticateOptional.php | 6 +- src/Http/Middleware/Stateless/Authorize.php | 13 ++- .../Stateless/AuthorizeOptional.php | 6 +- src/Model/Stateful/User.php | 3 + src/Model/Stateless/User.php | 3 + src/ServiceProvider.php | 6 + 18 files changed, 379 insertions(+), 49 deletions(-) create mode 100644 src/Contract/Event/Stateful/TokenExpired.php create mode 100644 src/Contract/Event/Stateful/TokenRefreshFailed.php create mode 100644 src/Contract/Event/Stateful/TokenRefreshSucceeded.php create mode 100644 src/Event/Stateful/TokenExpired.php create mode 100644 src/Event/Stateful/TokenRefreshFailed.php create mode 100644 src/Event/Stateful/TokenRefreshSucceeded.php diff --git a/config/auth0.php b/config/auth0.php index 6cae23c8..84c9a959 100644 --- a/config/auth0.php +++ b/config/auth0.php @@ -2,6 +2,10 @@ declare(strict_types=1); +/** + * Please review available configuration options here: + * https://github.com/auth0/auth0-PHP#configuration-options + */ return [ // Should be assigned either 'api', 'management', or 'webapp' to indicate your application's use case for the SDK. Determines what configuration options will be required at initialization. 'strategy' => env('AUTH0_STRATEGY', 'api'), @@ -24,6 +28,9 @@ // One or more API identifiers, found in your Auth0 API settings. The SDK uses the first value for building links. If provided, at least one of these values must match the 'aud' claim to validate an ID Token successfully. 'audience' => env('AUTH0_AUDIENCE', []), + // One or more scopes to request for Tokens. See https://auth0.com/docs/scopes + 'scope' => explode(' ', env('AUTH0_SCOPE', 'openid profile email')), + // One or more Organization IDs, found in your Auth0 Organization settings. The SDK uses the first value for building links. If provided, at least one of these values must match the 'org_id' claim to validate an ID Token successfully. 'organization' => env('AUTH0_ORGANIZATION', []), diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index dd1af2f5..f09681da 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -125,6 +125,21 @@ public function hasUser(): bool return ! is_null($this->getInstance()->getUser()); } + /** + * @inheritdoc + */ + public function hasScope( + string $scope + ): bool { + $user = $this->getInstance()->getUser(); + + if ($user !== null && in_array($scope, $user->getAccessTokenScope(), true)) { + return true; + } + + return false; + } + /** * @inheritdoc */ @@ -151,22 +166,16 @@ public function setRequest( public function user(): ?\Illuminate\Contracts\Auth\Authenticatable { $instance = $this->getInstance(); - $user = $instance->getUser(); + $user = null; + $token = $this->getTokenForRequest(); - if ($user === null) { - $stateful = app('auth0')->getSdk()->getCredentials(); - - if ($stateful !== null) { - $user = $this->provider->retrieveByCredentials((array) $stateful); - } + if ($token !== null) { + $user = $this->provider->retrieveByToken([], $token); } - if ($user === null) { - $token = $this->getTokenForRequest(); - - if ($token !== null) { - $user = $this->provider->retrieveByToken([], $token); - } + if ($user === null && $token === null) { + $user = $this->getUserFromSession(); + $user = $this->handleTokenExpiration($user); } if ($user !== null) { @@ -209,4 +218,73 @@ private function getInstance(): \Auth0\Laravel\StateInstance { return app()->make(\Auth0\Laravel\StateInstance::class); } + + /** + * Get the local user session. + */ + private function getUserFromSession(): ?\Illuminate\Contracts\Auth\Authenticatable + { + $session = app('auth0')->getSdk()->getCredentials(); + + if ($session !== null) { + return $this->provider->retrieveByCredentials((array) $session); + } + + return null; + } + + /** + * Handle instances of access token expiration. + */ + private function handleTokenExpiration( + ?\Illuminate\Contracts\Auth\Authenticatable $user + ): ?\Illuminate\Contracts\Auth\Authenticatable { + if ($user === null) { + return null; + } + + if ($user->getAccessTokenExpired() === false) { + return $user; + } + + // Did we scope with 'offline_access' (and does the API allow) for a refresh token? + if ($user->getRefreshToken() !== null) { + try { + app('auth0')->getSdk()->renew(); + } catch (\Auth0\SDK\Exception\StateException $tokenRefreshFailed) { + // Inform the host application token refresh failed, to enable custom handling behavior + event(new \Auth0\Laravel\Event\Stateful\TokenRefreshFailed()); + } + + // Retrieve any potentially updated state data + $refreshed = $this->getUserFromSession(); + + // Was refreshed successfully? + if ($refreshed !== null && $refreshed->getAccessTokenExpired() === false) { + // Inform the host application to enable custom handling behavior + $event = new \Auth0\Laravel\Event\Stateful\TokenRefreshSucceeded($refreshed); + event($event); + + return $event->getUser(); + } + } + + // We didn't have a refresh token, or the refresh failed. Inform host application. + $event = new \Auth0\Laravel\Event\Stateful\TokenExpired($user); + event($event); + + // Did the host application override default expiration handling? + if ($event->getUser()->getAccessTokenExpired() === false) { + // Unless the host application expressly opted into not clearing the local user session, do so: + return $event->getUser(); + } + + if ($event->getClearSession() === true) { + // Clear the local user session: + $this->getInstance()->setUser(null); + app('auth0')->getSdk()->clear(); + } + + return null; + } } diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php index bcfe4682..34ec5a2b 100644 --- a/src/Auth/User/Provider.php +++ b/src/Auth/User/Provider.php @@ -30,19 +30,30 @@ public function retrieveById( return null; } - $decoded = app('auth0')->getSdk()->decode($identifier, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_ID_TOKEN)->toArray(); - $scope = $decoded['scope'] ?? ''; - - // Process $identifier here ... - return $this->repository->fromAccessToken( - $decoded, - null, - $identifier, - explode(' ', $scope), - null, - null, - null, - ); + try { + $decoded = app('auth0')->getSdk()->decode($identifier, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_ID_TOKEN)->toArray(); + } catch (\Auth0\SDK\Exception\InvalidTokenException $invalidToken) { + $decoded = null; + } + + if ($decoded !== null) { + $scope = $decoded['scope'] ?? ''; + $exp = $decoded['exp'] ?? null; + $expired = time() > $exp; + + // Process $identifier here ... + return $this->repository->fromAccessToken( + $decoded, + null, + $identifier, + explode(' ', $scope), + $exp, + $expired, + null, + ); + } + + return null; } /** @@ -54,18 +65,29 @@ public function retrieveByToken( $identifier, $token ): ?\Illuminate\Contracts\Auth\Authenticatable { - $decoded = app('auth0')->getSdk()->decode($token, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_TOKEN)->toArray(); - $scope = $decoded['scope'] ?? ''; - - return $this->repository->fromAccessToken( - $decoded, - null, - $token, - explode(' ', $scope), - null, - null, - null, - ); + try { + $decoded = app('auth0')->getSdk()->decode($token, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_TOKEN)->toArray(); + } catch (\Auth0\SDK\Exception\InvalidTokenException $invalidToken) { + $decoded = null; + } + + if ($decoded !== null) { + $scope = $decoded['scope'] ?? ''; + $exp = $decoded['exp'] ?? null; + $expired = time() > $exp; + + return $this->repository->fromAccessToken( + $decoded, + null, + $token, + explode(' ', $scope), + $exp, + $expired, + null, + ); + } + + return null; } /** diff --git a/src/Auth0.php b/src/Auth0.php index ee5bf04f..a828b93a 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -12,7 +12,7 @@ final class Auth0 implements \Auth0\Laravel\Contract\Auth0 /** * The Laravel-Auth0 SDK version: */ - public const SDK_VERSION = '7.0.0'; + public const VERSION = '7.0.0'; /** * An instance of the Auth0-PHP SDK. @@ -31,6 +31,7 @@ public function getSdk(): \Auth0\SDK\Auth0 { if ($this->sdk === null) { $this->sdk = new \Auth0\SDK\Auth0($this->getConfiguration()); + $this->setSdkTelemetry(); } return $this->sdk; @@ -43,6 +44,7 @@ public function setSdk( \Auth0\SDK\Auth0 $sdk ): self { $this->sdk = $sdk; + $this->setSdkTelemetry(); return $this; } @@ -75,4 +77,15 @@ public function getState(): \Auth0\Laravel\StateInstance { return app()->make(\Auth0\Laravel\StateInstance::class); } + + /** + * Updates the Auth0 PHP SDK's telemetry to include the correct Laravel markers. + */ + private function setSdkTelemetry(): self + { + \Auth0\SDK\Utility\HttpTelemetry::setEnvProperty('Laravel', app()->version()); + \Auth0\SDK\Utility\HttpTelemetry::setPackage('laravel-auth0', self::VERSION); + + return $this; + } } diff --git a/src/Contract/Event/Stateful/TokenExpired.php b/src/Contract/Event/Stateful/TokenExpired.php new file mode 100644 index 00000000..fde2efe1 --- /dev/null +++ b/src/Contract/Event/Stateful/TokenExpired.php @@ -0,0 +1,38 @@ +user = $user; + $this->clearSession = $clearSession; + } + + /** + * @inheritdoc + */ + public function getUser(): \Illuminate\Contracts\Auth\Authenticatable + { + return $this->user; + } + + /** + * @inheritdoc + */ + public function setClearSession( + bool $clearSession + ): self { + $this->clearSession = $clearSession; + return $this; + } + + /** + * @inheritdoc + */ + public function getClearSession(): bool + { + return $this->clearSession; + } +} diff --git a/src/Event/Stateful/TokenRefreshFailed.php b/src/Event/Stateful/TokenRefreshFailed.php new file mode 100644 index 00000000..a430dc18 --- /dev/null +++ b/src/Event/Stateful/TokenRefreshFailed.php @@ -0,0 +1,9 @@ +user = $user; + } + + /** + * @inheritdoc + */ + public function setUser( + \Illuminate\Contracts\Auth\Authenticatable $user + ): self { + $this->user = $user; + $this->mutated = true; + return $this; + } + + /** + * @inheritdoc + */ + public function getUser(): \Illuminate\Contracts\Auth\Authenticatable + { + return $this->user; + } +} diff --git a/src/Http/Middleware/Stateful/Authenticate.php b/src/Http/Middleware/Stateful/Authenticate.php index 5033ae82..1313b7de 100644 --- a/src/Http/Middleware/Stateful/Authenticate.php +++ b/src/Http/Middleware/Stateful/Authenticate.php @@ -20,8 +20,10 @@ public function handle( \Illuminate\Http\Request $request, \Closure $next ) { - if (auth()->guard('auth0')->check()) { - auth()->guard('auth0')->login(auth()->guard('auth0')->user()); + $user = auth()->guard('auth0')->user(); + + if ($user !== null && $user instanceof \Auth0\Laravel\Model\Stateful\User) { + auth()->guard('auth0')->login($user); return $next($request); } diff --git a/src/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Http/Middleware/Stateful/AuthenticateOptional.php index e1c82b77..de4daaa9 100644 --- a/src/Http/Middleware/Stateful/AuthenticateOptional.php +++ b/src/Http/Middleware/Stateful/AuthenticateOptional.php @@ -20,8 +20,10 @@ public function handle( \Illuminate\Http\Request $request, \Closure $next ) { - if (auth()->guard('auth0')->check()) { - auth()->guard('auth0')->login(auth()->guard('auth0')->user()); + $user = auth()->guard('auth0')->user(); + + if ($user !== null && $user instanceof \Auth0\Laravel\Model\Stateful\User) { + auth()->guard('auth0')->login($user); } return $next($request); diff --git a/src/Http/Middleware/Stateless/Authorize.php b/src/Http/Middleware/Stateless/Authorize.php index 388de822..c16354c7 100644 --- a/src/Http/Middleware/Stateless/Authorize.php +++ b/src/Http/Middleware/Stateless/Authorize.php @@ -17,10 +17,17 @@ final class Authorize implements \Auth0\Laravel\Contract\Http\Middleware\Statele */ public function handle( \Illuminate\Http\Request $request, - \Closure $next + \Closure $next, + string $scope = '' ) { - if (auth()->guard('auth0')->check()) { - auth()->login(auth()->guard('auth0')->user()); + $user = auth()->guard('auth0')->user(); + + if ($user !== null && $user instanceof \Auth0\Laravel\Model\Stateless\User) { + if (strlen($scope) >= 1 && auth()->guard('auth0')->hasScope($scope) === false) { + return abort(403, 'Unauthorized'); + } + + auth()->login($user); return $next($request); } diff --git a/src/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Http/Middleware/Stateless/AuthorizeOptional.php index 710abf43..24336569 100644 --- a/src/Http/Middleware/Stateless/AuthorizeOptional.php +++ b/src/Http/Middleware/Stateless/AuthorizeOptional.php @@ -18,8 +18,10 @@ public function handle( \Illuminate\Http\Request $request, \Closure $next ) { - if (auth()->guard('auth0')->check()) { - auth()->guard('auth0')->login(auth()->guard('auth0')->user()); + $user = auth()->guard('auth0')->user(); + + if ($user !== null && $user instanceof \Auth0\Laravel\Model\Stateless\User) { + auth()->guard('auth0')->login($user); } return $next($request); diff --git a/src/Model/Stateful/User.php b/src/Model/Stateful/User.php index 4a717637..36dd495e 100644 --- a/src/Model/Stateful/User.php +++ b/src/Model/Stateful/User.php @@ -4,6 +4,9 @@ namespace Auth0\Laravel\Model\Stateful; +/** + * This model class represents a user authenticated by an Auth0 PHP session. + */ final class User extends \Auth0\Laravel\Model\User implements \Auth0\Laravel\Contract\Model\Stateful\User { } diff --git a/src/Model/Stateless/User.php b/src/Model/Stateless/User.php index af969c70..3e23e52e 100644 --- a/src/Model/Stateless/User.php +++ b/src/Model/Stateless/User.php @@ -4,6 +4,9 @@ namespace Auth0\Laravel\Model\Stateless; +/** + * This model class represents a user authorized by a bearer token. + */ final class User extends \Auth0\Laravel\Model\User implements \Auth0\Laravel\Contract\Model\Stateless\User { } diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index ffbedd7b..55a6df0a 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -51,5 +51,11 @@ public function bootingPackage(): void auth()->extend('auth0', static function ($app, $name, array $config): \Auth0\Laravel\Auth\Guard { return new \Auth0\Laravel\Auth\Guard(auth()->createUserProvider($config['provider']), $app->make('request')); }); + + $router = app()->make(\Illuminate\Routing\Router::class); + $router->aliasMiddleware('auth0.authenticate', \Auth0\Laravel\Http\Middleware\Stateful\Authenticate::class); + $router->aliasMiddleware('auth0.authenticate.optional', \Auth0\Laravel\Http\Middleware\Stateful\AuthenticateOptional::class); + $router->aliasMiddleware('auth0.authorize', \Auth0\Laravel\Http\Middleware\Stateless\Authorize::class); + $router->aliasMiddleware('auth0.authorize.optional', \Auth0\Laravel\Http\Middleware\Stateless\AuthorizeOptional::class); } } From b92117b585308d975dccb85dea8fb70f5644f407 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 28 Jan 2022 09:56:30 -0500 Subject: [PATCH 067/525] Finalize configuration file format (#251) --- .gitignore | 1 + composer.json | 17 ++++++- config/auth0.php | 30 ++++++++---- src/Configuration.php | 46 +++++++++++++++++++ src/Contract/Configuration.php | 30 ++++++++++++ src/Http/Controller/Stateful/Callback.php | 4 +- src/Http/Controller/Stateful/Login.php | 2 +- src/Http/Controller/Stateful/Logout.php | 2 +- src/Http/Middleware/Stateful/Authenticate.php | 2 +- 9 files changed, 118 insertions(+), 16 deletions(-) create mode 100644 src/Configuration.php create mode 100644 src/Contract/Configuration.php diff --git a/.gitignore b/.gitignore index 4bbb6625..a4ec8e0a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ vendor/ composer.lock composer.phar .phpunit.result.cache +composer.local.json diff --git a/composer.json b/composer.json index a7f7d5c2..d7adfda6 100644 --- a/composer.json +++ b/composer.json @@ -41,8 +41,8 @@ "spatie/laravel-package-tools": "^1.9" }, "require-dev": { - "laravel/laravel": "^8.4.4 || ^9.0", "ergebnis/phpstan-rules": "^1.0", + "laravel/laravel": "^8.4.4 || ^9.0", "nunomaduro/larastan": "^1.0", "nunomaduro/phpinsights": "^2.0", "nyholm/psr7": "^1.4", @@ -51,7 +51,8 @@ "pestphp/pest-plugin-laravel": "^1.2", "phpstan/phpstan-strict-rules": "^1.1", "phpunit/phpunit": "^9.5", - "thecodingmachine/phpstan-strict-rules": "^1.0" + "thecodingmachine/phpstan-strict-rules": "^1.0", + "wikimedia/composer-merge-plugin": "^2.0" }, "autoload": { "psr-4": { @@ -71,6 +72,18 @@ "aliases": { "Auth0": "Auth0\\Laravel\\Facade\\Auth0" } + }, + "merge-plugin": { + "include": [ + "composer.local.json" + ], + "recurse": true, + "replace": true, + "ignore-duplicates": false, + "merge-dev": true, + "merge-extra": false, + "merge-extra-deep": false, + "merge-scripts": false } }, "config": { diff --git a/config/auth0.php b/config/auth0.php index 84c9a959..e49d238a 100644 --- a/config/auth0.php +++ b/config/auth0.php @@ -7,8 +7,9 @@ * https://github.com/auth0/auth0-PHP#configuration-options */ return [ - // Should be assigned either 'api', 'management', or 'webapp' to indicate your application's use case for the SDK. Determines what configuration options will be required at initialization. - 'strategy' => env('AUTH0_STRATEGY', 'api'), + // Should be assigned either 'api', 'management', or 'webapp' to indicate your application's use case for the SDK. + // Determines what configuration options will be required. + 'strategy' => env('AUTH0_STRATEGY', 'webapp'), // Auth0 domain for your tenant, found in your Auth0 Application settings. 'domain' => env('AUTH0_DOMAIN'), @@ -26,13 +27,13 @@ 'clientSecret' => env('AUTH0_CLIENT_SECRET'), // One or more API identifiers, found in your Auth0 API settings. The SDK uses the first value for building links. If provided, at least one of these values must match the 'aud' claim to validate an ID Token successfully. - 'audience' => env('AUTH0_AUDIENCE', []), + 'audience' => \Auth0\Laravel\Configuration::stringToArrayOrNull(env('AUTH0_AUDIENCE')), // One or more scopes to request for Tokens. See https://auth0.com/docs/scopes - 'scope' => explode(' ', env('AUTH0_SCOPE', 'openid profile email')), + 'scope' => \Auth0\Laravel\Configuration::stringToArrayOrNull(env('AUTH0_SCOPE')), // One or more Organization IDs, found in your Auth0 Organization settings. The SDK uses the first value for building links. If provided, at least one of these values must match the 'org_id' claim to validate an ID Token successfully. - 'organization' => env('AUTH0_ORGANIZATION', []), + 'organization' => \Auth0\Laravel\Configuration::stringToArrayOrNull(env('AUTH0_ORGANIZATION')), // The secret used to derive an encryption key for the user identity in a session cookie and to sign the transient cookies used by the login callback. 'cookieSecret' => env('AUTH0_COOKIE_SECRET', env('APP_KEY')), @@ -40,8 +41,19 @@ // How long, in seconds, before cookies expire. If set to 0 the cookie will expire at the end of the session (when the browser closes). 'cookieExpires' => env('COOKIE_EXPIRES', 0), - // Named routes the SDK may call during stateful requests for redirections. - 'routeLogin' => 'login', - 'routeLogout' => 'logout', - 'routeCallback' => 'callback', + // Cookie domain, for example 'www.example.com', for use with PHP sessions and SDK cookies. Defaults to value of HTTP_HOST server environment information. + // Note: To make cookies visible on all subdomains then the domain must be prefixed with a dot like '.example.com'. + 'cookieDomain' => env('AUTH0_COOKIE_DOMAIN'), + + // Specifies path on the domain where the cookies will work. Defaults to '/'. Use a single slash ('/') for all paths on the domain. + 'cookiePath' => env('AUTH0_COOKIE_PATH'), + + // Defaults to false. Specifies whether cookies should ONLY be sent over secure connections. + 'cookieSecure' => \Auth0\Laravel\Configuration::stringToBoolOrNull(env('AUTH0_COOKIE_SECURE'), false), + + // Named routes within your Laravel application that the SDK may call during stateful requests for redirections. + 'routes' => [ + 'home' => env('AUTH0_ROUTE_HOME', '/'), + 'login' => env('AUTH0_ROUTE_LOGIN', 'login') + ] ]; diff --git a/src/Configuration.php b/src/Configuration.php new file mode 100644 index 00000000..06561b5b --- /dev/null +++ b/src/Configuration.php @@ -0,0 +1,46 @@ += 1 && strlen($delimiter) >= 1) { + $response = explode($delimiter, $config); + + // @phpstan-ignore-next-line + if (is_array($response) === true && count($response) >= 1 && strlen(trim($response[0])) !== '') { + return $response; + } + } + + return null; + } + + /** + * @inheritdoc + */ + public static function stringToBoolOrNull( + ?string $config, + ?bool $default = null + ): ?bool { + if (is_string($config) === true && strlen($config) >= 1) { + $config = strtolower(trim($config)); + + return $config === 'true'; + } + + return $default; + } +} diff --git a/src/Contract/Configuration.php b/src/Contract/Configuration.php new file mode 100644 index 00000000..908c4c66 --- /dev/null +++ b/src/Contract/Configuration.php @@ -0,0 +1,30 @@ +guard('auth0')->check()) { // They do; redirect to homepage. - return redirect()->intended('/'); + return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); } try { @@ -70,6 +70,6 @@ public function __invoke( auth()->guard('auth0')->setUser($event->getUser()); } - return redirect()->intended('/'); + return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); } } diff --git a/src/Http/Controller/Stateful/Login.php b/src/Http/Controller/Stateful/Login.php index 6e59452a..583ff76c 100644 --- a/src/Http/Controller/Stateful/Login.php +++ b/src/Http/Controller/Stateful/Login.php @@ -15,7 +15,7 @@ public function __invoke( \Illuminate\Http\Request $request ): \Illuminate\Http\RedirectResponse { if (auth()->guard('auth0')->check()) { - return redirect()->intended('/'); + return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); } return redirect()->away(app('auth0')->getSdk()->login()); diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index e180335f..eb7c1a88 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -21,6 +21,6 @@ public function __invoke( return redirect()->away(app('auth0')->getSdk()->authentication()->getLogoutLink()); } - return redirect()->intended('/'); + return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); } } diff --git a/src/Http/Middleware/Stateful/Authenticate.php b/src/Http/Middleware/Stateful/Authenticate.php index 1313b7de..a8c59243 100644 --- a/src/Http/Middleware/Stateful/Authenticate.php +++ b/src/Http/Middleware/Stateful/Authenticate.php @@ -27,6 +27,6 @@ public function handle( return $next($request); } - return redirect('login'); + return redirect(app()->make('config')->get('auth0.routes.login', 'login')); } } From cbcd7954a3a22c09368746b7f104201340fe81fb Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 7 Feb 2022 14:43:10 -0500 Subject: [PATCH 068/525] v7 Beta Documentation: Update README.md / add UPGRADE.md (#254) --- LICENSE.txt | 10 +- README.md | 328 +++++++++++++++++++++++++++++++++------------------- UPGRADE.md | 94 +++++++++++++++ 3 files changed, 307 insertions(+), 125 deletions(-) create mode 100644 UPGRADE.md diff --git a/LICENSE.txt b/LICENSE.txt index 564bf37b..a77a3309 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,17 +1,17 @@ The MIT License (MIT) - -Copyright (c) 2013 Auth0, Inc. (http://auth0.com) - + +Copyright (c) 2022 Auth0, Inc. (http://auth0.com) + 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 diff --git a/README.md b/README.md index 86b1c52b..e4db08e2 100644 --- a/README.md +++ b/README.md @@ -1,176 +1,259 @@ -# Laravel Auth0 Plugin +# Auth0 Laravel SDK -[![CircleCI](https://img.shields.io/circleci/project/github/auth0/laravel-auth0/main.svg)](https://circleci.com/gh/auth0/laravel-auth0) -[![Latest Stable Version](https://poser.pugx.org/auth0/login/v/stable)](https://packagist.org/packages/auth0/login) -[![License](https://poser.pugx.org/auth0/login/license)](https://packagist.org/packages/auth0/login) -[![Total Downloads](https://poser.pugx.org/auth0/login/downloads)](https://packagist.org/packages/auth0/login) -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0?ref=badge_shield) +[![Build Status](https://img.shields.io/circleci/project/github/auth0/laravel-auth0/main.svg)](https://circleci.com/gh/auth0/laravel-auth0) +[![Latest Stable Version](https://img.shields.io/packagist/v/auth0/login?label=stable)](https://packagist.org/packages/auth0/laravel-auth0) +[![Supported PHP Versions](https://img.shields.io/packagist/php-v/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) +[![License](https://img.shields.io/packagist/l/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0.svg?type=shield)](https://app.fossa.com/reports/4ef17265-c913-439b-8573-70bfc40d974d) -This plugin helps you integrate your [Laravel](https://laravel.com/) WebApp with [Auth0](https://auth0.com/) to achieve Single Sign On with a few simple steps. +> ***⚠️ β Beta Note — Please note this README includes documentation for the 7.x BETA release of the Auth0 Laravel SDK. As with all beta software, this should not considered stable or suitable for production use, but your experimentation with and feedback around it is greatly appreciated. Documentation for the stable release of this SDK, v6, [is available here.](https://github.com/auth0/laravel-auth0/tree/6.x)*** -## Supported Framework Versions +This SDK helps you integrate your [Laravel](https://laravel.com/) application with [Auth0](https://auth0.com/) to achieve single sign-on with a few simple steps. The SDK also provides an easy method of integration all the functionality of the underlying [Auth0-PHP](https://github.com/auth0/auth-PHP) inside your Laravel application, including all types of authentication, authorization of API endpoints, and issuing Management API calls. -This library follows the [Laravel support](https://laravel.com/docs/releases#support-policy) and [PHP release support](https://www.php.net/supported-versions.php) schedules. We do not support Laravel or PHP releases after they reach end-of-life. At the time of writing this includes [Laravel 6](https://laravel.com/docs/6.x/) and [Laravel 8](https://laravel.com/docs/8.x) on PHP 7.3 or newer. +- [Requirements](#requirements) +- [Usage](#usage) + - [Getting Started](#getting-started) + - [Installation](#installation) + - [Configuration the SDK](#configuration-the-sdk) + - [Regular Web Applications](#regular-web-applications) + - [Backend API Applications](#backend-api-applications) + - [Additional Options](#additional-options) + - [Configure your Application](#configure-your-application) + - [Authentication Routes](#authentication-routes) + - [Protecting Routes with Middleware](#protecting-routes-with-middleware) + - [Regular Web Applications](#regular-web-applications-1) + - [Backend API Applications](#backend-api-applications-1) +- [Documentation](#documentation) +- [Contributing](#contributing) +- [Support + Feedback](#support--feedback) +- [Vulnerability Reporting](#vulnerability-reporting) +- [What is Auth0?](#what-is-auth0) +- [License](#license) -As Composer handles these deprecations safely, this is not considered a breaking change and we may drop version support with minor library releases. Please ensure you are always running the latest PHP version to keep your application up to date with PHP's security fixes, and continue to receive our latest library updates. +## Requirements -Past releases of our plugin may potentially run on earlier, now unsupported versions of the Laravel framework, but these releases are not maintained. +| Laravel Version | PHP Version¹ | SDK Version | [Laravel Version Support Ends²](https://laravel.com/docs/master/releases#support-policy) | +| --------------- | ------------ | ----------- | ---------------------------------------------------------------------------------------- | +| 9.0 (LTS) | ≥ 8.0 | ≥ 7.0 | February 2025 | +| 8.0 | 7.4³, ≥ 8.0 | ≥ 6.0 | January 2023 | +| 6.0 (LTS) | 7.4³, ≥ 8.0 | 6.0 | September 2022 | -## Documentation +¹ This library follows the [PHP release support schedule](https://www.php.net/supported-versions.php). We do not support PHP versions after they [reach end of life](https://www.php.net/supported-versions.php). -Please see the [Laravel webapp quickstart](https://auth0.com/docs/quickstart/webapp/laravel) for a complete guide on how to install this in an existing project or to download a pre-configured sample project. Additional documentation on specific scenarios is below. +² This library follows the [Laravel release support schedule](https://laravel.com/docs/releases#support-policy). We do not support Laravel framework versions after they [reach end of life](https://laravel.com/docs/master/releases#support-policy). -### Setting up a JWKs cache +³ [PHP 7 will reach its end of life in November 2022.](https://www.php.net/supported-versions.php) Please upgrade to PHP 8. -In the `register` method of your `AppServiceProvider` add: +## Usage -```php -// app/Providers/AppServiceProvider.php -use Illuminate\Support\Facades\Cache; -// ... - public function register() - { - // ... - $this->app->bind( - '\Auth0\SDK\Helpers\Cache\CacheHandler', - function() { - static $cacheWrapper = null; - if ($cacheWrapper === null) { - $cache = Cache::store(); - $cacheWrapper = new LaravelCacheWrapper($cache); - } - return $cacheWrapper; - }); - } +### Getting Started + +- Create a [free Auth0 account](https://auth0.com/signup) and register an [Application](https://auth0.com/docs/applications). +- If you do not already have one, [prepare a Laravel project](https://laravel.com/docs/master/installation). + +### Installation + +The supported method of SDK installation is through [Composer](https://getcomposer.org/). From your terminal shell, `cd` into your project directory and issue the following command: + +```bash +composer require auth0/login:dev-main +``` + +***⚠️ β Beta Note*** — Due to the pre-production nature of the current release, you may need to update your `composer.json` file to allow Composer to install unstable code. This can be achieved by adding the following items to that file: + +```json +"minimum-stability": "dev", +"prefer-stable": true, +``` + +### Configuration the SDK + +Use the Laravel `vendor:publish` command to import the configuration file into your application: + +```sh +php artisan vendor:publish --tag=auth0-config ``` -You can implement your own cache strategy by creating a new class that implements the `Auth0\SDK\Helpers\Cache\CacheHandler` contract, or just use the cache strategy you want by picking that store with `Cache::store('your_store_name')`; +Now edit your `.env` file and add Auth0 tenants details for your project, depending on the type of application you're building: -### Storing users in your database +#### Regular Web Applications -You can customize the way you handle the users in your application by creating your own `UserRepository`. This class should implement the `Auth0\Login\Contract\Auth0UserRepository` contract. Please see the [Custom User Handling section of the Laravel Quickstart](https://auth0.com/docs/quickstart/webapp/laravel#optional-custom-user-handling) for the latest example. +```sh +# The URL of your Auth0 tenant domain +# You'll find this in your Auth0 Application's settings page. +AUTH0_DOMAIN=... -### Using auth guard +# Your Auth0 application's Client ID +# You'll find this in your Auth0 Application's settings page. +AUTH0_CLIENT_ID=... -To protect APIs using an access token generated by Auth0, there is an `auth0` API guard provided ([Laravel documentation on guards](https://laravel.com/docs/7.x/authentication#adding-custom-guards)). To use this guard, add it to `config/auth.php` with the driver `auth0`: +# Your Auth0 application's Client ID +# You'll find this in your Auth0 Application's settings page. +AUTH0_CLIENT_SECRET=... +# Your Auth0 Custom API identifier/audience. +# You'll find this in your Custom API's settings page. +AUTH0_AUDIENCE=... + +# Authentication callback URI, as defined in your Auth0 Application settings. +# (Update this as appropriate for your application's location.) +# (You must configure this in your Auth0 Application's settings page as well!) +AUTH0_REDIRECT_URI=http://localhost:3000/auth0/callback +``` + +#### Backend API Applications + +These are applications that accept an Access Token through the 'Authorization' header of a request. + +```sh +# This tells the Auth0 Laravel SDK about your use case to customize its behavior. +# The 'api' strategy is used for backend API applications like we're building here. +# See: https://github.com/auth0/auth0-PHP/blob/main/README.md#configuration-strategies +AUTH0_STRATEGY=api + +# The URL of your Auth0 tenant domain +# You'll find this in your Auth0 Application's settings page. +AUTH0_DOMAIN=... + +# Your Auth0 application's Client ID +# You'll find this in your Auth0 Application's settings page. +AUTH0_CLIENT_ID=... + +# Your Auth0 Custom API identifier/audience. +# You'll find this in your Custom API's settings page. +AUTH0_AUDIENCE=... ``` + +#### Additional Options + +The default configuration provided by the Auth0 Laravel SDK is intentionally limited and designed to support only the most common types of applications. More complex applications may require more robust configuration customizations available in the underlying Auth0-PHP SDK. You can add support for more configuration options by modifying your `config/auth0.php` and `.env` files. A complete list of configuration options are available [from the Auth0-PHP SDK README](https://github.com/auth0/auth0-PHP/blob/main/README.md#configuration-options). + +### Configure your Application + +Integrating the SDK's Guard requires some small changes to your `config\auth.php` file. + +To begin, find the `defaults` section. Set the default `guard` to `auth0`, like this: + +```php +// 📂 config/auth.php +'defaults' => [ + 'guard' => 'auth0', + // 📝 Leave any other settings in this section alone. +], +``` + +Next, find the `guards` section, and add `auth0` there: +```php +// 👆 Continued from above, in config/auth.php 'guards' => [ - ... + // 📝 Any additional guards you use should stay here, too. 'auth0' => [ 'driver' => 'auth0', 'provider' => 'auth0', ], ], +``` +Finally, find the `providers` section, and add `auth0` there as well: +```php +// 👆 Continued from above, in config/auth.php 'providers' => [ - ... + // 📝 Any additional providers you use should stay here, too. 'auth0' => [ 'driver' => 'auth0', + 'repository' => \Auth0\Laravel\Auth\User\Repository::class ], ], ``` -Once that has been added, add the guard to the middleware of any API route and check authentication during the request: +### Authentication Routes -``` -// get user -auth('auth0')->user(); -// check if logged in -auth('auth0')->check(); -// protect routes via middleware use -Route::group(['middleware' => 'auth:auth0'], function () {}); -``` +The SDK offers a number of convenience route controllers to ease supporting authentication in regular web application (that is, an application that handles end users logging in and out). -## Examples - -### Organizations +```php +Route::get('/login', \Auth0\Laravel\Http\Controller\Stateful\Login::class)->name('login'); +Route::get('/logout', \Auth0\Laravel\Http\Controller\Stateful\Logout::class)->name('logout'); +Route::get('/auth0/callback', \Auth0\Laravel\Http\Controller\Stateful\Callback::class)->name('auth0.callback'); +``` -[Organizations](https://auth0.com/docs/organizations) is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications. +These routes will automatically handle your regular web application's authentication flow for you. -Using Organizations, you can: +### Protecting Routes with Middleware -- Represent teams, business customers, partner companies, or any logical grouping of users that should have different ways of accessing your applications, as organizations. -- Manage their membership in a variety of ways, including user invitation. -- Configure branded, federated login flows for each organization. -- Implement role-based access control, such that users can have different roles when authenticating in the context of different organizations. -- Build administration capabilities into your products, using Organizations APIs, so that those businesses can manage their own organizations. +The Auth0 Laravel SDK includes a number of middleware that simplify either authenticating (regular web applications) or authorizing (backend api applications) your Laravel routes, depending on the type of application you're building. -Note that Organizations is currently only available to customers on our Enterprise and Startup subscription plans. +#### Regular Web Applications -#### Logging in with an Organization +These are for traditional applications that handle logging in and out. -Open your Auth0 Laravel plugin configuration file (usually `config/laravel-auth0.php`) uncomment the `organization` option and specify the Id for your Organization (found in your Organization settings on the Auth0 Dashboard.) +The `auth0.authenticate` middleware will check for an available user session and redirect any requests without one to the login route: ```php -// config/laravel-auth0.php -// ... - -/* -|-------------------------------------------------------------------------- -| Auth0 Organizations -|-------------------------------------------------------------------------- -| organization (string) Optional. Id of an Organization, if being used. Used when generating log in urls and validating token claims. -*/ - -'organization' => 'org_E6WbrPMQU2UJn6Rz', +Route::get('/required', function () { + return view('example.user.template'); +})->middleware(['auth0.authenticate']); ``` -From there, the Organization will automatically be used throughout your Laravel application's authentication login, including redirecting to the Universal Login page. +The `auth0.authenticate.optional` middleware will check for an available user session, but won't reject or redirect requests without one, allowing you to treat such requests as "guest" requests: ```php -// Expects the Laravel plugin to be configured first, as demonstrated above. +Route::get('/', function () { + if (Auth::check()) { + return view('example.user.template'); + } -App::make('auth0')->login(); + return view('example.guest.template'); +})->middleware(['auth0.authenticate.optional']); ``` -#### Accepting user invitations +Note that the `example.user.template` and `example.guest.templates` views are just examples and are not part of the SDK; replace these as appropriate for your app. -Auth0 Organizations allow users to be invited using emailed links, which will direct a user back to your application. The URL the user will arrive at is based on your configured `Application Login URI`, which you can change from your Application's settings inside the Auth0 dashboard. +#### Backend API Applications -When the user arrives at your application using an invite link, you can expect three query parameters to be provided: `invitation`, `organization`, and `organization_name`. These will always be delivered using a GET request. +These are applications that accept an Access Token through the 'Authorization' header of a request. -A helper function is provided to handle extracting these query parameters and automatically redirecting to the Universal Login page. Invoke this from your application's logic, such as a controller for an authentication route, to handle this process automatically. +The `auth0.authorize` middleware will resolve a Access Token and reject any request with an invalid token. ```php -// routes/example.php - -Route::get('/invite', [ExampleIndexController::class, 'invite'])->name('invite'); +Route::get('/api/private', function () { + return response()->json([ + 'message' => 'Hello from a private endpoint! You need to be authenticated to see this.', + 'authorized' => Auth::check(), + 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, + ], 200, [], JSON_PRETTY_PRINT); +})->middleware(['auth0.authorize']); ``` -```php -// Http/Controllers/Example/ExampleIndexController.php - -json([ + 'message' => 'Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.', + 'authorized' => Auth::check(), + 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, + ], 200, [], JSON_PRETTY_PRINT); +})->middleware(['auth0.authorize:read:messages']); +``` -class ExampleIndexController extends Controller -{ - /** - * Redirect to Auth0 Universal Login using the invitation code - * - * @return void - */ - public function invite() - { - App::make('auth0')->handleInvitation(); - } +The `auth0.authorize.optional` middleware will resolve an available Access Token, but won't block requests without one. This is useful when you want to treat tokenless requests as "guests": +```php +Route::get('/api/public', function () { + return response()->json([ + 'message' => 'Hello from a public endpoint! You don\'t need to be authenticated to see this.', + 'authorized' => Auth::check(), + 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, + ], 200, [], JSON_PRETTY_PRINT); +})->middleware(['auth0.authorize.optional']); ``` -## Installation +## Documentation -Install this plugin into a new or existing project using [Composer](https://getcomposer.org/doc/00-intro.md): +We provide a number of sample apps that demonstrate common use cases, to help you get started using this SDK: -```bash -$ composer require auth0/login:"~6.0" -``` - -Additional steps to install can be found in the [quickstart](https://auth0.com/docs/quickstart/webapp/laravel#integrate-auth0-in-your-application). +- [Web Application Authentication](https://auth0.com/docs/quickstart/webapp/laravel-beta/) ([GitHub repo](https://github.com/auth0-samples/auth0-laravel-php-web-app/tree/beta)) +- [Backend API Authorization](https://auth0.com/docs/quickstart/backend/laravel-beta/) ([GitHub repo](https://github.com/auth0-samples/auth0-laravel-api-samples/tree/beta)) ## Contributing @@ -181,26 +264,31 @@ We appreciate feedback and contribution to this repo! Before you get started, pl ## Support + Feedback -Include information on how to get support. Consider adding: +- The [Auth0 Community](https://community.auth0.com/) is a valuable resource for asking questions and finding answers, staffed by the Auth0 team and a community of enthusiastic developers +- For code-level support (such as feature requests and bug reports), we encourage you to [open issues](https://github.com/auth0/laravel-auth0/issues) here on our repo +- For customers on [paid plans](https://auth0.com/pricing/), our [support center](https://support.auth0.com/) is available for opening tickets with our knowledgeable support specialists + +Further details about our support solutions are [available on our website.](https://auth0.com/docs/support) + +## Vulnerability Reporting -- Use [Community](https://community.auth0.com/tags/laravel) for usage, questions, specific cases -- Use [Issues](https://github.com/auth0/laravel-auth0/issues) for code-level support +Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. ## What is Auth0? -Auth0 helps you to easily: +Auth0 helps you to: -- implement authentication with multiple identity providers, including social (e.g., Google, Facebook, Microsoft, LinkedIn, GitHub, Twitter, etc), or enterprise (e.g., Windows Azure AD, Google Apps, Active Directory, ADFS, SAML, etc.) -- log in users with username/password databases, passwordless, or multi-factor authentication -- link multiple user accounts together -- generate signed JSON Web Tokens to authorize your API calls and flow the user identity securely -- access demographics and analytics detailing how, when, and where users are logging in -- enrich user profiles from other data sources using customizable JavaScript rules +- Add authentication with [multiple authentication sources](https://docs.auth0.com/identityproviders), either social like Google, Facebook, Microsoft, LinkedIn, GitHub, Twitter, Box, Salesforce (amongst others), or enterprise identity systems like Windows Azure AD, Google Apps, Active Directory, ADFS or any SAML Identity Provider. +- Add authentication through more traditional **[username/password databases](https://docs.auth0.com/mysql-connection-tutorial)**. +- Add support for [passwordless](https://auth0.com/passwordless) and [multi-factor authentication](https://auth0.com/docs/mfa). +- Add support for [linking different user accounts](https://docs.auth0.com/link-accounts) with the same user. +- Analytics of how, when, and where users are logging in. +- Pull data from other sources and add it to the user profile through [JavaScript rules](https://docs.auth0.com/rules). [Why Auth0?](https://auth0.com/why-auth0) ## License -The Auth0 Laravel Login plugin is licensed under MIT - [LICENSE](LICENSE.txt) +The Auth0 Laravel SDK is open source software licensed under [the MIT license](https://opensource.org/licenses/MIT). See the [LICENSE](LICENSE.txt) file for more info. [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0?ref=badge_large) diff --git a/UPGRADE.md b/UPGRADE.md new file mode 100644 index 00000000..975df30d --- /dev/null +++ b/UPGRADE.md @@ -0,0 +1,94 @@ +# Upgrade Guide + +## v7 Migration Guide + +Auth0 Laravel SDK v7 includes many significant changes over previous versions: + +- Support for Laravel 9. +- Support for Auth0-PHP SDK 8. +- New authentication route controllers for plug-and-play login support. +- Improved authentication middleware for regular web applications. +- New authorization middleware for token-based backend API applications. + +As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes. Please review this guide thoroughly to undrstand the changes required to migrate your application to v7. + +--- + +### Before you begin: Updated Requirements + +- Laravel 8 and Laravel 9 are supported by the Auth0 Laravel SDK v7 release. +- PHP ≥7.4 is supported by the SDK when paired with Laravel 8. +- PHP ≥8.0 is supported by the SDK when paired with Laravel 9.¹ + +¹ This is a requirement of Laravel itself; only PHP 8+ will be supported going forward. + +--- + +### Breaking Changes Summary + +- Namespace has been updated from `Auth0\Login` to `Auth0\Laravel`. +- The Auth0-PHP SDK dependency has been updated from V7 to V8, which [may introduce breaking API changes](https://github.com/auth0/auth0-PHP/blob/main/UPGRADE.md) that will require further changes in your app outside the scope of this Laravel SDK. +- A simplified configuration file format is present. You will need to regenerate your config file. (Instructions below.) +- Changes to application files are no longer necessary, as the SDK registers services and middleware itself. You should remove any `config/app.php` or `app/HttpKernel.php` customizations made to avoid conflicts. (Instructions below.) + +--- + +### Migration Guidance + +#### Update Configuration Scheme + +- Configuration filename is now `config/auth0.php`. +- Configuration format has been updated to support Auth0-PHP SDK 8. + +1. Delete any previous laravel-auth0 configuration files present in your application. +2. Use `php artisan vendor:publish --tag=auth0-config` to generate an updated config file. +3. Review new configuration instructions in the [README](README.md#configuration-the-sdk). + +#### Remove `config\app.php` modifications + +- Previously, the SDK required you to add service provider classes to the `providers` array in this file. +- This is no longer necessary, as the SDK now registers services itself. + +1. Remove any references to the SDK in your `providers` array. + +#### Remove `app\Http\Kernel.php` modifications + +- Previously, the SDK required you to add middleware classes to the middleware arrays in this file. +- This is no longer necessary, as the SDK now registers these itself. + +1. Remove any references to the SDK in your `middleware` arrays. +2. Update any router middleware references in your app to the types instructed in the [README](README.md#protecting-routes-with-middleware). + +#### Update to new authentication routes, as appropriate +Note: This only applies to regular web application types. + +- Previously, the SDK required you to write boilerplate around login, logout and callback routes. +- The SDK now provides plug-and-play middleware that handles authentication flows, appropriate for most application needs. + +1. Remove any route logic around login, logout or callback routes. +2. Implement the new authentication utility routes as instructed in the [README](README.md#authentication-routes). + +#### Update to new `auth0.authenticate` middleware, as appropriate +Note: This only applies to regular web application types. + +- Previously, the SDK advised you to register the Auth0 authentication middleware yourself in the `app\Http\Kernel.php`, which invited you to specify custom naming schemes for these middlewares. +- The SDK now provides plug-and-play middleware with specific naming schemes. + +1. Update middleware references from previous custom registrations to the new scheme, as instructed in the [README](README.md#regular-web-applications-1). + + +#### Update to new `auth0.authorize` middleware, as appropriate +Note: This only applies to backend api application types. + +- Previously, the SDK advised you to write your own Access Token handling middleware using the `decodeJWT()` method from the Auth0 PHP SDK. +- The SDK now provides plug-and-play middleware that handles common endpoint authorization, appropriate for most application needs. + +1. Remove custom JWT processing or boilerplate code, particularly those referencing `decodeJWT()` from the old Auth0 PHP SDK releases. +2. Add new `middleware()` calls to your routes that reference the new SDK authorization middleware, as instructed in the [README](README.md#backend-api-applications-1). + +#### Upgrade Auth0-PHP dependency from 7 to 8, as appropriate + +- Previous versions of the SDK implemented v7 of the Auth0-PHP SDK dependency. +- The SDK now uses Auth0-PHP SDK v8. + +If you wrote custom code around the underlying Auth0-PHP, or otherwise made internal calls to the underlying SDK through the Laravel SDK, your application will require further upgrade steps. [Please review the upgrade guide for that SDK here.](https://github.com/auth0/auth0-PHP/blob/main/UPGRADE.md) From bc95423e9fd6a7213453a892d3ad1967b96b34ce Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 8 Feb 2022 16:20:05 -0500 Subject: [PATCH 069/525] Release 7.0.0-BETA1 (#255) --- CHANGELOG.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95b68395..1039d4b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Change Log +## [7.0.0-BETA1](https://github.com/auth0/laravel-auth0/tree/7.0.0-BETA1) (2022-02-08) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.5.0...7.0.0-BETA1) + +Auth0 Laravel SDK v7 includes many significant changes over previous versions: + +- Support for Laravel 9. +- Support for Auth0-PHP SDK 8. +- New authentication route controllers for plug-and-play login support. +- Improved authentication middleware for regular web applications. +- New authorization middleware for token-based backend API applications. + +As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes. Please review the [upgrade guide](UPGRADE.md) thoroughly to understand the changes required to migrate your application to v7. + +**Breaking Changes Summary** + +- Namespace has been updated from `Auth0\Login` to `Auth0\Laravel` +- Auth0-PHP SDK dependency updated to V8 +- New configuration format +- SDK now self-registers it's services and middleware + ## [6.5.0](https://github.com/auth0/laravel-auth0/tree/6.5.0) (2021-10-15) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.4.1...6.5.0) From 1a0eb63402df3b3f5c36cb0c248e6db20ce7dd35 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 9 Feb 2022 15:25:22 -0500 Subject: [PATCH 070/525] Update Bug Report.yml --- .github/ISSUE_TEMPLATE/Bug Report.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index 3ec46e90..159eb25b 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -11,6 +11,7 @@ body: label: SDK Version description: What version of our Laravel plugin are you running? (`composer show | grep auth0/login`) options: + - 7.0 - 6.5 - 6.4 - Other (specify in 'additional context') @@ -22,9 +23,9 @@ body: label: PHP Version description: What version of PHP are you running? (`php -v`) options: + - PHP 8.1 - PHP 8.0 - PHP 7.4 - - PHP 7.3 - Other (specify in 'additional context') validations: required: true From 547073e7e96bb3c7e0702021d8523306b6cda22c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 10 Feb 2022 11:25:24 -0500 Subject: [PATCH 071/525] Update `Auth\User\Provider::__construct()` to accept a Repository Interface, rather than Class (#257) --- src/Auth/User/Provider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php index 34ec5a2b..a6f259ec 100644 --- a/src/Auth/User/Provider.php +++ b/src/Auth/User/Provider.php @@ -9,13 +9,13 @@ final class Provider implements \Illuminate\Contracts\Auth\UserProvider, \Auth0\ /** * A repository instance. */ - private Repository $repository; + private \Auth0\Laravel\Contract\Auth\User\Repository $repository; /** * @inheritdoc */ public function __construct( - \Auth0\Laravel\Auth\User\Repository $repository + \Auth0\Laravel\Contract\Auth\User\Repository $repository ) { $this->repository = $repository; } From b8b4dffd949b493644a817913b448661491e9193 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 10 Feb 2022 18:57:27 -0500 Subject: [PATCH 072/525] Update Requirements in README for Laravel 9 (#258) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e4db08e2..7cf4cd6e 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ This SDK helps you integrate your [Laravel](https://laravel.com/) application wi | Laravel Version | PHP Version¹ | SDK Version | [Laravel Version Support Ends²](https://laravel.com/docs/master/releases#support-policy) | | --------------- | ------------ | ----------- | ---------------------------------------------------------------------------------------- | -| 9.0 (LTS) | ≥ 8.0 | ≥ 7.0 | February 2025 | +| 9.0 | ≥ 8.0 | ≥ 7.0 | February 2024 | | 8.0 | 7.4³, ≥ 8.0 | ≥ 6.0 | January 2023 | | 6.0 (LTS) | 7.4³, ≥ 8.0 | 6.0 | September 2022 | From 8b6ffb1ac36abb5c2a4474e393a3f52913856e03 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 17 Feb 2022 12:42:28 -0600 Subject: [PATCH 073/525] Allow post-logout return url to be configurable (#261) --- src/Http/Controller/Stateful/Logout.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index eb7c1a88..56d6e82d 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -18,7 +18,7 @@ public function __invoke( $request->session()->invalidate(); $request->session()->regenerateToken(); - return redirect()->away(app('auth0')->getSdk()->authentication()->getLogoutLink()); + return redirect()->away(app('auth0')->getSdk()->authentication()->getLogoutLink(url(http://github.com/app()->make('config')->get('auth0.routes.home', '/')))); } return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); From 4883b4907e35c9dd6ea3a2b2524a84838fc96d4a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 20 Feb 2022 14:39:00 -0600 Subject: [PATCH 074/525] Delete Auth0.php --- src/facade/Auth0.php | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 src/facade/Auth0.php diff --git a/src/facade/Auth0.php b/src/facade/Auth0.php deleted file mode 100644 index 16b8fbb6..00000000 --- a/src/facade/Auth0.php +++ /dev/null @@ -1,21 +0,0 @@ - Date: Sun, 20 Feb 2022 14:39:25 -0600 Subject: [PATCH 075/525] Fix folder name case --- src/Facade/Auth0.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/Facade/Auth0.php diff --git a/src/Facade/Auth0.php b/src/Facade/Auth0.php new file mode 100644 index 00000000..16b8fbb6 --- /dev/null +++ b/src/Facade/Auth0.php @@ -0,0 +1,21 @@ + Date: Tue, 1 Mar 2022 01:15:10 +0100 Subject: [PATCH 076/525] decouple user models with interface (#263) --- src/Http/Middleware/Stateful/Authenticate.php | 2 +- src/Http/Middleware/Stateful/AuthenticateOptional.php | 2 +- src/Http/Middleware/Stateless/Authorize.php | 2 +- src/Http/Middleware/Stateless/AuthorizeOptional.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Http/Middleware/Stateful/Authenticate.php b/src/Http/Middleware/Stateful/Authenticate.php index a8c59243..00a4e932 100644 --- a/src/Http/Middleware/Stateful/Authenticate.php +++ b/src/Http/Middleware/Stateful/Authenticate.php @@ -22,7 +22,7 @@ public function handle( ) { $user = auth()->guard('auth0')->user(); - if ($user !== null && $user instanceof \Auth0\Laravel\Model\Stateful\User) { + if ($user !== null && $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { auth()->guard('auth0')->login($user); return $next($request); } diff --git a/src/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Http/Middleware/Stateful/AuthenticateOptional.php index de4daaa9..d7e93ae0 100644 --- a/src/Http/Middleware/Stateful/AuthenticateOptional.php +++ b/src/Http/Middleware/Stateful/AuthenticateOptional.php @@ -22,7 +22,7 @@ public function handle( ) { $user = auth()->guard('auth0')->user(); - if ($user !== null && $user instanceof \Auth0\Laravel\Model\Stateful\User) { + if ($user !== null && $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { auth()->guard('auth0')->login($user); } diff --git a/src/Http/Middleware/Stateless/Authorize.php b/src/Http/Middleware/Stateless/Authorize.php index c16354c7..eca524d9 100644 --- a/src/Http/Middleware/Stateless/Authorize.php +++ b/src/Http/Middleware/Stateless/Authorize.php @@ -22,7 +22,7 @@ public function handle( ) { $user = auth()->guard('auth0')->user(); - if ($user !== null && $user instanceof \Auth0\Laravel\Model\Stateless\User) { + if ($user !== null && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { if (strlen($scope) >= 1 && auth()->guard('auth0')->hasScope($scope) === false) { return abort(403, 'Unauthorized'); } diff --git a/src/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Http/Middleware/Stateless/AuthorizeOptional.php index 24336569..1ae72a50 100644 --- a/src/Http/Middleware/Stateless/AuthorizeOptional.php +++ b/src/Http/Middleware/Stateless/AuthorizeOptional.php @@ -20,7 +20,7 @@ public function handle( ) { $user = auth()->guard('auth0')->user(); - if ($user !== null && $user instanceof \Auth0\Laravel\Model\Stateless\User) { + if ($user !== null && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { auth()->guard('auth0')->login($user); } From 58ce97fc0f9d72d5d1789b2a484bf1eb227665f2 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 9 Mar 2022 11:19:41 -0500 Subject: [PATCH 077/525] Update UserProvider API (#264) --- src/Auth/Guard.php | 252 +++++++++--------- src/Auth/User/Provider.php | 73 +---- src/Auth/User/Repository.php | 59 +--- src/Contract/Auth/Guard.php | 61 +---- src/Contract/Auth/User/Provider.php | 47 +--- src/Contract/Auth/User/Repository.php | 57 +--- src/Contract/Event/Stateful/TokenExpired.php | 29 -- .../Event/Stateful/TokenRefreshSucceeded.php | 22 -- src/Contract/Model/User.php | 110 +++----- src/Contract/StateInstance.php | 88 +++++- src/Event/Stateful/TokenExpired.php | 46 ---- src/Event/Stateful/TokenRefreshSucceeded.php | 32 --- src/Model/Stateless/User.php | 2 +- src/Model/User.php | 150 +++-------- src/StateInstance.php | 173 +++++++++++- 15 files changed, 487 insertions(+), 714 deletions(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index f09681da..5553a468 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -4,7 +4,7 @@ namespace Auth0\Laravel\Auth; -final class Guard implements \Illuminate\Contracts\Auth\Guard, \Auth0\Laravel\Contract\Auth\Guard +final class Guard implements \Auth0\Laravel\Contract\Auth\Guard, \Illuminate\Contracts\Auth\Guard { /** * The user provider implementation. @@ -16,36 +16,15 @@ final class Guard implements \Illuminate\Contracts\Auth\Guard, \Auth0\Laravel\Co */ private \Illuminate\Http\Request $request; - /** - * The name of the query string item from the request containing the API token. - */ - private string $inputKey; - - /** - * The name of the token "column" in persistent storage. - */ - private string $storageKey; - - /** - * Indicates if the API token is hashed in storage. - */ - private bool $hash = false; - /** * @inheritdoc */ public function __construct( \Illuminate\Contracts\Auth\UserProvider $provider, - \Illuminate\Http\Request $request, - $inputKey = 'api_token', - $storageKey = 'api_token', - $hash = false + \Illuminate\Http\Request $request ) { $this->provider = $provider; $this->request = $request; - $this->inputKey = $inputKey; - $this->storageKey = $storageKey; - $this->hash = $hash; } /** @@ -54,7 +33,7 @@ public function __construct( public function login( \Illuminate\Contracts\Auth\Authenticatable $user ): self { - $this->getInstance()->setUser($user); + $this->getState()->setUser($user); return $this; } @@ -63,7 +42,7 @@ public function login( */ public function logout(): self { - $this->getInstance()->setUser(null); + $this->getState()->setUser(null); app('auth0')->getSdk()->clear(); return $this; } @@ -84,6 +63,14 @@ public function guest(): bool return ! $this->check(); } + /** + * @inheritdoc + */ + public function user(): ?\Illuminate\Contracts\Auth\Authenticatable + { + return $this->getState()->getUser() ?? $this->getUserFromToken() ?? $this->getUserFromSession() ?? null; + } + /** * @inheritdoc */ @@ -104,17 +91,23 @@ public function id() /** * @inheritdoc + * + * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ public function validate( array $credentials = [] ): bool { - if (! isset($credentials[$this->inputKey])) { - return false; - } - - $credentials = [$this->storageKey => $credentials[$this->inputKey]]; + return false; + } - return $this->provider->retrieveByCredentials($credentials) !== null; + /** + * @inheritdoc + */ + public function setUser( + \Illuminate\Contracts\Auth\Authenticatable $user + ): self { + $user = $this->getState()->setUser($user); + return $this; } /** @@ -122,7 +115,7 @@ public function validate( */ public function hasUser(): bool { - return ! is_null($this->getInstance()->getUser()); + return ! is_null($this->getState()->getUser()); } /** @@ -131,9 +124,9 @@ public function hasUser(): bool public function hasScope( string $scope ): bool { - $user = $this->getInstance()->getUser(); + $state = $this->getState(); - if ($user !== null && in_array($scope, $user->getAccessTokenScope(), true)) { + if (in_array($scope, $state->getAccessTokenScope() ?? [], true)) { return true; } @@ -141,150 +134,147 @@ public function hasScope( } /** - * @inheritdoc - */ - public function setUser( - \Illuminate\Contracts\Auth\Authenticatable $user - ): self { - $user = $this->getInstance()->setUser($user); - return $this; - } - - /** - * @inheritdoc - */ - public function setRequest( - \Illuminate\Http\Request $request - ): self { - $this->request = $request; - return $this; - } - - /** - * @inheritdoc + * Get the user context from a provided access token. */ - public function user(): ?\Illuminate\Contracts\Auth\Authenticatable + private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable { - $instance = $this->getInstance(); - $user = null; - $token = $this->getTokenForRequest(); + // Retrieve an available bearer token from the request. + $token = $this->request->bearerToken(); - if ($token !== null) { - $user = $this->provider->retrieveByToken([], $token); + // If a session is not available, return null. + if ($token === null) { + return null; } - if ($user === null && $token === null) { - $user = $this->getUserFromSession(); - $user = $this->handleTokenExpiration($user); + try { + // Attempt to decode the bearer token. + $decoded = app('auth0')->getSdk()->decode($token, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_TOKEN)->toArray(); + } catch (\Auth0\SDK\Exception\InvalidTokenException $invalidToken) { + // Invalid bearer token. + return null; } + // Query the UserProvider to retrieve tue user for the token. + $user = $this->getProvider()->getRepository()->fromAccessToken($decoded); + + // Was a user retrieved successfully? if ($user !== null) { - $instance->setUser($user); + if (! $user instanceof \Illuminate\Contracts\Auth\Authenticatable) { + die('User model returned fromAccessToken must implement \Illuminate\Contracts\Auth\Authenticatable.'); + } + + if (! $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { + die('User model returned fromAccessToken must implement \Auth0\Laravel\Contract\Model\Stateless\User.'); + } + + $this->getState() + ->clear() + ->setDecoded($decoded) + ->setAccessToken($token) + ->setAccessTokenScope(explode(' ', $decoded['scope'] ?? '')) + ->setAccessTokenExpiration($decoded['exp'] ?? null); } return $user; } /** - * @inheritdoc + * Get the user context from an Auth0-PHP SDK session.. */ - public function getTokenForRequest(): ?string + private function getUserFromSession(): ?\Illuminate\Contracts\Auth\Authenticatable { - $token = $this->request->query($this->inputKey); - - if ($token === null) { - $token = $this->request->input($this->inputKey); - } + // Retrieve an available session from the Auth0-PHP SDK. + $session = app('auth0')->getSdk()->getCredentials(); - if ($token === null) { - $token = $this->request->bearerToken(); + // If a session is not available, return null. + if ($session === null) { + return null; } - if ($token === null) { - $token = $this->request->getPassword(); - } + // Query the UserProvider to retrieve tue user for the session. + $user = $this->getProvider()->getRepository()->fromSession($session->user); - if ($token !== null && is_string($token)) { - return $token; - } + // Was a user retrieved successfully? + if ($user !== null) { + if (! $user instanceof \Illuminate\Contracts\Auth\Authenticatable) { + die('User model returned fromSession must implement \Illuminate\Contracts\Auth\Authenticatable.'); + } - return null; - } + if (! $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { + die('User model returned fromSession must implement \Auth0\Laravel\Contract\Model\Stateful\User.'); + } - /** - * Return the current request's StateInstance singleton. - */ - private function getInstance(): \Auth0\Laravel\StateInstance - { - return app()->make(\Auth0\Laravel\StateInstance::class); - } + $this->getState() + ->clear() + ->setDecoded($session->user) + ->setIdToken($session->idToken) + ->setAccessToken($session->accessToken) + ->setAccessTokenScope($session->accessTokenScope) + ->setAccessTokenExpiration($session->accessTokenExpiration) + ->setRefreshToken($session->refreshToken); - /** - * Get the local user session. - */ - private function getUserFromSession(): ?\Illuminate\Contracts\Auth\Authenticatable - { - $session = app('auth0')->getSdk()->getCredentials(); - - if ($session !== null) { - return $this->provider->retrieveByCredentials((array) $session); + $user = $this->handleSessionExpiration($user); } - return null; + return $user; } /** - * Handle instances of access token expiration. + * Handle instances of session token expiration. */ - private function handleTokenExpiration( + private function handleSessionExpiration( ?\Illuminate\Contracts\Auth\Authenticatable $user ): ?\Illuminate\Contracts\Auth\Authenticatable { - if ($user === null) { - return null; - } + $state = $this->getState(); - if ($user->getAccessTokenExpired() === false) { + // Unless our token expired, we have nothing to do here. + if ($state->getAccessTokenExpired() !== true) { return $user; } - // Did we scope with 'offline_access' (and does the API allow) for a refresh token? - if ($user->getRefreshToken() !== null) { + // Do we have a refresh token? + if ($state->getRefreshToken() !== null) { try { + // Try to renew our token. app('auth0')->getSdk()->renew(); } catch (\Auth0\SDK\Exception\StateException $tokenRefreshFailed) { - // Inform the host application token refresh failed, to enable custom handling behavior + // Renew failed. Inform application. event(new \Auth0\Laravel\Event\Stateful\TokenRefreshFailed()); } - // Retrieve any potentially updated state data - $refreshed = $this->getUserFromSession(); - - // Was refreshed successfully? - if ($refreshed !== null && $refreshed->getAccessTokenExpired() === false) { - // Inform the host application to enable custom handling behavior - $event = new \Auth0\Laravel\Event\Stateful\TokenRefreshSucceeded($refreshed); - event($event); + // Retrieve updated state data + $refreshed = app('auth0')->getSdk()->getCredentials(); - return $event->getUser(); + if ($refreshed !== null && $refreshed->accessTokenExpired === false) { + event(new \Auth0\Laravel\Event\Stateful\TokenRefreshSucceeded()); + return $user; } } - // We didn't have a refresh token, or the refresh failed. Inform host application. - $event = new \Auth0\Laravel\Event\Stateful\TokenExpired($user); - event($event); - - // Did the host application override default expiration handling? - if ($event->getUser()->getAccessTokenExpired() === false) { - // Unless the host application expressly opted into not clearing the local user session, do so: - return $event->getUser(); - } + // We didn't have a refresh token, or the refresh failed. + // Clear session. + $state->clear(); + app('auth0')->getSdk()->clear(); - if ($event->getClearSession() === true) { - // Clear the local user session: - $this->getInstance()->setUser(null); - app('auth0')->getSdk()->clear(); - } + // Inform host application. + event(new \Auth0\Laravel\Event\Stateful\TokenExpired()); return null; } + + /** + * Return the current request's StateInstance singleton. + */ + private function getState(): \Auth0\Laravel\StateInstance + { + return app()->make(\Auth0\Laravel\StateInstance::class); + } + + /** + * Return the current request's StateInstance singleton. + */ + private function getProvider(): \Illuminate\Contracts\Auth\UserProvider + { + return $this->provider; + } } diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php index a6f259ec..3bb74a20 100644 --- a/src/Auth/User/Provider.php +++ b/src/Auth/User/Provider.php @@ -4,7 +4,7 @@ namespace Auth0\Laravel\Auth\User; -final class Provider implements \Illuminate\Contracts\Auth\UserProvider, \Auth0\Laravel\Contract\Auth\User\Provider +final class Provider implements \Auth0\Laravel\Contract\Auth\User\Provider, \Illuminate\Contracts\Auth\UserProvider { /** * A repository instance. @@ -22,37 +22,12 @@ public function __construct( /** * @inheritdoc + * + * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ public function retrieveById( $identifier ): ?\Illuminate\Contracts\Auth\Authenticatable { - if (! is_string($identifier)) { - return null; - } - - try { - $decoded = app('auth0')->getSdk()->decode($identifier, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_ID_TOKEN)->toArray(); - } catch (\Auth0\SDK\Exception\InvalidTokenException $invalidToken) { - $decoded = null; - } - - if ($decoded !== null) { - $scope = $decoded['scope'] ?? ''; - $exp = $decoded['exp'] ?? null; - $expired = time() > $exp; - - // Process $identifier here ... - return $this->repository->fromAccessToken( - $decoded, - null, - $identifier, - explode(' ', $scope), - $exp, - $expired, - null, - ); - } - return null; } @@ -65,46 +40,18 @@ public function retrieveByToken( $identifier, $token ): ?\Illuminate\Contracts\Auth\Authenticatable { - try { - $decoded = app('auth0')->getSdk()->decode($token, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_TOKEN)->toArray(); - } catch (\Auth0\SDK\Exception\InvalidTokenException $invalidToken) { - $decoded = null; - } - - if ($decoded !== null) { - $scope = $decoded['scope'] ?? ''; - $exp = $decoded['exp'] ?? null; - $expired = time() > $exp; - - return $this->repository->fromAccessToken( - $decoded, - null, - $token, - explode(' ', $scope), - $exp, - $expired, - null, - ); - } - return null; } /** * @inheritdoc + * + * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ public function retrieveByCredentials( array $credentials ): ?\Illuminate\Contracts\Auth\Authenticatable { - return $this->repository->fromSession( - $credentials['user'] ?? null, - $credentials['idToken'] ?? null, - $credentials['accessToken'] ?? null, - $credentials['accessTokenScope'] ?? null, - $credentials['accessTokenExpiration'] ?? null, - $credentials['accessTokenExpired'] ?? null, - $credentials['refreshToken'] ?? null, - ); + return null; } /** @@ -129,4 +76,12 @@ public function updateRememberToken( $token ): void { } + + /** + * @inheritdoc + */ + public function getRepository(): \Auth0\Laravel\Contract\Auth\User\Repository + { + return $this->repository; + } } diff --git a/src/Auth/User/Repository.php b/src/Auth/User/Repository.php index 9245c84c..7e7295a4 100644 --- a/src/Auth/User/Repository.php +++ b/src/Auth/User/Repository.php @@ -10,22 +10,10 @@ final class Repository implements \Auth0\Laravel\Contract\Auth\User\Repository * @inheritdoc */ public function fromSession( - array $profile, - ?string $idToken, - ?string $accessToken, - ?array $accessTokenScope, - ?int $accessTokenExpiration, - ?bool $accessTokenExpired, - ?string $refreshToken - ): \Illuminate\Contracts\Auth\Authenticatable { + array $user + ): ?\Illuminate\Contracts\Auth\Authenticatable { return new \Auth0\Laravel\Model\Stateful\User( - $profile, - $idToken, - $accessToken, - $accessTokenScope, - $accessTokenExpiration, - $accessTokenExpired, - $refreshToken + $user ); } @@ -33,45 +21,10 @@ public function fromSession( * @inheritdoc */ public function fromAccessToken( - array $profile, - ?string $idToken, - ?string $accessToken, - ?array $accessTokenScope, - ?int $accessTokenExpiration, - ?bool $accessTokenExpired, - ?string $refreshToken - ): \Illuminate\Contracts\Auth\Authenticatable { + array $user + ): ?\Illuminate\Contracts\Auth\Authenticatable { return new \Auth0\Laravel\Model\Stateless\User( - $profile, - $idToken, - $accessToken, - $accessTokenScope, - $accessTokenExpiration, - $accessTokenExpired, - $refreshToken - ); - } - - /** - * @inheritdoc - */ - public function fromIdToken( - array $profile, - ?string $idToken, - ?string $accessToken, - ?array $accessTokenScope, - ?int $accessTokenExpiration, - ?bool $accessTokenExpired, - ?string $refreshToken - ): \Illuminate\Contracts\Auth\Authenticatable { - return new \Auth0\Laravel\Model\Stateless\User( - $profile, - $idToken, - $accessToken, - $accessTokenScope, - $accessTokenExpiration, - $accessTokenExpired, - $refreshToken + $user ); } } diff --git a/src/Contract/Auth/Guard.php b/src/Contract/Auth/Guard.php index 43175680..55e688fb 100644 --- a/src/Contract/Auth/Guard.php +++ b/src/Contract/Auth/Guard.php @@ -11,16 +11,10 @@ interface Guard * * @param \Illuminate\Contracts\Auth\UserProvider $provider * @param \Illuminate\Http\Request $request - * @param string $inputKey - * @param string $storageKey - * @param bool $hash */ public function __construct( \Illuminate\Contracts\Auth\UserProvider $provider, - \Illuminate\Http\Request $request, - $inputKey = 'api_token', - $storageKey = 'api_token', - $hash = false + \Illuminate\Http\Request $request ); /** @@ -37,66 +31,13 @@ public function login( */ public function logout(): self; - /** - * Determine if the current user is authenticated. - * - * @return bool - */ - public function check(): bool; - - /** - * Determine if the current user is a guest. - * - * @return bool - */ - public function guest(): bool; - - /** - * Get the ID for the currently authenticated user. - * - * @return int|string|null - */ - public function id(); - - /** - * Validate a user's credentials. - * - * @param array $credentials - */ - public function validate( - array $credentials = [] - ): bool; - /** * Determine if the guard has a user instance. */ public function hasUser(): bool; - /** - * Set the current user. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - */ - public function setUser( - \Illuminate\Contracts\Auth\Authenticatable $user - ): self; - - /** - * Set the current request instance. - * - * @param \Illuminate\Http\Request $request - */ - public function setRequest( - \Illuminate\Http\Request $request - ): self; - /** * Get the currently authenticated user. */ public function user(): ?\Illuminate\Contracts\Auth\Authenticatable; - - /** - * Get the token for the current request. - */ - public function getTokenForRequest(): ?string; } diff --git a/src/Contract/Auth/User/Provider.php b/src/Contract/Auth/User/Provider.php index df5aa760..0fc8a772 100644 --- a/src/Contract/Auth/User/Provider.php +++ b/src/Contract/Auth/User/Provider.php @@ -7,7 +7,7 @@ interface Provider { /** - * Auth0UserProvider constructor. + * \Auth0\Laravel\Contract\Auth\User\Provider constructor. * * @param \Auth0\Laravel\Auth\User\Repository $repository A repository instance. */ @@ -16,48 +16,7 @@ public function __construct( ); /** - * Returns a \Auth0\Laravel\Model\Stateless\User instance from an Id Token. - * - * @param string $identifier A string representing the encoded Id Token. - */ - public function retrieveById( - $identifier - ): ?\Illuminate\Contracts\Auth\Authenticatable; - - /** - * Returns a \Auth0\Laravel\Model\Stateless\User instance from an Access Token. - * - * @param mixed $identifier Unused in this provider. - * @param string $token A string representing the encoded Access Token. - */ - public function retrieveByToken( - $identifier, - $token - ): ?\Illuminate\Contracts\Auth\Authenticatable; - - /** - * Returns a \Auth0\Laravel\Model\Stateless\User instance translated from an Auth0-PHP SDK session. - */ - public function retrieveByCredentials( - array $credentials - ): ?\Illuminate\Contracts\Auth\Authenticatable; - - /** - * Returns true if the provided $user's unique identifier matches the credentials payload. - */ - public function validateCredentials( - \Illuminate\Contracts\Auth\Authenticatable $user, - array $credentials - ): bool; - - /** - * Method required by interface. Not supported. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user User context. - * @param string $token A string representing the remember token. + * Returns the assigned user provider. */ - public function updateRememberToken( - \Illuminate\Contracts\Auth\Authenticatable $user, - $token - ): void; + public function getRepository(): \Auth0\Laravel\Contract\Auth\User\Repository; } diff --git a/src/Contract/Auth/User/Repository.php b/src/Contract/Auth/User/Repository.php index 649c7218..9997375e 100644 --- a/src/Contract/Auth/User/Repository.php +++ b/src/Contract/Auth/User/Repository.php @@ -9,63 +9,18 @@ interface Repository /** * Generate a \Auth0\Laravel\Model\Stateful\User instance from an available Auth0-PHP user session. * - * @param array $profile An array containing the raw Auth0 user data. - * @param string|null $idToken An ID Token used by the user context. Null when unavailable. - * @param string|null $accessToken An Access Token used by the user context. Null when unavailable. - * @param array|null $accessTokenScope An array of scopes requested/returned during authentication for the user context. Null when unavailable. - * @param int|null $accessTokenExpiration A unix timestamp representing when an access token expires, if available. - * @param bool|null $accessTokenExpired Returns true if the access token has expired, if an expiration timestamp was available. - * @param string|null $refreshToken A Refresh Token used by the user context. Null when unavailable. + * @param array $user An array containing the raw Auth0 user data. */ public function fromSession( - array $profile, - ?string $idToken, - ?string $accessToken, - ?array $accessTokenScope, - ?int $accessTokenExpiration, - ?bool $accessTokenExpired, - ?string $refreshToken - ): \Illuminate\Contracts\Auth\Authenticatable; + array $user + ): ?\Illuminate\Contracts\Auth\Authenticatable; /** * Generate a \Auth0\Laravel\Model\Stateful\User instance from a parsed Access Token. * - * @param array $profile An array containing the raw Auth0 user data. - * @param string|null $idToken An ID Token used by the user context. Null when unavailable. - * @param string|null $accessToken An Access Token used by the user context. Null when unavailable. - * @param array|null $accessTokenScope An array of scopes requested/returned during authentication for the user context. Null when unavailable. - * @param int|null $accessTokenExpiration A unix timestamp representing when an access token expires, if available. - * @param bool|null $accessTokenExpired Returns true if the access token has expired, if an expiration timestamp was available. - * @param string|null $refreshToken A Refresh Token used by the user context. Null when unavailable. + * @param array $user An array containing the raw Auth0 user data. */ public function fromAccessToken( - array $profile, - ?string $idToken, - ?string $accessToken, - ?array $accessTokenScope, - ?int $accessTokenExpiration, - ?bool $accessTokenExpired, - ?string $refreshToken - ): \Illuminate\Contracts\Auth\Authenticatable; - - /** - * Generate a \Auth0\Laravel\Model\Stateful\User instance from a parsed ID Token. - * - * @param array $profile An array containing the raw Auth0 user data. - * @param string|null $idToken An ID Token used by the user context. Null when unavailable. - * @param string|null $accessToken An Access Token used by the user context. Null when unavailable. - * @param array|null $accessTokenScope An array of scopes requested/returned during authentication for the user context. Null when unavailable. - * @param int|null $accessTokenExpiration A unix timestamp representing when an access token expires, if available. - * @param bool|null $accessTokenExpired Returns true if the access token has expired, if an expiration timestamp was available. - * @param string|null $refreshToken A Refresh Token used by the user context. Null when unavailable. - */ - public function fromIdToken( - array $profile, - ?string $idToken, - ?string $accessToken, - ?array $accessTokenScope, - ?int $accessTokenExpiration, - ?bool $accessTokenExpired, - ?string $refreshToken - ): \Illuminate\Contracts\Auth\Authenticatable; + array $user + ): ?\Illuminate\Contracts\Auth\Authenticatable; } diff --git a/src/Contract/Event/Stateful/TokenExpired.php b/src/Contract/Event/Stateful/TokenExpired.php index fde2efe1..501cad8c 100644 --- a/src/Contract/Event/Stateful/TokenExpired.php +++ b/src/Contract/Event/Stateful/TokenExpired.php @@ -6,33 +6,4 @@ interface TokenExpired { - /** - * AuthenticationFailed constructor. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user An instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user. - * @param bool $clearSession Whether or not the local user session will be cleared after the event resolves. - */ - public function __construct( - \Illuminate\Contracts\Auth\Authenticatable $user, - bool $clearSession = true - ); - - /** - * Return the object representing the user session that has expired. - */ - public function getUser(): \Illuminate\Contracts\Auth\Authenticatable; - - /** - * Determine whether the provided exception will be thrown by the SDK. - * - * @param bool $clearException Whether or not the local user session will be cleared after the event resolves. - */ - public function setClearSession( - bool $clearException - ): self; - - /** - * Returns whether the SDK should clear the local user session after the event resolves. - */ - public function getClearSession(): bool; } diff --git a/src/Contract/Event/Stateful/TokenRefreshSucceeded.php b/src/Contract/Event/Stateful/TokenRefreshSucceeded.php index af313f23..42bec9da 100644 --- a/src/Contract/Event/Stateful/TokenRefreshSucceeded.php +++ b/src/Contract/Event/Stateful/TokenRefreshSucceeded.php @@ -6,26 +6,4 @@ interface TokenRefreshSucceeded { - /** - * TokenRefreshSucceeded constructor. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user An instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user. - */ - public function __construct( - \Illuminate\Contracts\Auth\Authenticatable $user - ); - - /** - * Overwrite the authenticated user. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user An instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user. - */ - public function setUser( - \Illuminate\Contracts\Auth\Authenticatable $user - ): self; - - /** - * Return the authenticated user. - */ - public function getUser(): \Illuminate\Contracts\Auth\Authenticatable; } diff --git a/src/Contract/Model/User.php b/src/Contract/Model/User.php index 1115e63e..fecdea70 100644 --- a/src/Contract/Model/User.php +++ b/src/Contract/Model/User.php @@ -8,103 +8,65 @@ interface User { /** * \Auth0\Laravel\Model\User constructor. + * + * @param array $attributes Attributes representing the user data. */ public function __construct( - array $profile, - ?string $idToken, - ?string $accessToken, - ?array $accessTokenScope, - ?int $accessTokenExpiration, - ?bool $accessTokenExpired, - ?string $refreshToken + array $attributes = [] ); /** - * Add a generic getter to get all the properties of the user. + * Dynamically retrieve attributes on the model. * - * @return mixed|null Returns the related value, or null if not set. - */ - public function __get( - string $name - ); - - /** - * Return a JSON-encoded representation of the user. - */ - public function __toString(): string; - - /** - * Get the unique identifier for the user. + * @param string $key * * @return mixed */ - public function getAuthIdentifier(); + public function __get( + string $key + ); /** - * Get the name of the unique identifier for the user. + * Dynamically set attributes on the model. * - * @return string + * @param string $key + * @param mixed $value */ - public function getAuthIdentifierName(); + public function __set( + string $key, + $value + ): void; /** - * Get the password for the user. + * Fill the model with an array of attributes. * - * @return string - */ - public function getAuthPassword(): string; - - /** - * Get the token value for the "remember me" session. + * @param array $attributes */ - public function getRememberToken(): string; + public function fill( + array $attributes + ): self; /** - * Set the token value for the "remember me" session. + * Set a given attribute on the model. * - * @param string $value + * @param string $key + * @param mixed $value */ - public function setRememberToken( + public function setAttribute( + string $key, $value - ): void; - - /** - * Get the column name for the "remember me" token. - */ - public function getRememberTokenName(): string; - - /** - * Return the profile data for the user context. Null when unavailable. - */ - public function getProfile(): ?array; - - /** - * Return the ID Token for the user context. Null when unavailable. - */ - public function getIdToken(): ?string; - - /** - * Return the Access Token for the user context. Null when unavailable. - */ - public function getAccessToken(): ?string; - - /** - * Return the Access Token's scope for the user context. Null when unavailable. - */ - public function getAccessTokenScope(): ?array; + ): self; /** - * Return the Access Token's expiration (represented as a unix timestamp) for the user context. Null when unavailable. - */ - public function getAccessTokenExpiration(): ?int; - - /** - * Return true if the Access Token has expired for the user context. Null when unavailable. - */ - public function getAccessTokenExpired(): ?bool; - - /** - * Return the Refresh Token for the user context. Null when unavailable. + * Get an attribute from the model. + * + * @param string $key + * @param mixed $default + * + * @return mixed */ - public function getRefreshToken(): ?string; + public function getAttribute( + string $key, + $default = null + ); } diff --git a/src/Contract/StateInstance.php b/src/Contract/StateInstance.php index 8190706d..5886dbfa 100644 --- a/src/Contract/StateInstance.php +++ b/src/Contract/StateInstance.php @@ -6,6 +6,16 @@ interface StateInstance { + /** + * Reset all attributes of the StateInstance to default values. + */ + public function clear(): self; + + /** + * Return the authenticated user context for the current request. + */ + public function getUser(): ?\Illuminate\Contracts\Auth\Authenticatable; + /** * Set the authenticated user context for the current request. * @@ -16,7 +26,81 @@ public function setUser( ): self; /** - * Return the authenticated user context for the current request. + * Retrieve the decoded token data for the request context, if available. */ - public function getUser(): ?\Illuminate\Contracts\Auth\Authenticatable; + public function getDecoded(): ?array; + + /** + * Set the decoded token data for the request context. + */ + public function setDecoded( + ?array $data + ): self; + + /** + * Retrieve the id token for the request context, if available. + */ + public function getIdToken(): ?string; + + /** + * Set the id token for the request context. + */ + public function setIdToken( + ?string $idToken + ): self; + + /** + * Retrieve the access token for the request context, if available. + */ + public function getAccessToken(): ?string; + + /** + * Set the access token for the request context. + */ + public function setAccessToken( + ?string $accessToken + ): self; + + /** + * Retrieve the access token scopes for the request context, if available. + */ + public function getAccessTokenScope(): ?array; + + /** + * Set the access token scopes for the request context. + */ + public function setAccessTokenScope( + ?array $accessTokenScope + ): self; + + /** + * Retrieve the access token expiration timestamp for the request context, if available. + */ + public function getAccessTokenExpiration(): ?int; + + /** + * Set the access token expiration timestamp for the request context. + */ + public function setAccessTokenExpiration( + ?int $accessTokenExpiration + ): self; + + /** + * Retrieve the access token expiration state, if available. + */ + public function getAccessTokenExpired(): ?bool; + + /** + * Retrieve the refresh token for the request context, if available. + */ + public function getRefreshToken(): ?string; + + /** + * Set the refresh token for the request context, if available. + * + * @param string $refreshToken Refresh token returned from the code exchange. + */ + public function setRefreshToken( + ?string $refreshToken + ): self; } diff --git a/src/Event/Stateful/TokenExpired.php b/src/Event/Stateful/TokenExpired.php index c0527b1d..337f4b74 100644 --- a/src/Event/Stateful/TokenExpired.php +++ b/src/Event/Stateful/TokenExpired.php @@ -6,50 +6,4 @@ final class TokenExpired extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Stateful\TokenExpired { - /** - * An instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user. - */ - private \Illuminate\Contracts\Auth\Authenticatable $user; - - /** - * Determines whether the local session will be cleared by the SDK after the event resolves. - */ - private bool $clearSession; - - /** - * @inheritdoc - */ - public function __construct( - \Illuminate\Contracts\Auth\Authenticatable $user, - bool $clearSession = true - ) { - $this->user = $user; - $this->clearSession = $clearSession; - } - - /** - * @inheritdoc - */ - public function getUser(): \Illuminate\Contracts\Auth\Authenticatable - { - return $this->user; - } - - /** - * @inheritdoc - */ - public function setClearSession( - bool $clearSession - ): self { - $this->clearSession = $clearSession; - return $this; - } - - /** - * @inheritdoc - */ - public function getClearSession(): bool - { - return $this->clearSession; - } } diff --git a/src/Event/Stateful/TokenRefreshSucceeded.php b/src/Event/Stateful/TokenRefreshSucceeded.php index 9d201282..2708c856 100644 --- a/src/Event/Stateful/TokenRefreshSucceeded.php +++ b/src/Event/Stateful/TokenRefreshSucceeded.php @@ -6,36 +6,4 @@ final class TokenRefreshSucceeded extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Stateful\TokenRefreshSucceeded { - /** - * An instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user. - */ - private \Illuminate\Contracts\Auth\Authenticatable $user; - - /** - * @inheritdoc - */ - public function __construct( - \Illuminate\Contracts\Auth\Authenticatable $user - ) { - $this->user = $user; - } - - /** - * @inheritdoc - */ - public function setUser( - \Illuminate\Contracts\Auth\Authenticatable $user - ): self { - $this->user = $user; - $this->mutated = true; - return $this; - } - - /** - * @inheritdoc - */ - public function getUser(): \Illuminate\Contracts\Auth\Authenticatable - { - return $this->user; - } } diff --git a/src/Model/Stateless/User.php b/src/Model/Stateless/User.php index 3e23e52e..368dd9ae 100644 --- a/src/Model/Stateless/User.php +++ b/src/Model/Stateless/User.php @@ -5,7 +5,7 @@ namespace Auth0\Laravel\Model\Stateless; /** - * This model class represents a user authorized by a bearer token. + * This model class represents a user authorized by an Access Token. */ final class User extends \Auth0\Laravel\Model\User implements \Auth0\Laravel\Contract\Model\Stateless\User { diff --git a/src/Model/User.php b/src/Model/User.php index 26314036..1b05039a 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -7,76 +7,72 @@ abstract class User implements \Illuminate\Contracts\Auth\Authenticatable, \Auth0\Laravel\Contract\Model\User { /** - * Profile data for the user context, when available. - */ - private array $profile; - - /** - * ID Token for the user context, when available. - */ - private ?string $idToken; - - /** - * Access Token for the user context, when available. - */ - private ?string $accessToken; - - /** - * Access Token scopes for the user context, when available. + * The model's attributes. + * + * @var array */ - private ?array $accessTokenScope; + private $attributes = []; /** - * Access Token expiration timestamp for the user context, when available. + * @inheritdoc */ - private ?int $accessTokenExpiration; + public function __construct( + array $attributes = [] + ) { + $this->fill($attributes); + } /** - * Access Token expiration indicator for the user context, when available. + * @inheritdoc */ - private ?bool $accessTokenExpired; + public function __get( + string $key + ) { + return $this->getAttribute($key); + } /** - * Refresh Token for the user context, when available. + * @inheritdoc */ - private ?string $refreshToken; + public function __set( + string $key, + $value + ): void { + $this->setAttribute($key, $value); + } /** * @inheritdoc */ - public function __construct( - array $profile, - ?string $idToken, - ?string $accessToken, - ?array $accessTokenScope, - ?int $accessTokenExpiration, - ?bool $accessTokenExpired, - ?string $refreshToken - ) { - $this->profile = $profile; - $this->idToken = $idToken; - $this->accessToken = $accessToken; - $this->accessTokenScope = $accessTokenScope; - $this->accessTokenExpiration = $accessTokenExpiration; - $this->accessTokenExpired = $accessTokenExpired; - $this->refreshToken = $refreshToken; + public function fill( + array $attributes + ): self { + foreach ($attributes as $key => $value) { + $this->setAttribute($key, $value); + } + + return $this; } /** * @inheritdoc */ - public function __get( - string $name - ) { - return array_key_exists($name, $this->profile) ? $this->profile[$name] : null; + public function setAttribute( + string $key, + $value + ): self { + $this->attributes[$key] = $value; + return $this; } /** * @inheritdoc */ - public function __toString(): string - { - return json_encode($this->profile, JSON_THROW_ON_ERROR, 512); + public function getAttribute( + string $key, + $default = null + ) { + return $this->attributes[$key] ?? $default; } /** @@ -84,11 +80,7 @@ public function __toString(): string */ public function getAuthIdentifier() { - if (isset($this->profile['sub'])) { - return $this->profile['sub']; - } - - return $this->profile['user_id']; + return $this->attributes['sub'] ?? $this->attributes['user_id'] ?? $this->attributes['email'] ?? null; } /** @@ -132,60 +124,4 @@ public function getRememberTokenName(): string { return ''; } - - /** - * @inheritdoc - */ - public function getProfile(): ?array - { - return $this->profile; - } - - /** - * @inheritdoc - */ - public function getIdToken(): ?string - { - return $this->idToken; - } - - /** - * @inheritdoc - */ - public function getAccessToken(): ?string - { - return $this->accessToken; - } - - /** - * @inheritdoc - */ - public function getAccessTokenScope(): ?array - { - return $this->accessTokenScope; - } - - /** - * @inheritdoc - */ - public function getAccessTokenExpiration(): ?int - { - return $this->accessTokenExpiration; - } - - /** - * @inheritdoc - */ - public function getAccessTokenExpired(): ?bool - { - return $this->accessTokenExpired; - } - - /** - * @inheritdoc - */ - public function getRefreshToken(): ?string - { - return $this->refreshToken; - } } diff --git a/src/StateInstance.php b/src/StateInstance.php index ba2ccd0b..76d39216 100644 --- a/src/StateInstance.php +++ b/src/StateInstance.php @@ -4,13 +4,66 @@ namespace Auth0\Laravel; -final class StateInstance +final class StateInstance implements \Auth0\Laravel\Contract\StateInstance { /** * An authenticated user context for the current request. */ private ?\Illuminate\Contracts\Auth\Authenticatable $user = null; + /** + * Decoded token data from the request context. + */ + private ?array $decoded; + + /** + * ID Token for the request context, when available. + */ + private ?string $idToken; + + /** + * Access Token for the request context, when available. + */ + private ?string $accessToken; + + /** + * Access Token scopes for the request context, when available. + */ + private ?array $accessTokenScope; + + /** + * Access Token expiration timestamp for the request context, when available. + */ + private ?int $accessTokenExpiration; + + /** + * Refresh Token for the request context, when available. + */ + private ?string $refreshToken; + + /** + * @inheritdoc + */ + public function clear(): self + { + $this->user = null; + $this->decoded = null; + $this->idToken = null; + $this->accessToken = null; + $this->accessTokenScope = null; + $this->accessTokenExpiration = null; + $this->refreshToken = null; + return $this; + } + + /** + * @inheritdoc + */ + public function getUser(): ?\Illuminate\Contracts\Auth\Authenticatable + { + return $this->user; + } + /** * @inheritdoc */ @@ -24,8 +77,122 @@ public function setUser( /** * @inheritdoc */ - public function getUser(): ?\Illuminate\Contracts\Auth\Authenticatable + public function getDecoded(): ?array { - return $this->user; + return $this->decoded; + } + + /** + * @inheritdoc + */ + public function setDecoded( + ?array $data + ): self { + $this->decoded = $data; + return $this; + } + + /** + * @inheritdoc + */ + public function getIdToken(): ?string + { + return $this->idToken; + } + + /** + * @inheritdoc + */ + public function setIdToken( + ?string $idToken + ): self { + $this->idToken = $idToken; + return $this; + } + + /** + * @inheritdoc + */ + public function getAccessToken(): ?string + { + return $this->accessToken; + } + + /** + * @inheritdoc + */ + public function setAccessToken( + ?string $accessToken + ): self { + $this->accessToken = $accessToken; + return $this; + } + + /** + * @inheritdoc + */ + public function getAccessTokenScope(): ?array + { + return $this->accessTokenScope; + } + + /** + * @inheritdoc + */ + public function setAccessTokenScope( + ?array $accessTokenScope + ): self { + $this->accessTokenScope = $accessTokenScope; + return $this; + } + + /** + * @inheritdoc + */ + public function getAccessTokenExpiration(): ?int + { + return $this->accessTokenExpiration; + } + + /** + * @inheritdoc + */ + public function setAccessTokenExpiration( + ?int $accessTokenExpiration + ): self { + $this->accessTokenExpiration = $accessTokenExpiration; + return $this; + } + + /** + * @inheritdoc + */ + public function getAccessTokenExpired(): ?bool + { + $expires = $this->getAccessTokenExpiration(); + + if ($expires === null) { + return null; + } + + return time() >= $expires; + } + + /** + * @inheritdoc + */ + public function getRefreshToken(): ?string + { + return $this->refreshToken; + } + + /** + * @inheritdoc + */ + public function setRefreshToken( + ?string $refreshToken + ): self { + $this->refreshToken = $refreshToken; + return $this; } } From 7167e408f6950d05fd342d25a73467031f3ce40f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 9 Mar 2022 13:53:09 -0500 Subject: [PATCH 078/525] Introduce Rector tests for code quality improvement suggestions (#265) --- .circleci/config.yml | 19 +++++++++++++++++++ composer.json | 6 ++++++ rector.php | 26 ++++++++++++++++++++++++++ src/Configuration.php | 2 +- src/ServiceProvider.php | 24 ++++++------------------ 5 files changed, 58 insertions(+), 19 deletions(-) create mode 100644 rector.php diff --git a/.circleci/config.yml b/.circleci/config.yml index 4ee64cde..e59029ee 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -44,6 +44,12 @@ commands: name: Run code quality analysis (PHP Insights) command: php -d memory-limit=-1 ./vendor/bin/phpinsights -v --no-interaction --min-quality=100 --min-complexity=50 --min-architecture=100 --min-style=100 + run-rector: + steps: + - run: + name: Run code quality analysis (Rector) + command: php -d memory_limit=-1 ./vendor/bin/rector process src --dry-run + run-phpstan: steps: - run: @@ -75,6 +81,15 @@ jobs: steps: - setup - run-phpinsights + rector: + parameters: + php: + type: string + docker: + - image: php:<< parameters.php >>-cli-alpine + steps: + - setup + - run-rector phpstan: parameters: php: @@ -120,6 +135,10 @@ workflows: matrix: parameters: php: ["7.4", "8.0", "8.1"] + - rector: + matrix: + parameters: + php: ["7.4", "8.0", "8.1"] - phpstan: matrix: parameters: diff --git a/composer.json b/composer.json index d7adfda6..3da10cd8 100644 --- a/composer.json +++ b/composer.json @@ -51,6 +51,7 @@ "pestphp/pest-plugin-laravel": "^1.2", "phpstan/phpstan-strict-rules": "^1.1", "phpunit/phpunit": "^9.5", + "rector/rector": "^0.12.16", "thecodingmachine/phpstan-strict-rules": "^1.0", "wikimedia/composer-merge-plugin": "^2.0" }, @@ -93,6 +94,7 @@ "scripts": { "tests": [ "@tests:phpinsights", + "@tests:rector", "@tests:phpstan", "@tests:pest" ], @@ -100,6 +102,10 @@ "Composer\\Config::disableProcessTimeout", "@php ./vendor/bin/phpinsights -v --no-interaction" ], + "tests:rector": [ + "Composer\\Config::disableProcessTimeout", + "@php ./vendor/bin/rector process src --dry-run" + ], "tests:phpstan": [ "Composer\\Config::disableProcessTimeout", "@php ./vendor/bin/phpstan analyse --ansi --memory-limit 512M" diff --git a/rector.php b/rector.php new file mode 100644 index 00000000..05a45e1b --- /dev/null +++ b/rector.php @@ -0,0 +1,26 @@ +parameters(); + $parameters->set(Option::PATHS, [ + __DIR__ . '/src', + ]); + + // Define what rule sets will be applied + $containerConfigurator->import(LevelSetList::UP_TO_PHP_74); + + // get services (needed for register a single rule) + // $services = $containerConfigurator->services(); + + // register a single rule + // $services->set(TypedPropertyRector::class); + + $parameters->set(Option::PHPSTAN_FOR_RECTOR_PATH, getcwd() . '/phpstan.neon.dist'); +}; diff --git a/src/Configuration.php b/src/Configuration.php index 06561b5b..88cf75a7 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -20,7 +20,7 @@ public static function stringToArrayOrNull( $response = explode($delimiter, $config); // @phpstan-ignore-next-line - if (is_array($response) === true && count($response) >= 1 && strlen(trim($response[0])) !== '') { + if (is_array($response) === true && count($response) >= 1 && strlen(trim($response[0])) !== 0) { return $response; } } diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 55a6df0a..80759109 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -22,21 +22,13 @@ public function configurePackage( */ public function registeringPackage(): void { - app()->singleton(Auth0::class, static function (): \Auth0\Laravel\Auth0 { - return new Auth0(); - }); + app()->singleton(Auth0::class, static fn (): \Auth0\Laravel\Auth0 => new Auth0()); - app()->singleton('auth0', static function (): \Auth0\Laravel\Auth0 { - return app()->make(Auth0::class); - }); + app()->singleton('auth0', static fn (): \Auth0\Laravel\Auth0 => app()->make(Auth0::class)); - app()->singleton(StateInstance::class, static function (): \Auth0\Laravel\StateInstance { - return new StateInstance(); - }); + app()->singleton(StateInstance::class, static fn (): \Auth0\Laravel\StateInstance => new StateInstance()); - app()->singleton(\Auth0\Laravel\Auth\User\Repository::class, static function (): \Auth0\Laravel\Auth\User\Repository { - return new \Auth0\Laravel\Auth\User\Repository(); - }); + app()->singleton(\Auth0\Laravel\Auth\User\Repository::class, static fn (): \Auth0\Laravel\Auth\User\Repository => new \Auth0\Laravel\Auth\User\Repository()); } /** @@ -44,13 +36,9 @@ public function registeringPackage(): void */ public function bootingPackage(): void { - auth()->provider('auth0', static function ($app, array $config): \Auth0\Laravel\Auth\User\Provider { - return new \Auth0\Laravel\Auth\User\Provider(app()->make($config['repository'])); - }); + auth()->provider('auth0', static fn ($app, array $config): \Auth0\Laravel\Auth\User\Provider => new \Auth0\Laravel\Auth\User\Provider(app()->make($config['repository']))); - auth()->extend('auth0', static function ($app, $name, array $config): \Auth0\Laravel\Auth\Guard { - return new \Auth0\Laravel\Auth\Guard(auth()->createUserProvider($config['provider']), $app->make('request')); - }); + auth()->extend('auth0', static fn ($app, $name, array $config): \Auth0\Laravel\Auth\Guard => new \Auth0\Laravel\Auth\Guard(auth()->createUserProvider($config['provider']), $app->make('request'))); $router = app()->make(\Illuminate\Routing\Router::class); $router->aliasMiddleware('auth0.authenticate', \Auth0\Laravel\Http\Middleware\Stateful\Authenticate::class); From d9eb2ecf220e513b3d8d4703c3bea68ecd8482da Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 9 Mar 2022 14:26:02 -0500 Subject: [PATCH 079/525] Apply Rector improvements (#267) --- src/Model/User.php | 4 +--- src/StateInstance.php | 12 ++++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Model/User.php b/src/Model/User.php index 1b05039a..7e186a3e 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -8,10 +8,8 @@ abstract class User implements \Illuminate\Contracts\Auth\Authenticatable, \Auth { /** * The model's attributes. - * - * @var array */ - private $attributes = []; + private array $attributes = []; /** * @inheritdoc diff --git a/src/StateInstance.php b/src/StateInstance.php index 76d39216..3adfab89 100644 --- a/src/StateInstance.php +++ b/src/StateInstance.php @@ -14,32 +14,32 @@ final class StateInstance implements \Auth0\Laravel\Contract\StateInstance /** * Decoded token data from the request context. */ - private ?array $decoded; + private ?array $decoded = null; /** * ID Token for the request context, when available. */ - private ?string $idToken; + private ?string $idToken = null; /** * Access Token for the request context, when available. */ - private ?string $accessToken; + private ?string $accessToken = null; /** * Access Token scopes for the request context, when available. */ - private ?array $accessTokenScope; + private ?array $accessTokenScope = null; /** * Access Token expiration timestamp for the request context, when available. */ - private ?int $accessTokenExpiration; + private ?int $accessTokenExpiration = null; /** * Refresh Token for the request context, when available. */ - private ?string $refreshToken; + private ?string $refreshToken = null; /** * @inheritdoc From bbe14968f21c50717b30f11db957e1e8f7578c9c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 9 Mar 2022 15:30:03 -0500 Subject: [PATCH 080/525] Release 7.0.0-BETA2 (#266) --- CHANGELOG.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1039d4b0..14c34fde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Change Log +## [7.0.0-BETA2](https://github.com/auth0/laravel-auth0/tree/7.0.0-BETA2) (2022-03-09) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.5.0...7.0.0-BETA2) + +Please review the [BETA1 changelog notes below](#700-beta1-2022-02-08) before upgrading your application from 6.x, as 7.0 is a new major containing breaking changes. As with all beta releases, this should not be considered stable or suitable for production use, but your experimentation with and feedback around it is greatly appreciated. + +**Changes** +- Update Middleware interface checks for custom user model types [\#263](https://github.com/auth0/laravel-auth0/pull/263) ([sheggi](https://github.com/sheggi)) +- Updated UserProvider API [\#264](https://github.com/auth0/laravel-auth0/pull/264) ([evansims](https://github.com/evansims)) +- Add Rector to test suite [\#265](https://github.com/auth0/laravel-auth0/pull/265) ([evansims](https://github.com/evansims)) + ## [7.0.0-BETA1](https://github.com/auth0/laravel-auth0/tree/7.0.0-BETA1) (2022-02-08) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.5.0...7.0.0-BETA1) @@ -19,7 +30,7 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes - Namespace has been updated from `Auth0\Login` to `Auth0\Laravel` - Auth0-PHP SDK dependency updated to V8 - New configuration format -- SDK now self-registers it's services and middleware +- SDK now self-registers its services and middleware ## [6.5.0](https://github.com/auth0/laravel-auth0/tree/6.5.0) (2021-10-15) From 6edd8c67eb9275df975102b13b954f403db09d46 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 9 Mar 2022 18:27:12 -0500 Subject: [PATCH 081/525] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7cf4cd6e..267b289f 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Build Status](https://img.shields.io/circleci/project/github/auth0/laravel-auth0/main.svg)](https://circleci.com/gh/auth0/laravel-auth0) [![Latest Stable Version](https://img.shields.io/packagist/v/auth0/login?label=stable)](https://packagist.org/packages/auth0/laravel-auth0) +[![Latest Version](https://img.shields.io/packagist/v/auth0/login?include_prereleases&label=latest)](https://packagist.org/packages/auth0/laravel-auth0) [![Supported PHP Versions](https://img.shields.io/packagist/php-v/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) [![License](https://img.shields.io/packagist/l/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0.svg?type=shield)](https://app.fossa.com/reports/4ef17265-c913-439b-8573-70bfc40d974d) From 06238bdfa0bdf165b02cb8433a6d3c8e23cfc9ec Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 21 Mar 2022 19:00:50 -0400 Subject: [PATCH 082/525] Release 7.0.0 (#270) --- CHANGELOG.md | 22 ++++++++++++++++++++++ README.md | 13 ++----------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14c34fde..bea13ef6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Change Log +## [7.0.0](https://github.com/auth0/laravel-auth0/tree/7.0.0) (2022-03-21) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.5.0...7.0.0) + +Auth0 Laravel SDK v7 includes many significant changes over previous versions: + +- Support for Laravel 9. +- Support for Auth0-PHP SDK 8. +- New authentication route controllers for plug-and-play login support. +- Improved authentication middleware for regular web applications. +- New authorization middleware for token-based backend API applications. + +As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes. Please review the [upgrade guide](UPGRADE.md) thoroughly to understand the changes required to migrate your application to v7. + +**Breaking Changes Summary** + +- Namespace has been updated from `Auth0\Login` to `Auth0\Laravel` +- Auth0-PHP SDK dependency updated to V8 +- New configuration format +- SDK now self-registers its services and middleware +- New UserProvider API + ## [7.0.0-BETA2](https://github.com/auth0/laravel-auth0/tree/7.0.0-BETA2) (2022-03-09) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.5.0...7.0.0-BETA2) diff --git a/README.md b/README.md index 267b289f..50d6cb98 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,6 @@ [![License](https://img.shields.io/packagist/l/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0.svg?type=shield)](https://app.fossa.com/reports/4ef17265-c913-439b-8573-70bfc40d974d) -> ***⚠️ β Beta Note — Please note this README includes documentation for the 7.x BETA release of the Auth0 Laravel SDK. As with all beta software, this should not considered stable or suitable for production use, but your experimentation with and feedback around it is greatly appreciated. Documentation for the stable release of this SDK, v6, [is available here.](https://github.com/auth0/laravel-auth0/tree/6.x)*** - This SDK helps you integrate your [Laravel](https://laravel.com/) application with [Auth0](https://auth0.com/) to achieve single sign-on with a few simple steps. The SDK also provides an easy method of integration all the functionality of the underlying [Auth0-PHP](https://github.com/auth0/auth-PHP) inside your Laravel application, including all types of authentication, authorization of API endpoints, and issuing Management API calls. - [Requirements](#requirements) @@ -60,13 +58,6 @@ The supported method of SDK installation is through [Composer](https://getcompos composer require auth0/login:dev-main ``` -***⚠️ β Beta Note*** — Due to the pre-production nature of the current release, you may need to update your `composer.json` file to allow Composer to install unstable code. This can be achieved by adding the following items to that file: - -```json -"minimum-stability": "dev", -"prefer-stable": true, -``` - ### Configuration the SDK Use the Laravel `vendor:publish` command to import the configuration file into your application: @@ -253,8 +244,8 @@ Route::get('/api/public', function () { We provide a number of sample apps that demonstrate common use cases, to help you get started using this SDK: -- [Web Application Authentication](https://auth0.com/docs/quickstart/webapp/laravel-beta/) ([GitHub repo](https://github.com/auth0-samples/auth0-laravel-php-web-app/tree/beta)) -- [Backend API Authorization](https://auth0.com/docs/quickstart/backend/laravel-beta/) ([GitHub repo](https://github.com/auth0-samples/auth0-laravel-api-samples/tree/beta)) +- [Web Application Authentication](https://auth0.com/docs/quickstart/webapp/laravel/) ([GitHub repo](https://github.com/auth0-samples/auth0-laravel-php-web-app)) +- [Backend API Authorization](https://auth0.com/docs/quickstart/backend/laravel/) ([GitHub repo](https://github.com/auth0-samples/auth0-laravel-api-samples)) ## Contributing From 790f060802b5c422fe9dd3e01751798112f2d1b6 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 10 Apr 2022 20:21:52 -0500 Subject: [PATCH 083/525] Update config.yml --- .circleci/config.yml | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e59029ee..67c40ba2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -81,6 +81,7 @@ jobs: steps: - setup - run-phpinsights + rector: parameters: php: @@ -90,6 +91,7 @@ jobs: steps: - setup - run-rector + phpstan: parameters: php: @@ -99,14 +101,7 @@ jobs: steps: - setup - run-phpstan - semgrep: - docker: - - image: returntocorp/semgrep:latest - steps: - - checkout - - run: - name: Run static code analysis (Semgrep) - command: semgrep --config auto + pest: parameters: php: @@ -117,6 +112,7 @@ jobs: - setup - setup-pcov - run-pest + snyk: parameters: php: @@ -127,6 +123,19 @@ jobs: - setup - run-snyk + semgrep: + docker: + - image: returntocorp/semgrep-agent:v1 + environment: + SEMGREP_REPO_NAME: "auth0/laravel-auth0" + SEMGREP_REPO_URL: "https://github.com/auth0/laravel-auth0" + steps: + - checkout + - run: + name: Run vulnerabilities tests (Semgrep) + command: | + semgrep-agent --baseline-ref main --publish-token $SEMGREP_TOKEN + workflows: test: jobs: @@ -147,13 +156,12 @@ workflows: matrix: parameters: php: ["7.4", "8.0", "8.1"] - - hold: - type: approval + - semgrep: + context: + - semgrep-env - snyk: matrix: parameters: php: ["7.4", "8.0", "8.1"] context: - snyk-env - requires: - - hold From 099d10f407e7141bac7169f23900d9953bc5b00c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 10 Apr 2022 20:23:16 -0500 Subject: [PATCH 084/525] Update config.yml --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 67c40ba2..fea69ed5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -139,7 +139,6 @@ jobs: workflows: test: jobs: - - semgrep - phpinsights: matrix: parameters: From 95a305f1c24c6fe544913eee98af69ac55c5d48c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 1 May 2022 15:50:16 -0400 Subject: [PATCH 085/525] Update README.md --- README.md | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 50d6cb98..fc9d1cff 100644 --- a/README.md +++ b/README.md @@ -31,17 +31,26 @@ This SDK helps you integrate your [Laravel](https://laravel.com/) application wi ## Requirements -| Laravel Version | PHP Version¹ | SDK Version | [Laravel Version Support Ends²](https://laravel.com/docs/master/releases#support-policy) | -| --------------- | ------------ | ----------- | ---------------------------------------------------------------------------------------- | -| 9.0 | ≥ 8.0 | ≥ 7.0 | February 2024 | -| 8.0 | 7.4³, ≥ 8.0 | ≥ 6.0 | January 2023 | -| 6.0 (LTS) | 7.4³, ≥ 8.0 | 6.0 | September 2022 | - -¹ This library follows the [PHP release support schedule](https://www.php.net/supported-versions.php). We do not support PHP versions after they [reach end of life](https://www.php.net/supported-versions.php). - -² This library follows the [Laravel release support schedule](https://laravel.com/docs/releases#support-policy). We do not support Laravel framework versions after they [reach end of life](https://laravel.com/docs/master/releases#support-policy). - -³ [PHP 7 will reach its end of life in November 2022.](https://www.php.net/supported-versions.php) Please upgrade to PHP 8. +| SDK Version | Laravel Version¹ | PHP Version² | Support Ends³ | +|-------------|------------------|--------------|---------------| +| 7 | 9 | 8.1 | Feb 2024 | +| | | 8.0 | Nov 2023 | +| | 8 | 8.1 | Jan 2023 | +| | | 8.0 | Jan 2023 | +| | | 7.4 | Nov 2022 | +| 6⁴ | 8 | 8.1 | Jan 2023 | +| | | 8.0 | Jan 2023 | +| | | 7.4 | Nov 2022 | +| | 6 (LTS) | 8.0 | Sep 2022 | +| | | 7.4 | Sep 2022 | + +¹ This library follows the [Laravel release support schedule](https://laravel.com/docs/releases#support-policy). We do not support framework versions after they stop receiving security fixes from Laravel. + +² This library follows the [PHP release support schedule](https://www.php.net/supported-versions.php). We do not support runtime versions after they stop receiving security fixes from the PHP Group. + +³ Our support windows are determined by the Laravel and PHP Group support schedules, and support ends when either the Laravel framework or PHP runtime outlined above stop receiving security fixes, whichever comes first. + +⁴ With the release of Laravel SDK v7, v6 is now in bug-fix only mode. Please migrate to v7 to continue to receive feature enhancements. ## Usage From 0e7159845e74342d2717de839d2653800e84915e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 1 May 2022 15:51:52 -0400 Subject: [PATCH 086/525] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 67deae3a..6a279552 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -27,5 +27,4 @@ Resolves # ### Contributor Checklist - [ ] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) - - [ ] I have read the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) From 4235aa1ee8a2c6b00ca0dbf3da002dd20795296e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 1 May 2022 15:53:34 -0400 Subject: [PATCH 087/525] Create dependabot.yml --- .github/dependabot.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..dfb465a1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + - package-ecosystem: composer + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 From 081081c51cbb256d8758995f0d1f91c600712a00 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 1 May 2022 15:56:11 -0400 Subject: [PATCH 088/525] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6a279552..fc9f6f7a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,9 @@ ### Changes @@ -21,10 +24,12 @@ Resolves # ### Testing ### Contributor Checklist - [ ] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) -- [ ] I have read the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) +- [ ] I have read the [Auth0 code of conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) From f14b75c92116a933f0421708b229440cf3c69467 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 1 May 2022 15:57:23 -0400 Subject: [PATCH 089/525] Update Bug Report.yml --- .github/ISSUE_TEMPLATE/Bug Report.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index 159eb25b..932a5d61 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -23,6 +23,7 @@ body: label: PHP Version description: What version of PHP are you running? (`php -v`) options: + - PHP 8.2 - PHP 8.1 - PHP 8.0 - PHP 7.4 From 8eaf02955ea57d90614805b7ea15ba3780fbcce6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 16:03:54 -0400 Subject: [PATCH 090/525] Update orchestra/testbench requirement from 6.0 to 6.24.1 (#279) Updates the requirements on [orchestra/testbench](https://github.com/orchestral/testbench) to permit the latest version. - [Release notes](https://github.com/orchestral/testbench/releases) - [Changelog](https://github.com/orchestral/testbench/blob/7.x/CHANGELOG-6.x.md) - [Commits](https://github.com/orchestral/testbench/compare/v6.0.0...v6.24.1) --- updated-dependencies: - dependency-name: orchestra/testbench dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3da10cd8..aaad8bbc 100644 --- a/composer.json +++ b/composer.json @@ -46,7 +46,7 @@ "nunomaduro/larastan": "^1.0", "nunomaduro/phpinsights": "^2.0", "nyholm/psr7": "^1.4", - "orchestra/testbench": "6.0", + "orchestra/testbench": "6.24.1", "pestphp/pest": "^1.21", "pestphp/pest-plugin-laravel": "^1.2", "phpstan/phpstan-strict-rules": "^1.1", From 19ba72c57c7562894d1833c475e1a17531de4726 Mon Sep 17 00:00:00 2001 From: le-bru <99329443+le-bru@users.noreply.github.com> Date: Sun, 1 May 2022 22:13:31 +0200 Subject: [PATCH 091/525] added ActingAsAuth0User Trait that can be used in HTTP tests (#276) * added ActingAsAuth0User Trait that can be used in HTTP tests for authorizing requests as auth0 user with custom attributes set * fixed code styling issues * Fix linter warnings on code style Co-authored-by: Leonhard Brunner Co-authored-by: Evan Sims --- README.md | 32 +++++++++++++++++++++++ src/Traits/ActingAsAuth0User.php | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 src/Traits/ActingAsAuth0User.php diff --git a/README.md b/README.md index fc9d1cff..287ca689 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ This SDK helps you integrate your [Laravel](https://laravel.com/) application wi - [Protecting Routes with Middleware](#protecting-routes-with-middleware) - [Regular Web Applications](#regular-web-applications-1) - [Backend API Applications](#backend-api-applications-1) + - [Authorizing HTTP Tests](#authorizing-http-tests) - [Documentation](#documentation) - [Contributing](#contributing) - [Support + Feedback](#support--feedback) @@ -249,6 +250,37 @@ Route::get('/api/public', function () { })->middleware(['auth0.authorize.optional']); ``` +### Authorizing HTTP Tests +If your application does contain HTTP tests which access routes that are protected by the `auth0.authorize` middleware, you can use the trait `Auth0\Laravel\Traits\ActingAsAuth0User` in your tests, which will give you a helper method `actingAsAuth0User(array $attributes=[])` simmilar to Laravels `actingAs` method, that allows you to fake beeing authenticated as a Auth0 user. + +The argument `attributes` is optional and you can use it to set any auth0 specific user attributes like scope, sub, azp, iap and so on. If no attributes are set, some default values are used. + +#### Example with a scope protected route +Let's assume you have a route like the following, that is protected by the scope `read:messages`: +```php +Route::get('/api/private-scoped', function () { + return response()->json([ + 'message' => 'Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.', + 'authorized' => Auth::check(), + 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, + ], 200, [], JSON_PRETTY_PRINT); +})->middleware(['auth0.authorize:read:messages']); +``` + +To be able to test the route from above, the implementation of your test would have to look like this: +```php + use Auth0\Laravel\Traits\ActingAsAuth0User; + + public function test_readMessages(){ + $response = $this->actingAsAuth0User([ + "scope"=>"read:messages" + ])->getJson("/api/private-scoped"); + + $response->assertStatus(200); + } +``` + + ## Documentation We provide a number of sample apps that demonstrate common use cases, to help you get started using this SDK: diff --git a/src/Traits/ActingAsAuth0User.php b/src/Traits/ActingAsAuth0User.php new file mode 100644 index 00000000..120f0b50 --- /dev/null +++ b/src/Traits/ActingAsAuth0User.php @@ -0,0 +1,45 @@ + 'some-auth0-user-id', + 'azp' => 'some-auth0-appplication-client-id', + 'iat' => time(), + 'exp' => time() + 60 * 60, + 'scope' => '', + ]; + + $auth0user = new User(array_merge($defaults, $attributes)); + + if ($auth0user->getAttribute('scope')) { + app()->make(StateInstance::class)->setAccessTokenScope(explode(' ', $auth0user->getAttribute('scope'))); + } + + return $this->actingAs($auth0user, 'auth0'); + } +} From d0f6e29df8d175b37013234471f8201aa7475256 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 1 May 2022 16:25:55 -0500 Subject: [PATCH 092/525] Normalize Package manifest (#280) * Normalize Composer manifest * Update tests * Update composer.json * Update tests.yml * Create security.yml * Update security.yml * Update security.yml * Update security.yml * Update security.yml * Update security.yml * Delete config.yml * Update security.yml * Update security.yml --- .circleci/config.yml | 166 --------------------------------- .github/workflows/checks.yml | 19 ++++ .github/workflows/security.yml | 84 +++++++++++++++++ .github/workflows/tests.yml | 108 +++++++++++++++++++++ composer.json | 53 ++++++----- 5 files changed, 241 insertions(+), 189 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 .github/workflows/checks.yml create mode 100644 .github/workflows/security.yml create mode 100644 .github/workflows/tests.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index fea69ed5..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,166 +0,0 @@ -version: 2.1 - -commands: - setup: - steps: - - run: - name: Configure environment - command: | - apk update - - - checkout - - - run: - name: Install dependencies - command: | - EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')" - php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" - ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")" - - if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then - >&2 echo 'ERROR: Invalid installer checksum' - rm composer-setup.php - exit 1 - fi - - php composer-setup.php --quiet - RESULT=$? - rm composer-setup.php - - php composer.phar install --no-interaction --prefer-dist - - setup-pcov: - steps: - - run: - name: Configure pcov - command: | - apk add autoconf gcc make musl-dev - pecl install pcov - docker-php-ext-enable pcov - - run-phpinsights: - steps: - - run: - name: Run code quality analysis (PHP Insights) - command: php -d memory-limit=-1 ./vendor/bin/phpinsights -v --no-interaction --min-quality=100 --min-complexity=50 --min-architecture=100 --min-style=100 - - run-rector: - steps: - - run: - name: Run code quality analysis (Rector) - command: php -d memory_limit=-1 ./vendor/bin/rector process src --dry-run - - run-phpstan: - steps: - - run: - name: Run static code analysis (PHPStan) - command: php -d memory_limit=-1 ./vendor/bin/phpstan analyse --ansi - - run-pest: - steps: - - run: - name: Run unit tests (Pest) - command: php -d memory_limit=-1 ./vendor/bin/pest --stop-on-failure --min=100 - - run-snyk: - steps: - - run: - name: Run vulnerabilities tests (Snyk) - command: | - apk add npm - npm install -g snyk - snyk test --dev --org=auth0-sdks --project-name=auth0-PHP - -jobs: - phpinsights: - parameters: - php: - type: string - docker: - - image: php:<< parameters.php >>-cli-alpine - steps: - - setup - - run-phpinsights - - rector: - parameters: - php: - type: string - docker: - - image: php:<< parameters.php >>-cli-alpine - steps: - - setup - - run-rector - - phpstan: - parameters: - php: - type: string - docker: - - image: php:<< parameters.php >>-cli-alpine - steps: - - setup - - run-phpstan - - pest: - parameters: - php: - type: string - docker: - - image: php:<< parameters.php >>-cli-alpine - steps: - - setup - - setup-pcov - - run-pest - - snyk: - parameters: - php: - type: string - docker: - - image: php:<< parameters.php >>-cli-alpine - steps: - - setup - - run-snyk - - semgrep: - docker: - - image: returntocorp/semgrep-agent:v1 - environment: - SEMGREP_REPO_NAME: "auth0/laravel-auth0" - SEMGREP_REPO_URL: "https://github.com/auth0/laravel-auth0" - steps: - - checkout - - run: - name: Run vulnerabilities tests (Semgrep) - command: | - semgrep-agent --baseline-ref main --publish-token $SEMGREP_TOKEN - -workflows: - test: - jobs: - - phpinsights: - matrix: - parameters: - php: ["7.4", "8.0", "8.1"] - - rector: - matrix: - parameters: - php: ["7.4", "8.0", "8.1"] - - phpstan: - matrix: - parameters: - php: ["7.4", "8.0", "8.1"] - - pest: - matrix: - parameters: - php: ["7.4", "8.0", "8.1"] - - semgrep: - context: - - semgrep-env - - snyk: - matrix: - parameters: - php: ["7.4", "8.0", "8.1"] - context: - - snyk-env diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 00000000..684766d6 --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,19 @@ +name: Checks + +on: + push: + branches: + - main + pull_request: + +jobs: + composer-normalize: + name: Composer Normalize + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Composer normalize + uses: docker://ergebnis/composer-normalize-action diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 00000000..a2dd96de --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,84 @@ +name: Security + +on: + push: + branches: + - main + pull_request: + +jobs: + snyk: + name: Snyk + runs-on: ubuntu-latest + strategy: + max-parallel: 10 + matrix: + php: ["7.4", "8.0", "8.1"] + + if: (github.actor != 'dependabot[bot]') + steps: + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + extensions: mbstring + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install dependencies + run: composer update --no-interaction --no-progress + + - name: Run Snyk to check for vulnerabilities + uses: snyk/actions/php@master + continue-on-error: true + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + with: + args: --severity-threshold=high --sarif-file-output=snyk.sarif + + - name: Check to see if the SARIF a was generated + id: sarif_file_exists + uses: andstor/file-existence-action@v1 + with: + files: "snyk.sarif" + + - name: Upload result to GitHub Code Scanning + uses: github/codeql-action/upload-sarif@v2 + if: steps.sarif_file_exists.outputs.files_exists == 'true' + with: + sarif_file: snyk.sarif + + semgrep: + name: Semgrep + runs-on: ubuntu-latest + container: + image: returntocorp/semgrep + + if: (github.actor != 'dependabot[bot]') + steps: + - uses: actions/checkout@v3 + + - run: semgrep scan --sarif --output=semgrep.sarif + env: + SEMGREP_RULES: >- + p/phpcs-security-audit + p/security-audit + p/secrets + p/owasp-top-ten + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} + SEMGREP_REPO_NAME: "auth0/laravel-auth0" + SEMGREP_REPO_URL: "https://github.com/auth0/laravel-auth0" + + - name: Check to see if the SARIF a was generated + id: sarif_file_exists + uses: andstor/file-existence-action@v1 + with: + files: "semgrep.sarif" + + - name: Upload SARIF file for GitHub Advanced Security Dashboard + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: semgrep.sarif + if: always() diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..7ec93393 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,108 @@ +name: Static analysis + +on: + push: + branches: + - main + pull_request: + +jobs: + phpstan: + name: PHPStan + runs-on: ubuntu-latest + strategy: + max-parallel: 10 + matrix: + php: ["7.4", "8.0", "8.1"] + + steps: + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + extensions: mbstring + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install dependencies + run: composer update --no-interaction --no-progress + + - name: Execute PHPStan + run: vendor/bin/phpstan analyze --no-progress + + phpinsights: + name: PHPInsights + runs-on: ubuntu-latest + strategy: + max-parallel: 10 + matrix: + php: ["7.4", "8.0", "8.1"] + + steps: + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + extensions: mbstring + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install dependencies + run: composer update --no-interaction --no-progress + + - name: Execute PHPInsights + run: vendor/bin/phpinsights --no-interaction + + rector: + name: Rector + runs-on: ubuntu-latest + strategy: + max-parallel: 10 + matrix: + php: ["7.4", "8.0", "8.1"] + + steps: + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + extensions: mbstring + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install dependencies + run: composer update --no-interaction --no-progress + + - name: Execute Rector + run: vendor/bin/rector process src --dry-run + + pest: + name: Pest + runs-on: ubuntu-latest + strategy: + max-parallel: 10 + matrix: + php: ["7.4", "8.0", "8.1"] + + steps: + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: pcov + extensions: mbstring + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install dependencies + run: composer update --no-interaction --no-progress + + - name: Execute Pest + run: vendor/bin/pest --stop-on-failure --coverage diff --git a/composer.json b/composer.json index aaad8bbc..7717ad5d 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,7 @@ { "name": "auth0/login", "description": "Auth0 Laravel SDK. Straight-forward and tested methods for implementing authentication, and accessing Auth0's Management API endpoints.", + "license": "MIT", "type": "library", "keywords": [ "laravel", @@ -19,8 +20,6 @@ "protect", "api" ], - "homepage": "https://github.com/auth0/laravel-auth0", - "license": "MIT", "authors": [ { "name": "Auth0", @@ -28,6 +27,7 @@ "homepage": "https://auth0.com/" } ], + "homepage": "https://github.com/auth0/laravel-auth0", "require": { "php": "^7.4 || ^8.0", "ext-filter": "*", @@ -37,10 +37,11 @@ "auth0/auth0-php": "^8.0", "illuminate/contracts": "^8.0 || ^9.0", "illuminate/http": "^8.0 || ^9.0", - "illuminate/support": " ^8.0 || ^9.0", + "illuminate/support": "^8.0 || ^9.0", "spatie/laravel-package-tools": "^1.9" }, "require-dev": { + "ergebnis/composer-normalize": "^2.25", "ergebnis/phpstan-rules": "^1.0", "laravel/laravel": "^8.4.4 || ^9.0", "nunomaduro/larastan": "^1.0", @@ -65,54 +66,60 @@ "Auth0\\Laravel\\Tests\\": "tests" } }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "pestphp/pest-plugin": true, + "ergebnis/composer-normalize": true, + "wikimedia/composer-merge-plugin": true + }, + "optimize-autoloader": true, + "sort-packages": true + }, "extra": { "laravel": { - "providers": [ - "Auth0\\Laravel\\ServiceProvider" - ], "aliases": { "Auth0": "Auth0\\Laravel\\Facade\\Auth0" - } + }, + "providers": [ + "Auth0\\Laravel\\ServiceProvider" + ] }, "merge-plugin": { + "ignore-duplicates": false, "include": [ "composer.local.json" ], - "recurse": true, - "replace": true, - "ignore-duplicates": false, "merge-dev": true, "merge-extra": false, "merge-extra-deep": false, - "merge-scripts": false + "merge-scripts": false, + "recurse": true, + "replace": true } }, - "config": { - "optimize-autoloader": true, - "sort-packages": true - }, "scripts": { "tests": [ + "@tests:pest", "@tests:phpinsights", - "@tests:rector", "@tests:phpstan", - "@tests:pest" + "@tests:rector" ], - "tests:phpinsights": [ + "tests:pest": [ "Composer\\Config::disableProcessTimeout", - "@php ./vendor/bin/phpinsights -v --no-interaction" + "@php ./vendor/bin/pest --stop-on-failure --coverage" ], - "tests:rector": [ + "tests:phpinsights": [ "Composer\\Config::disableProcessTimeout", - "@php ./vendor/bin/rector process src --dry-run" + "@php ./vendor/bin/phpinsights -v --no-interaction" ], "tests:phpstan": [ "Composer\\Config::disableProcessTimeout", "@php ./vendor/bin/phpstan analyse --ansi --memory-limit 512M" ], - "tests:pest": [ + "tests:rector": [ "Composer\\Config::disableProcessTimeout", - "@php ./vendor/bin/pest --stop-on-failure --coverage" + "@php ./vendor/bin/rector process src --dry-run" ] } } From c6bb0288f35396f50400e20462f1530a32d82df4 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 1 May 2022 17:31:19 -0400 Subject: [PATCH 093/525] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 287ca689..7ed8eb2c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ # Auth0 Laravel SDK -[![Build Status](https://img.shields.io/circleci/project/github/auth0/laravel-auth0/main.svg)](https://circleci.com/gh/auth0/laravel-auth0) [![Latest Stable Version](https://img.shields.io/packagist/v/auth0/login?label=stable)](https://packagist.org/packages/auth0/laravel-auth0) [![Latest Version](https://img.shields.io/packagist/v/auth0/login?include_prereleases&label=latest)](https://packagist.org/packages/auth0/laravel-auth0) [![Supported PHP Versions](https://img.shields.io/packagist/php-v/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) +![example branch parameter](https://github.com/auth0/laravel-auth0/actions/workflows/checks.yml/badge.svg) +![example branch parameter](https://github.com/auth0/laravel-auth0/actions/workflows/security.yml/badge.svg) +![example branch parameter](https://github.com/auth0/laravel-auth0/actions/workflows/tests.yml/badge.svg) [![License](https://img.shields.io/packagist/l/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0.svg?type=shield)](https://app.fossa.com/reports/4ef17265-c913-439b-8573-70bfc40d974d) From bb52257f1da80e35b0c6e06913f7f5fb94191ee8 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 1 May 2022 17:32:23 -0400 Subject: [PATCH 094/525] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7ed8eb2c..15ff5c7c 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ [![Latest Stable Version](https://img.shields.io/packagist/v/auth0/login?label=stable)](https://packagist.org/packages/auth0/laravel-auth0) [![Latest Version](https://img.shields.io/packagist/v/auth0/login?include_prereleases&label=latest)](https://packagist.org/packages/auth0/laravel-auth0) [![Supported PHP Versions](https://img.shields.io/packagist/php-v/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) -![example branch parameter](https://github.com/auth0/laravel-auth0/actions/workflows/checks.yml/badge.svg) -![example branch parameter](https://github.com/auth0/laravel-auth0/actions/workflows/security.yml/badge.svg) -![example branch parameter](https://github.com/auth0/laravel-auth0/actions/workflows/tests.yml/badge.svg) +![Build Status](https://github.com/auth0/laravel-auth0/actions/workflows/checks.yml/badge.svg) +![Build Status](https://github.com/auth0/laravel-auth0/actions/workflows/security.yml/badge.svg) +![Build Status](https://github.com/auth0/laravel-auth0/actions/workflows/tests.yml/badge.svg) [![License](https://img.shields.io/packagist/l/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0.svg?type=shield)](https://app.fossa.com/reports/4ef17265-c913-439b-8573-70bfc40d974d) From 89b91057ffe1c6fbd8c5656a25f1974e17c9f347 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 1 May 2022 18:08:52 -0400 Subject: [PATCH 095/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 15ff5c7c..d93e18fb 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ This SDK helps you integrate your [Laravel](https://laravel.com/) application wi The supported method of SDK installation is through [Composer](https://getcomposer.org/). From your terminal shell, `cd` into your project directory and issue the following command: ```bash -composer require auth0/login:dev-main +composer require auth0/login ``` ### Configuration the SDK From 6a34c7aab35f0ad0c8d5c9de554de3d48b39ae52 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 1 May 2022 18:09:41 -0400 Subject: [PATCH 096/525] Update README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d93e18fb..775d2593 100644 --- a/README.md +++ b/README.md @@ -271,15 +271,15 @@ Route::get('/api/private-scoped', function () { To be able to test the route from above, the implementation of your test would have to look like this: ```php - use Auth0\Laravel\Traits\ActingAsAuth0User; +use Auth0\Laravel\Traits\ActingAsAuth0User; - public function test_readMessages(){ - $response = $this->actingAsAuth0User([ - "scope"=>"read:messages" - ])->getJson("/api/private-scoped"); +public function test_readMessages(){ + $response = $this->actingAsAuth0User([ + "scope"=>"read:messages" + ])->getJson("/api/private-scoped"); - $response->assertStatus(200); - } + $response->assertStatus(200); +} ``` From 55d1eb05866f1853f94319180de0100f2bbf8a13 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 1 May 2022 17:33:16 -0500 Subject: [PATCH 097/525] Cleanup test suite (#281) * Cleanup test suite * Update tests.yml * Update .gitignore --- .../workflows-configs/phpinsights.php | 0 .../workflows-configs/phpstan.neon.dist | 0 .../workflows-configs/phpunit.xml.dist | 0 .../workflows-configs/rector.php | 0 .github/workflows/tests.yml | 14 ++++++++++- .gitignore | 6 ++++- composer.json | 24 ------------------- infection.json.dist | 15 ------------ 8 files changed, 18 insertions(+), 41 deletions(-) rename phpinsights.php => .github/workflows-configs/phpinsights.php (100%) rename phpstan.neon.dist => .github/workflows-configs/phpstan.neon.dist (100%) rename phpunit.xml.dist => .github/workflows-configs/phpunit.xml.dist (100%) rename rector.php => .github/workflows-configs/rector.php (100%) delete mode 100644 infection.json.dist diff --git a/phpinsights.php b/.github/workflows-configs/phpinsights.php similarity index 100% rename from phpinsights.php rename to .github/workflows-configs/phpinsights.php diff --git a/phpstan.neon.dist b/.github/workflows-configs/phpstan.neon.dist similarity index 100% rename from phpstan.neon.dist rename to .github/workflows-configs/phpstan.neon.dist diff --git a/phpunit.xml.dist b/.github/workflows-configs/phpunit.xml.dist similarity index 100% rename from phpunit.xml.dist rename to .github/workflows-configs/phpunit.xml.dist diff --git a/rector.php b/.github/workflows-configs/rector.php similarity index 100% rename from rector.php rename to .github/workflows-configs/rector.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7ec93393..c4461bfa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,6 +29,9 @@ jobs: - name: Install dependencies run: composer update --no-interaction --no-progress + - name: Prepare configuration + run: mv $GITHUB_WORKSPACE/.github/workflows-configs/phpstan.neon.dist $GITHUB_WORKSPACE/phpstan.neon.dist + - name: Execute PHPStan run: vendor/bin/phpstan analyze --no-progress @@ -54,6 +57,9 @@ jobs: - name: Install dependencies run: composer update --no-interaction --no-progress + - name: Prepare configuration + run: mv $GITHUB_WORKSPACE/.github/workflows-configs/phpinsights.php $GITHUB_WORKSPACE/phpinsights.php + - name: Execute PHPInsights run: vendor/bin/phpinsights --no-interaction @@ -79,6 +85,9 @@ jobs: - name: Install dependencies run: composer update --no-interaction --no-progress + - name: Prepare configuration + run: mv $GITHUB_WORKSPACE/.github/workflows-configs/rector.php $GITHUB_WORKSPACE/rector.php + - name: Execute Rector run: vendor/bin/rector process src --dry-run @@ -104,5 +113,8 @@ jobs: - name: Install dependencies run: composer update --no-interaction --no-progress + - name: Prepare configuration + run: mv $GITHUB_WORKSPACE/.github/workflows-configs/phpunit.xml.dist $GITHUB_WORKSPACE/phpunit.xml.dist + - name: Execute Pest - run: vendor/bin/pest --stop-on-failure --coverage + run: vendor/bin/pest --ci --coverage diff --git a/.gitignore b/.gitignore index a4ec8e0a..1345ad9d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,8 @@ vendor/ composer.lock composer.phar .phpunit.result.cache -composer.local.json +composer.local.json +phpinsights.php +phpstan.neon.dist +phpunit.xml.dist +rector.php diff --git a/composer.json b/composer.json index 7717ad5d..d95510df 100644 --- a/composer.json +++ b/composer.json @@ -97,29 +97,5 @@ "recurse": true, "replace": true } - }, - "scripts": { - "tests": [ - "@tests:pest", - "@tests:phpinsights", - "@tests:phpstan", - "@tests:rector" - ], - "tests:pest": [ - "Composer\\Config::disableProcessTimeout", - "@php ./vendor/bin/pest --stop-on-failure --coverage" - ], - "tests:phpinsights": [ - "Composer\\Config::disableProcessTimeout", - "@php ./vendor/bin/phpinsights -v --no-interaction" - ], - "tests:phpstan": [ - "Composer\\Config::disableProcessTimeout", - "@php ./vendor/bin/phpstan analyse --ansi --memory-limit 512M" - ], - "tests:rector": [ - "Composer\\Config::disableProcessTimeout", - "@php ./vendor/bin/rector process src --dry-run" - ] } } diff --git a/infection.json.dist b/infection.json.dist deleted file mode 100644 index e3bfe945..00000000 --- a/infection.json.dist +++ /dev/null @@ -1,15 +0,0 @@ -{ - "source": { - "directories": [ - "src" - ] - }, - "logs": { - "text": "infection.log", - "perMutator": "infection.mutators.md" - }, - "mutators": { - "@default": true - }, - "testFramework": "pest" -} From bd6ee079a30f10c1c8dbfb7e470c50f53251e45a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 1 May 2022 19:52:14 -0400 Subject: [PATCH 098/525] Update README.md --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 775d2593..32d5aba8 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,7 @@ [![Latest Stable Version](https://img.shields.io/packagist/v/auth0/login?label=stable)](https://packagist.org/packages/auth0/laravel-auth0) [![Latest Version](https://img.shields.io/packagist/v/auth0/login?include_prereleases&label=latest)](https://packagist.org/packages/auth0/laravel-auth0) [![Supported PHP Versions](https://img.shields.io/packagist/php-v/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) -![Build Status](https://github.com/auth0/laravel-auth0/actions/workflows/checks.yml/badge.svg) -![Build Status](https://github.com/auth0/laravel-auth0/actions/workflows/security.yml/badge.svg) -![Build Status](https://github.com/auth0/laravel-auth0/actions/workflows/tests.yml/badge.svg) [![License](https://img.shields.io/packagist/l/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0.svg?type=shield)](https://app.fossa.com/reports/4ef17265-c913-439b-8573-70bfc40d974d) This SDK helps you integrate your [Laravel](https://laravel.com/) application with [Auth0](https://auth0.com/) to achieve single sign-on with a few simple steps. The SDK also provides an easy method of integration all the functionality of the underlying [Auth0-PHP](https://github.com/auth0/auth-PHP) inside your Laravel application, including all types of authentication, authorization of API endpoints, and issuing Management API calls. From 1f2619b7a1916cc2a4c912cbb65aedd39bb4d306 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 May 2022 00:22:58 -0400 Subject: [PATCH 099/525] Update rector/rector requirement from ^0.12.16 to ^0.12.16 || ^0.13.0 (#285) Updates the requirements on [rector/rector](https://github.com/rectorphp/rector) to permit the latest version. - [Release notes](https://github.com/rectorphp/rector/releases) - [Commits](https://github.com/rectorphp/rector/compare/0.12.16...0.13.0) --- updated-dependencies: - dependency-name: rector/rector dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d95510df..bab9ab63 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,7 @@ "pestphp/pest-plugin-laravel": "^1.2", "phpstan/phpstan-strict-rules": "^1.1", "phpunit/phpunit": "^9.5", - "rector/rector": "^0.12.16", + "rector/rector": "^0.12.16 || ^0.13.0", "thecodingmachine/phpstan-strict-rules": "^1.0", "wikimedia/composer-merge-plugin": "^2.0" }, From 248ed56804f880c5d758ed1141a596a071f6125e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 1 Jun 2022 19:11:32 -0500 Subject: [PATCH 100/525] fix: `errorDescription` value incorrectly assigned (#288) --- src/Http/Controller/Stateful/Callback.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index de3a2904..d5c5795d 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -40,7 +40,7 @@ public function __invoke( $error = $request->query('error', ''); $errorDescription = $request->query('error_description', ''); $error = is_string($error) ? $error : ''; - $errorDescription = is_string($errorDescription) ? $error : ''; + $errorDescription = is_string($errorDescription) ? $errorDescription : ''; // Clear the local session via the Auth0-PHP SDK: app('auth0')->getSdk()->clear(); From b62e775d745b054e774f2c59a1c3f85309d89d41 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 1 Jun 2022 19:31:22 -0500 Subject: [PATCH 101/525] Release 7.0.1 (#289) --- CHANGELOG.md | 11 +++++++++++ src/Auth0.php | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bea13ef6..1742bfec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Change Log +## [7.0.1](https://github.com/auth0/laravel-auth0/tree/7.0.1) (2022-06-01) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.0.0...7.0.1) + +**Fixed** + +- Fixed an issue in `Auth0\Laravel\Http\Controller\Stateful\Callback` where `$errorDescription`'s value was assigned an incorrect value when an error was encountered. [\#266](https://github.com/auth0/laravel-auth0/pull/288) ([evansims](https://github.com/evansims)) + +**Closed Issues** +- Resolves [\#287](https://github.com/auth0/laravel-auth0/issues/287) ([piljac1](https://github.com/piljac1)) + ## [7.0.0](https://github.com/auth0/laravel-auth0/tree/7.0.0) (2022-03-21) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.5.0...7.0.0) diff --git a/src/Auth0.php b/src/Auth0.php index a828b93a..e67aea11 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -12,7 +12,7 @@ final class Auth0 implements \Auth0\Laravel\Contract\Auth0 /** * The Laravel-Auth0 SDK version: */ - public const VERSION = '7.0.0'; + public const VERSION = '7.0.1'; /** * An instance of the Auth0-PHP SDK. From 9c15e59f2ad02d66e7b656eb8124ae4622b9d4d5 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 9 Jun 2022 09:03:02 -0500 Subject: [PATCH 102/525] Update security.yml --- .github/workflows/security.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index a2dd96de..169453f8 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -71,14 +71,14 @@ jobs: SEMGREP_REPO_NAME: "auth0/laravel-auth0" SEMGREP_REPO_URL: "https://github.com/auth0/laravel-auth0" - - name: Check to see if the SARIF a was generated - id: sarif_file_exists - uses: andstor/file-existence-action@v1 - with: - files: "semgrep.sarif" +# - name: Check to see if the SARIF a was generated +# id: sarif_file_exists +# uses: andstor/file-existence-action@v1 +# with: +# files: "semgrep.sarif" - - name: Upload SARIF file for GitHub Advanced Security Dashboard - uses: github/codeql-action/upload-sarif@v2 - with: - sarif_file: semgrep.sarif - if: always() +# - name: Upload SARIF file for GitHub Advanced Security Dashboard +# uses: github/codeql-action/upload-sarif@v2 +# with: +# sarif_file: semgrep.sarif +# if: always() From 08ba514ad10de09356c496c057369c917e955955 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 9 Jun 2022 09:29:11 -0500 Subject: [PATCH 103/525] Update rector.php --- .github/workflows-configs/rector.php | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/.github/workflows-configs/rector.php b/.github/workflows-configs/rector.php index 05a45e1b..cfe882bf 100644 --- a/.github/workflows-configs/rector.php +++ b/.github/workflows-configs/rector.php @@ -2,25 +2,21 @@ declare(strict_types=1); -use Rector\Core\Configuration\Option; -use Rector\Set\ValueObject\LevelSetList; -use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; +use Rector\Config\RectorConfig; +use Rector\Core\ValueObject\PhpVersion; +use Rector\Php74\Rector\Property\TypedPropertyRector; +use Rector\Set\ValueObject\SetList; -return static function (ContainerConfigurator $containerConfigurator): void { - // get parameters - $parameters = $containerConfigurator->parameters(); - $parameters->set(Option::PATHS, [ - __DIR__ . '/src', - ]); +return static function (RectorConfig $rectorConfig): void { + $rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/tests']); - // Define what rule sets will be applied - $containerConfigurator->import(LevelSetList::UP_TO_PHP_74); + $rectorConfig->sets([ + SetList::CODE_QUALITY, + ]); - // get services (needed for register a single rule) - // $services = $containerConfigurator->services(); + $rectorConfig->rule(TypedPropertyRector::class); - // register a single rule - // $services->set(TypedPropertyRector::class); + $rectorConfig->phpVersion(PhpVersion::PHP_74); - $parameters->set(Option::PHPSTAN_FOR_RECTOR_PATH, getcwd() . '/phpstan.neon.dist'); + $rectorConfig->phpstanConfig(__DIR__ . '/phpstan.neon.dist'); }; From a268a57927e909ca88723fc092e334aefbfd371e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 9 Jun 2022 09:30:48 -0500 Subject: [PATCH 104/525] Update tests.yml --- .github/workflows/tests.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c4461bfa..c07fdab3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -84,8 +84,11 @@ jobs: - name: Install dependencies run: composer update --no-interaction --no-progress + + - name: Prepare configuration (1/2) + run: mv $GITHUB_WORKSPACE/.github/workflows-configs/phpstan.neon.dist $GITHUB_WORKSPACE/phpstan.neon.dist - - name: Prepare configuration + - name: Prepare configuration (2/2) run: mv $GITHUB_WORKSPACE/.github/workflows-configs/rector.php $GITHUB_WORKSPACE/rector.php - name: Execute Rector From 7b1901bbeef7cecef290bf30e29b7a29795182db Mon Sep 17 00:00:00 2001 From: Frederik Prijck Date: Thu, 9 Jun 2022 16:33:47 +0200 Subject: [PATCH 105/525] Add Ship CLI configuration (#290) Co-authored-by: Evan Sims --- .shiprc | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .shiprc diff --git a/.shiprc b/.shiprc new file mode 100644 index 00000000..579ae8f7 --- /dev/null +++ b/.shiprc @@ -0,0 +1,6 @@ +{ + "files": { + "src/Auth0.php": [] + }, + "prefixVersion": false +} From c43f664a0b77b5a70c9058a77ba9c52507a2b2c9 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 16 Jun 2022 13:12:57 -0500 Subject: [PATCH 106/525] change: Use class names for app() calls (#291) * change: Use classes instead for app() calls * change: Minor code optimizations --- src/Auth/Guard.php | 19 +++++++------------ src/Configuration.php | 6 +++--- src/Http/Controller/Stateful/Callback.php | 10 +++++----- src/Http/Controller/Stateful/Login.php | 2 +- src/Http/Controller/Stateful/Logout.php | 2 +- 5 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 5553a468..fd34c05d 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -43,7 +43,7 @@ public function login( public function logout(): self { $this->getState()->setUser(null); - app('auth0')->getSdk()->clear(); + app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); return $this; } @@ -125,12 +125,7 @@ public function hasScope( string $scope ): bool { $state = $this->getState(); - - if (in_array($scope, $state->getAccessTokenScope() ?? [], true)) { - return true; - } - - return false; + return in_array($scope, $state->getAccessTokenScope() ?? [], true); } /** @@ -148,7 +143,7 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable try { // Attempt to decode the bearer token. - $decoded = app('auth0')->getSdk()->decode($token, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_TOKEN)->toArray(); + $decoded = app(\Auth0\Laravel\Auth0::class)->getSdk()->decode($token, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_TOKEN)->toArray(); } catch (\Auth0\SDK\Exception\InvalidTokenException $invalidToken) { // Invalid bearer token. return null; @@ -184,7 +179,7 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable private function getUserFromSession(): ?\Illuminate\Contracts\Auth\Authenticatable { // Retrieve an available session from the Auth0-PHP SDK. - $session = app('auth0')->getSdk()->getCredentials(); + $session = app(\Auth0\Laravel\Auth0::class)->getSdk()->getCredentials(); // If a session is not available, return null. if ($session === null) { @@ -236,14 +231,14 @@ private function handleSessionExpiration( if ($state->getRefreshToken() !== null) { try { // Try to renew our token. - app('auth0')->getSdk()->renew(); + app(\Auth0\Laravel\Auth0::class)->getSdk()->renew(); } catch (\Auth0\SDK\Exception\StateException $tokenRefreshFailed) { // Renew failed. Inform application. event(new \Auth0\Laravel\Event\Stateful\TokenRefreshFailed()); } // Retrieve updated state data - $refreshed = app('auth0')->getSdk()->getCredentials(); + $refreshed = app(\Auth0\Laravel\Auth0::class)->getSdk()->getCredentials(); if ($refreshed !== null && $refreshed->accessTokenExpired === false) { event(new \Auth0\Laravel\Event\Stateful\TokenRefreshSucceeded()); @@ -254,7 +249,7 @@ private function handleSessionExpiration( // We didn't have a refresh token, or the refresh failed. // Clear session. $state->clear(); - app('auth0')->getSdk()->clear(); + app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); // Inform host application. event(new \Auth0\Laravel\Event\Stateful\TokenExpired()); diff --git a/src/Configuration.php b/src/Configuration.php index 88cf75a7..33484996 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -16,11 +16,11 @@ public static function stringToArrayOrNull( ?string $config, string $delimiter = ' ' ): ?array { - if (is_string($config) === true && strlen($config) >= 1 && strlen($delimiter) >= 1) { + if (is_string($config) && strlen($config) >= 1 && strlen($delimiter) >= 1) { $response = explode($delimiter, $config); // @phpstan-ignore-next-line - if (is_array($response) === true && count($response) >= 1 && strlen(trim($response[0])) !== 0) { + if (is_array($response) && count($response) >= 1 && strlen(trim($response[0])) !== 0) { return $response; } } @@ -35,7 +35,7 @@ public static function stringToBoolOrNull( ?string $config, ?bool $default = null ): ?bool { - if (is_string($config) === true && strlen($config) >= 1) { + if (is_string($config) && strlen($config) >= 1) { $config = strtolower(trim($config)); return $config === 'true'; diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index d5c5795d..f4848323 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -20,17 +20,17 @@ public function __invoke( try { if ($request->query('state') !== null && $request->query('code') !== null) { - app('auth0')->getSdk()->exchange(); + app(\Auth0\Laravel\Auth0::class)->getSdk()->exchange(); } } catch (\Throwable $exception) { - app('auth0')->getSdk()->clear(); + app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); // Throw hookable $event to allow custom error handling scenarios. $event = new \Auth0\Laravel\Event\Stateful\AuthenticationFailed($exception, true); event($event); // If the event was not hooked by the host application, throw an exception: - if ($event->getThrowException() === true) { + if ($event->getThrowException()) { throw $exception; } } @@ -43,7 +43,7 @@ public function __invoke( $errorDescription = is_string($errorDescription) ? $errorDescription : ''; // Clear the local session via the Auth0-PHP SDK: - app('auth0')->getSdk()->clear(); + app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); // Create a dynamic exception to report the API error response: $exception = \Auth0\Laravel\Exception\Stateful\CallbackException::apiException($error, $errorDescription); @@ -53,7 +53,7 @@ public function __invoke( event($event); // If the event was not hooked by the host application, throw an exception: - if ($event->getThrowException() === true) { + if ($event->getThrowException()) { throw $exception; } } diff --git a/src/Http/Controller/Stateful/Login.php b/src/Http/Controller/Stateful/Login.php index 583ff76c..a73bd8dc 100644 --- a/src/Http/Controller/Stateful/Login.php +++ b/src/Http/Controller/Stateful/Login.php @@ -18,6 +18,6 @@ public function __invoke( return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); } - return redirect()->away(app('auth0')->getSdk()->login()); + return redirect()->away(app(\Auth0\Laravel\Auth0::class)->getSdk()->login()); } } diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index 56d6e82d..60ab5dbe 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -18,7 +18,7 @@ public function __invoke( $request->session()->invalidate(); $request->session()->regenerateToken(); - return redirect()->away(app('auth0')->getSdk()->authentication()->getLogoutLink(url(http://github.com/app()->make('config')->get('auth0.routes.home', '/')))); + return redirect()->away(app(\Auth0\Laravel\Auth0::class)->getSdk()->authentication()->getLogoutLink(url(http://github.com/app()->make('config')->get('auth0.routes.home', '/')))); } return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); From e468b0573ad85192581b89c5fd531c7c34bbb83a Mon Sep 17 00:00:00 2001 From: Anand Capur Date: Wed, 20 Jul 2022 01:43:20 -0700 Subject: [PATCH 107/525] Fix readme link to PHP SDK (#293) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 32d5aba8..46ff1d98 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Supported PHP Versions](https://img.shields.io/packagist/php-v/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) [![License](https://img.shields.io/packagist/l/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) -This SDK helps you integrate your [Laravel](https://laravel.com/) application with [Auth0](https://auth0.com/) to achieve single sign-on with a few simple steps. The SDK also provides an easy method of integration all the functionality of the underlying [Auth0-PHP](https://github.com/auth0/auth-PHP) inside your Laravel application, including all types of authentication, authorization of API endpoints, and issuing Management API calls. +This SDK helps you integrate your [Laravel](https://laravel.com/) application with [Auth0](https://auth0.com/) to achieve single sign-on with a few simple steps. The SDK also provides an easy method of integration all the functionality of the underlying [Auth0-PHP](https://github.com/auth0/auth0-PHP) inside your Laravel application, including all types of authentication, authorization of API endpoints, and issuing Management API calls. - [Requirements](#requirements) - [Usage](#usage) From e42a5480b2eaa8dad18f5b4400f10503efc52f33 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 5 Aug 2022 11:41:58 -0500 Subject: [PATCH 108/525] [SDK-3576] Return interfaces instead of concrete classes (#296) * Return interfaces instead of concrete classes * Return hard SdkConfiguration types due to upstream SDK requirements --- src/Auth0.php | 8 ++++---- src/Contract/Auth0.php | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Auth0.php b/src/Auth0.php index e67aea11..74381c8d 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -17,7 +17,7 @@ final class Auth0 implements \Auth0\Laravel\Contract\Auth0 /** * An instance of the Auth0-PHP SDK. */ - private ?\Auth0\SDK\Auth0 $sdk = null; + private ?\Auth0\SDK\Contract\Auth0Interface $sdk = null; /** * An instance of the Auth0-PHP SDK's SdkConfiguration, which handles configuration state. @@ -27,7 +27,7 @@ final class Auth0 implements \Auth0\Laravel\Contract\Auth0 /** * @inheritdoc */ - public function getSdk(): \Auth0\SDK\Auth0 + public function getSdk(): \Auth0\SDK\Contract\Auth0Interface { if ($this->sdk === null) { $this->sdk = new \Auth0\SDK\Auth0($this->getConfiguration()); @@ -41,7 +41,7 @@ public function getSdk(): \Auth0\SDK\Auth0 * @inheritdoc */ public function setSdk( - \Auth0\SDK\Auth0 $sdk + \Auth0\SDK\Contract\Auth0Interface $sdk ): self { $this->sdk = $sdk; $this->setSdkTelemetry(); @@ -73,7 +73,7 @@ public function setConfiguration( /** * @inheritdoc */ - public function getState(): \Auth0\Laravel\StateInstance + public function getState(): \Auth0\Laravel\Contract\StateInstance { return app()->make(\Auth0\Laravel\StateInstance::class); } diff --git a/src/Contract/Auth0.php b/src/Contract/Auth0.php index 7f03451b..619958bd 100644 --- a/src/Contract/Auth0.php +++ b/src/Contract/Auth0.php @@ -9,13 +9,13 @@ interface Auth0 /** * Create/return instance of the Auth0-PHP SDK. */ - public function getSdk(): \Auth0\SDK\Auth0; + public function getSdk(): \Auth0\SDK\Contract\Auth0Interface; /** * Create/return instance of the Auth0-PHP SDK. */ public function setSdk( - \Auth0\SDK\Auth0 $sdk + \Auth0\SDK\Contract\Auth0Interface $sdk ): self; /** @@ -33,5 +33,5 @@ public function setConfiguration( /** * Create/create a request state instance, a storage singleton containing authenticated user data. */ - public function getState(): \Auth0\Laravel\StateInstance; + public function getState(): \Auth0\Laravel\Contract\StateInstance; } From 1a4b3ee4588aaaf60fb054f9d342d70b7911a6f6 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 8 Aug 2022 16:49:12 -0500 Subject: [PATCH 109/525] [SDK-3585] Fix: `Missing Code` error on Callback Route for Octane Customers (#297) * Fix for `Missing Code` erroron Callback Route w/ Octane * Ignore PhpStorm project files --- .gitignore | 1 + src/Http/Controller/Stateful/Callback.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1345ad9d..d4fcd693 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ build/ vendor/ +.idea/ .env .DS_Store composer.lock diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index f4848323..5c9a4af5 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -20,7 +20,7 @@ public function __invoke( try { if ($request->query('state') !== null && $request->query('code') !== null) { - app(\Auth0\Laravel\Auth0::class)->getSdk()->exchange(); + app(\Auth0\Laravel\Auth0::class)->getSdk()->exchange(null, $request->query('code'), $request->query('state')); } } catch (\Throwable $exception) { app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); From 65ce48b315e0df0f7c0aa06ae0f79f8df0063a72 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 9 Aug 2022 10:00:22 -0500 Subject: [PATCH 110/525] Release 7.1.0 (#298) --- CHANGELOG.md | 10 ++++++++++ src/Auth0.php | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1742bfec..b62a3f8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## [7.1.0](https://github.com/auth0/laravel-auth0/tree/7.1.0) (2022-08-08) +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.0.1...7.1.0) + +**Changed** +- [SDK-3576] Return interfaces instead of concrete classes [\#296](https://github.com/auth0/laravel-auth0/pull/296) ([evansims](https://github.com/evansims)) +- change: Use class names for app() calls [\#291](https://github.com/auth0/laravel-auth0/pull/291) ([evansims](https://github.com/evansims)) + +**Fixed** +- [SDK-3585] Fix: `Missing Code` error on Callback Route for Octane Customers [\#297](https://github.com/auth0/laravel-auth0/pull/297) ([evansims](https://github.com/evansims)) + ## [7.0.1](https://github.com/auth0/laravel-auth0/tree/7.0.1) (2022-06-01) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.0.0...7.0.1) diff --git a/src/Auth0.php b/src/Auth0.php index 74381c8d..09217ec8 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -12,7 +12,7 @@ final class Auth0 implements \Auth0\Laravel\Contract\Auth0 /** * The Laravel-Auth0 SDK version: */ - public const VERSION = '7.0.1'; + public const VERSION = '7.1.0'; /** * An instance of the Auth0-PHP SDK. From 397d92dadb23aeecedb643b847cdd52b2ea2e87c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 25 Aug 2022 01:40:00 -0500 Subject: [PATCH 111/525] Create repo-maintenance.yml --- .github/workflows/repo-maintenance.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/repo-maintenance.yml diff --git a/.github/workflows/repo-maintenance.yml b/.github/workflows/repo-maintenance.yml new file mode 100644 index 00000000..c18bff90 --- /dev/null +++ b/.github/workflows/repo-maintenance.yml @@ -0,0 +1,22 @@ +name: 'Repository Maintenance' + +on: + schedule: + - cron: '0 * * * *' + workflow_dispatch: + +permissions: + issues: write + pull-requests: write + +concurrency: + group: lock + +jobs: + action: + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v3 + with: + issue-inactive-days: '30' + pr-inactive-days: '30' From fe07b0169e25f551e8ace0e93d37986944d3e619 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 25 Aug 2022 02:08:46 -0500 Subject: [PATCH 112/525] Refactor tests (#303) * Refactor tests * Update composer.json --- .github/workflows/tests.yml | 219 ++++++++++++++---- .gitignore | 5 +- composer.json | 11 +- .../phpinsights.php => phpinsights.php | 0 .../phpstan.neon.dist => phpstan.neon.dist | 2 - .../phpunit.xml.dist => phpunit.xml.dist | 0 pint.json | 4 + psalm.xml.dist | 26 +++ .../rector.php => rector.php | 0 9 files changed, 213 insertions(+), 54 deletions(-) rename .github/workflows-configs/phpinsights.php => phpinsights.php (100%) rename .github/workflows-configs/phpstan.neon.dist => phpstan.neon.dist (91%) rename .github/workflows-configs/phpunit.xml.dist => phpunit.xml.dist (100%) create mode 100644 pint.json create mode 100644 psalm.xml.dist rename .github/workflows-configs/rector.php => rector.php (100%) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c07fdab3..87ea8d69 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,4 +1,4 @@ -name: Static analysis +name: Analysis on: push: @@ -7,117 +7,256 @@ on: pull_request: jobs: - phpstan: - name: PHPStan + dependencies: + name: Dependencies runs-on: ubuntu-latest + strategy: max-parallel: 10 matrix: php: ["7.4", "8.0", "8.1"] steps: - - name: Set up PHP + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up PHP ${{ matrix.php }} uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} coverage: none extensions: mbstring + env: + update: true + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + + - name: Install dependencies with composer + run: composer update --no-ansi --no-interaction --no-progress --prefer-dist --prefer-stable + + pest: + name: Pest + runs-on: ubuntu-latest + continue-on-error: true + needs: ["dependencies"] + + strategy: + max-parallel: 10 + matrix: + php: ["7.4", "8.0", "8.1"] + + steps: + - name: Set up PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: pcov + extensions: mbstring + env: + update: true + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Checkout code uses: actions/checkout@v3 - - name: Install dependencies - run: composer update --no-interaction --no-progress + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - name: Prepare configuration - run: mv $GITHUB_WORKSPACE/.github/workflows-configs/phpstan.neon.dist $GITHUB_WORKSPACE/phpstan.neon.dist + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - name: Execute PHPStan - run: vendor/bin/phpstan analyze --no-progress + - name: Install dependencies with composer + run: composer install --prefer-dist + + - name: Execute Pest + run: vendor/bin/pest --coverage-clover coverage/coverage.xml --no-interaction - phpinsights: - name: PHPInsights + - if: (matrix.php == '8.1') + uses: codecov/codecov-action@v2 + with: + directory: coverage + + phpstan: + name: PHPStan runs-on: ubuntu-latest + needs: ["dependencies"] + strategy: + fail-fast: true max-parallel: 10 matrix: php: ["7.4", "8.0", "8.1"] steps: - - name: Set up PHP + - name: Set up PHP ${{ matrix.php }} uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} coverage: none extensions: mbstring + env: + update: true + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Checkout code uses: actions/checkout@v3 + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + - name: Install dependencies - run: composer update --no-interaction --no-progress + run: composer install --prefer-dist - - name: Prepare configuration - run: mv $GITHUB_WORKSPACE/.github/workflows-configs/phpinsights.php $GITHUB_WORKSPACE/phpinsights.php + - name: Execute PHPStan + run: vendor/bin/phpstan analyze --no-progress - - name: Execute PHPInsights - run: vendor/bin/phpinsights --no-interaction + # psalm: + # name: Psalm + # runs-on: ubuntu-latest + # needs: ["dependencies"] - rector: - name: Rector + # strategy: + # fail-fast: true + # max-parallel: 10 + # matrix: + # php: ["7.4", "8.0", "8.1"] + + # steps: + # - name: Set up PHP ${{ matrix.php }} + # uses: shivammathur/setup-php@v2 + # with: + # php-version: ${{ matrix.php }} + # coverage: none + # extensions: mbstring + # env: + # update: true + # COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # - name: Checkout code + # uses: actions/checkout@v3 + + # - name: Get composer cache directory + # id: composer-cache + # run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + # - name: Cache dependencies + # uses: actions/cache@v2 + # with: + # path: ${{ steps.composer-cache.outputs.dir }} + # key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + # restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + + # - name: Install dependencies + # run: composer install --prefer-dist + + # - name: Execute Psalm + # run: vendor/bin/psalm --no-progress + + pint: + name: Laravel Pint runs-on: ubuntu-latest + needs: ["dependencies"] + strategy: + fail-fast: true max-parallel: 10 matrix: - php: ["7.4", "8.0", "8.1"] + php: ["8.0", "8.1"] steps: - - name: Set up PHP + - name: Set up PHP ${{ matrix.php }} uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} coverage: none extensions: mbstring + env: + update: true + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Checkout code uses: actions/checkout@v3 + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + - name: Install dependencies - run: composer update --no-interaction --no-progress - - - name: Prepare configuration (1/2) - run: mv $GITHUB_WORKSPACE/.github/workflows-configs/phpstan.neon.dist $GITHUB_WORKSPACE/phpstan.neon.dist + run: composer install --prefer-dist - - name: Prepare configuration (2/2) - run: mv $GITHUB_WORKSPACE/.github/workflows-configs/rector.php $GITHUB_WORKSPACE/rector.php + - name: Install Laravel Pint + run: composer require laravel/pint:* --dev --with-all-dependencies - - name: Execute Rector - run: vendor/bin/rector process src --dry-run + - name: Execute Laravel Pint + run: vendor/bin/pint --test - pest: - name: Pest + rector: + name: Rector runs-on: ubuntu-latest + needs: ["dependencies"] + strategy: + fail-fast: true max-parallel: 10 matrix: php: ["7.4", "8.0", "8.1"] steps: - - name: Set up PHP + - name: Set up PHP ${{ matrix.php }} uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - coverage: pcov + coverage: none extensions: mbstring + env: + update: true + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Checkout code uses: actions/checkout@v3 - - name: Install dependencies - run: composer update --no-interaction --no-progress + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - name: Prepare configuration - run: mv $GITHUB_WORKSPACE/.github/workflows-configs/phpunit.xml.dist $GITHUB_WORKSPACE/phpunit.xml.dist + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - name: Execute Pest - run: vendor/bin/pest --ci --coverage + - name: Install dependencies + run: composer install --prefer-dist + + - name: Execute Rector + run: vendor/bin/rector process src --dry-run diff --git a/.gitignore b/.gitignore index d4fcd693..397959dd 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,4 @@ composer.lock composer.phar .phpunit.result.cache composer.local.json -phpinsights.php -phpstan.neon.dist -phpunit.xml.dist -rector.php + diff --git a/composer.json b/composer.json index bab9ab63..28286517 100644 --- a/composer.json +++ b/composer.json @@ -41,19 +41,16 @@ "spatie/laravel-package-tools": "^1.9" }, "require-dev": { - "ergebnis/composer-normalize": "^2.25", - "ergebnis/phpstan-rules": "^1.0", "laravel/laravel": "^8.4.4 || ^9.0", "nunomaduro/larastan": "^1.0", - "nunomaduro/phpinsights": "^2.0", "nyholm/psr7": "^1.4", "orchestra/testbench": "6.24.1", "pestphp/pest": "^1.21", "pestphp/pest-plugin-laravel": "^1.2", - "phpstan/phpstan-strict-rules": "^1.1", + "phpstan/phpstan": "^1.7", + "phpstan/phpstan-strict-rules": "^1.3", "phpunit/phpunit": "^9.5", - "rector/rector": "^0.12.16 || ^0.13.0", - "thecodingmachine/phpstan-strict-rules": "^1.0", + "rector/rector": "^0.13.6", "wikimedia/composer-merge-plugin": "^2.0" }, "autoload": { @@ -68,9 +65,7 @@ }, "config": { "allow-plugins": { - "dealerdirect/phpcodesniffer-composer-installer": true, "pestphp/pest-plugin": true, - "ergebnis/composer-normalize": true, "wikimedia/composer-merge-plugin": true }, "optimize-autoloader": true, diff --git a/.github/workflows-configs/phpinsights.php b/phpinsights.php similarity index 100% rename from .github/workflows-configs/phpinsights.php rename to phpinsights.php diff --git a/.github/workflows-configs/phpstan.neon.dist b/phpstan.neon.dist similarity index 91% rename from .github/workflows-configs/phpstan.neon.dist rename to phpstan.neon.dist index 6e534aa6..048f34c2 100644 --- a/.github/workflows-configs/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,7 +1,5 @@ includes: - vendor/phpstan/phpstan-strict-rules/rules.neon - - vendor/ergebnis/phpstan-rules/rules.neon - - vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon parameters: level: max diff --git a/.github/workflows-configs/phpunit.xml.dist b/phpunit.xml.dist similarity index 100% rename from .github/workflows-configs/phpunit.xml.dist rename to phpunit.xml.dist diff --git a/pint.json b/pint.json new file mode 100644 index 00000000..2bf69b74 --- /dev/null +++ b/pint.json @@ -0,0 +1,4 @@ +{ + "preset": "psr12", + "exclude": ["tests"] +} diff --git a/psalm.xml.dist b/psalm.xml.dist new file mode 100644 index 00000000..06744c2b --- /dev/null +++ b/psalm.xml.dist @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/.github/workflows-configs/rector.php b/rector.php similarity index 100% rename from .github/workflows-configs/rector.php rename to rector.php From d4c5da8ccbb4889d101306fcfc68d67f1bc44c3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Aug 2022 02:13:54 -0500 Subject: [PATCH 113/525] Update orchestra/testbench requirement from 6.24.1 to 6.25.0 (#302) Updates the requirements on [orchestra/testbench](https://github.com/orchestral/testbench) to permit the latest version. - [Release notes](https://github.com/orchestral/testbench/releases) - [Changelog](https://github.com/orchestral/testbench/blob/7.x/CHANGELOG-6.x.md) - [Commits](https://github.com/orchestral/testbench/compare/v6.24.1...v6.25.0) --- updated-dependencies: - dependency-name: orchestra/testbench dependency-type: direct:development ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 28286517..52a6bf71 100644 --- a/composer.json +++ b/composer.json @@ -44,7 +44,7 @@ "laravel/laravel": "^8.4.4 || ^9.0", "nunomaduro/larastan": "^1.0", "nyholm/psr7": "^1.4", - "orchestra/testbench": "6.24.1", + "orchestra/testbench": "6.25.0", "pestphp/pest": "^1.21", "pestphp/pest-plugin-laravel": "^1.2", "phpstan/phpstan": "^1.7", From 329ff4be4f23d3ded23564b171135755001d5dc5 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 25 Aug 2022 08:31:14 -0500 Subject: [PATCH 114/525] Update repo-maintenance.yml --- .github/workflows/repo-maintenance.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/repo-maintenance.yml b/.github/workflows/repo-maintenance.yml index c18bff90..3f74e250 100644 --- a/.github/workflows/repo-maintenance.yml +++ b/.github/workflows/repo-maintenance.yml @@ -2,7 +2,7 @@ name: 'Repository Maintenance' on: schedule: - - cron: '0 * * * *' + - cron: '0 0 * * *' workflow_dispatch: permissions: @@ -20,3 +20,11 @@ jobs: with: issue-inactive-days: '30' pr-inactive-days: '30' + issue-comment: > + This issue has been automatically locked since there + has not been any recent activity after it was closed. + Please open a new issue for related bugs. + pr-comment: > + This pull request has been automatically locked since there + has not been any recent activity after it was closed. + Please open a new issue for related bugs. From df06f93ba057c69ef9dd648a89bab552a3f25494 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 26 Aug 2022 01:15:32 -0500 Subject: [PATCH 115/525] Update README.md --- README.md | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/README.md b/README.md index 46ff1d98..78d67578 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ This SDK helps you integrate your [Laravel](https://laravel.com/) application wi - [Protecting Routes with Middleware](#protecting-routes-with-middleware) - [Regular Web Applications](#regular-web-applications-1) - [Backend API Applications](#backend-api-applications-1) + - [Custom User Providers](#custom-user-providers) - [Authorizing HTTP Tests](#authorizing-http-tests) - [Documentation](#documentation) - [Contributing](#contributing) @@ -248,7 +249,116 @@ Route::get('/api/public', function () { })->middleware(['auth0.authorize.optional']); ``` +### Custom User Models and Repositories + +In Laravel, a User Repository is an interface that sits between your authentication source (Auth0) and core Laravel authentication services. It allows you to shape and manipulate the user model and it's data as you need to. + +For example, Auth0's unique identifier is a `string` in the format `auth0|123456abcdef`. If you were to attempt to persist a user to many traditional databases you'd likely encounter an error as, by default, a unique identifier is often exected to be an `integer` rather than a `string` type. A custom user model and repository is a great way to address integration challenges like this. + +#### Creating a Custom User Model + +Let's setup a custom user model for our application. To do this, let's create a file at `app/Auth/Models/User.php` within our Laravel project. This new class needs to implement the `Illuminate\Contracts\Auth\Authenticatable` interface to be compatible with Laravel's Guard API and this SDK. It must also implement either `Auth0\Laravel\Contract\Model\Stateful\User` or `Auth0\Laravel\Contract\Model\Stateless\User` depending on your application's needs. For example: + +```php + + */ + protected $fillable = [ + 'id', + 'name', + 'email', + ]; + + /** + * The attributes that should be hidden for serialization. + * + * @var array + */ + protected $hidden = []; + + /** + * The attributes that should be cast. + * + * @var array + */ + protected $casts = []; +} +``` + +#### Creating a Custom User Repository + +Now let's create a custom user repository for your application which will return the new new custom model. To do this, create the file `app/Auth/CustomUserRepository.php`. This new class must implment the `Auth0\Laravel\Contract\Auth\User\Repository` interface. This new repository takes in user data returned from Auth0's API, applies it to the `App\Models\User` custom user model created in the previous step, and returns it for use throughout your application. + +```php + 'just_a_random_example|' . $user['sub'] ?? $user['user_id'] ?? null, + 'name' => $user['name'], + 'email' => $user['email'] + ]); + } + + public function fromAccessToken( + array $user + ): ?\Illuminate\Contracts\Auth\Authenticatable { + // Simliar to above. Used for stateless application types. + return null; + } +} +``` + +#### Creating a Custom User Repository + +Finally, update your application's `config/auth.php` file. Within the Auth0 provider, assign a custom `repository` value pointing to your new custom user provider class. For example: + +```php + 'providers' => [ + //... + + 'auth0' => [ + 'driver' => 'auth0', + 'repository' => App\Auth\CustomUserRepository::class + ], + ], +``` + ### Authorizing HTTP Tests + If your application does contain HTTP tests which access routes that are protected by the `auth0.authorize` middleware, you can use the trait `Auth0\Laravel\Traits\ActingAsAuth0User` in your tests, which will give you a helper method `actingAsAuth0User(array $attributes=[])` simmilar to Laravels `actingAs` method, that allows you to fake beeing authenticated as a Auth0 user. The argument `attributes` is optional and you can use it to set any auth0 specific user attributes like scope, sub, azp, iap and so on. If no attributes are set, some default values are used. From 89084d5e0c11f3cd68dbfe601c5e1694d6c2de49 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 26 Aug 2022 01:18:48 -0500 Subject: [PATCH 116/525] Update README.md --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 78d67578..12eeda45 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,10 @@ This SDK helps you integrate your [Laravel](https://laravel.com/) application wi - [Protecting Routes with Middleware](#protecting-routes-with-middleware) - [Regular Web Applications](#regular-web-applications-1) - [Backend API Applications](#backend-api-applications-1) - - [Custom User Providers](#custom-user-providers) + - [Custom User Models and Repositories](#custom-user-models-and-repositories) + - [Creating a Custom User Model](#creating-a-custom-user-model) + - [Creating a Custom User Repository](#creating-a-custom-user-repository) + - [Using a Custom User Repository](#using-a-custom-user-repository) - [Authorizing HTTP Tests](#authorizing-http-tests) - [Documentation](#documentation) - [Contributing](#contributing) @@ -342,7 +345,7 @@ class CustomUserRepository implements \Auth0\Laravel\Contract\Auth\User\Reposito } ``` -#### Creating a Custom User Repository +#### Using a Custom User Repository Finally, update your application's `config/auth.php` file. Within the Auth0 provider, assign a custom `repository` value pointing to your new custom user provider class. For example: From 0b5a158304bdcaf3afdfc08ca189185dad688d33 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 5 Sep 2022 20:43:41 -0500 Subject: [PATCH 117/525] Update repo-maintenance.yml --- .github/workflows/repo-maintenance.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/repo-maintenance.yml b/.github/workflows/repo-maintenance.yml index 3f74e250..a862d87a 100644 --- a/.github/workflows/repo-maintenance.yml +++ b/.github/workflows/repo-maintenance.yml @@ -20,11 +20,3 @@ jobs: with: issue-inactive-days: '30' pr-inactive-days: '30' - issue-comment: > - This issue has been automatically locked since there - has not been any recent activity after it was closed. - Please open a new issue for related bugs. - pr-comment: > - This pull request has been automatically locked since there - has not been any recent activity after it was closed. - Please open a new issue for related bugs. From a28d215a8185456c577da001d1450ad8bbed6bf6 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 14 Sep 2022 16:34:36 -0500 Subject: [PATCH 118/525] Typo fixes --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 12eeda45..c3271bed 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ This SDK helps you integrate your [Laravel](https://laravel.com/) application wi - [Creating a Custom User Repository](#creating-a-custom-user-repository) - [Using a Custom User Repository](#using-a-custom-user-repository) - [Authorizing HTTP Tests](#authorizing-http-tests) + - [Octane](#octane) - [Documentation](#documentation) - [Contributing](#contributing) - [Support + Feedback](#support--feedback) @@ -391,6 +392,13 @@ public function test_readMessages(){ } ``` +### Octane + +Octane compatibility is currently considered experimental and unsupported. + +Although we are working toward ensuring the SDK is fully compatible with this performance-enhancing technique using Open Swoole and RoadRunner, we do not recommend using this feature with our SDK in production until we have greenlit support fully. Due to the aggressive structural changes Octane introduces, there is a lot of room of opportunity for problem spots and niche edge cases we haven't resolved yet. + +In the meantime, feedback and bug fix contributions are greatly appreciated. ## Documentation From 633f39022073231a972f439daf0da203d6f10fb4 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 14 Sep 2022 17:07:54 -0500 Subject: [PATCH 119/525] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c3271bed..870bda87 100644 --- a/README.md +++ b/README.md @@ -396,9 +396,9 @@ public function test_readMessages(){ Octane compatibility is currently considered experimental and unsupported. -Although we are working toward ensuring the SDK is fully compatible with this performance-enhancing technique using Open Swoole and RoadRunner, we do not recommend using this feature with our SDK in production until we have greenlit support fully. Due to the aggressive structural changes Octane introduces, there is a lot of room of opportunity for problem spots and niche edge cases we haven't resolved yet. +Although we are working toward ensuring the SDK is fully compatible with this performance-enhancing technique backed by Open Swoole and RoadRunner, we do not recommend using this feature with our SDK in production until we have full confidence and greenlit support. Due to the aggressive changes Octane makes to Laravel's behavior, there is opportunity for problems we haven't fully identified or resolved yet. -In the meantime, feedback and bug fix contributions are greatly appreciated. +Feedback and bug fix contributions are greatly appreciated as we work on Octane support. ## Documentation From 11e68dbd23c3db8796a118e32007bf9a09c355b6 Mon Sep 17 00:00:00 2001 From: Tony Fox <111282924+tonyfox-disguise@users.noreply.github.com> Date: Thu, 15 Sep 2022 00:26:59 +0100 Subject: [PATCH 120/525] Added viaRemember function to guard (#306) * Added viaRemember function I've found some third-party apps like Filament use the Auth::viaRemember() when checking auth status * Update Guard.php * Remove blank line breaking linter Co-authored-by: Evan Sims Co-authored-by: Evan Sims --- src/Auth/Guard.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index fd34c05d..531c589e 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -127,6 +127,14 @@ public function hasScope( $state = $this->getState(); return in_array($scope, $state->getAccessTokenScope() ?? [], true); } + + /** + * Always returns false to keep third-party apps happy + */ + public function viaRemember(): bool + { + return false; + } /** * Get the user context from a provided access token. From 45e7ecb993fc5f2fe91e997309df525dfe41f39f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Oct 2022 16:36:59 -0500 Subject: [PATCH 121/525] [SDK-3669] Add StoreInterface bridge for Laravel Sessions (#307) * [SDK-3669] Add StoreInterface bridge support for Laravel Sessions * PHP 7.4 fixes * Drop PHP 7.4 support out of necessity for type definitions conflict * Drop 7.4 check from Snyk * Move Laravel/Pint into dev-dependencies * Fix PHP 8+ getItem definition for CacheItemPoolInterface * Add EBS to developer dependencies * Code style pass --- .github/workflows/security.yml | 2 +- .github/workflows/tests.yml | 55 +---- composer.json | 6 +- ecs.php | 89 ++++++++ phpstan.neon.dist | 12 -- src/Auth/Guard.php | 58 ++++-- src/Auth/User/Provider.php | 27 +-- src/Auth/User/Repository.php | 18 +- src/Auth0.php | 51 ++++- src/Cache/LaravelCacheItem.php | 92 +++++++++ src/Cache/LaravelCachePool.php | 192 ++++++++++++++++++ src/Configuration.php | 12 +- src/Contract/Auth/Guard.php | 9 +- src/Contract/Auth/User/Provider.php | 4 +- src/Contract/Auth/User/Repository.php | 8 +- src/Contract/Auth0.php | 8 +- src/Contract/Configuration.php | 10 +- src/Contract/Event/Configuration/Built.php | 29 +++ .../Event/Stateful/AuthenticationFailed.php | 13 +- .../Stateful/AuthenticationSucceeded.php | 8 +- .../Exception/Stateful/CallbackException.php | 5 +- .../Http/Controller/Stateful/Callback.php | 4 +- .../Http/Controller/Stateful/Login.php | 4 +- .../Http/Controller/Stateful/Logout.php | 4 +- .../Http/Middleware/Stateful/Authenticate.php | 8 +- .../Stateful/AuthenticateOptional.php | 8 +- .../Http/Middleware/Stateless/Authorize.php | 10 +- .../Stateless/AuthorizeOptional.php | 8 +- src/Contract/Model/User.php | 34 +--- src/Contract/ServiceProvider.php | 4 +- src/Contract/StateInstance.php | 28 +-- src/Event/Configuration/Built.php | 40 ++++ src/Event/Stateful/AuthenticationFailed.php | 16 +- .../Stateful/AuthenticationSucceeded.php | 10 +- src/Exception/Stateful/CallbackException.php | 6 +- src/Http/Controller/Stateful/Callback.php | 19 +- src/Http/Controller/Stateful/Login.php | 5 +- src/Http/Controller/Stateful/Logout.php | 20 +- src/Http/Middleware/Stateful/Authenticate.php | 15 +- .../Stateful/AuthenticateOptional.php | 15 +- src/Http/Middleware/Stateless/Authorize.php | 16 +- .../Stateless/AuthorizeOptional.php | 15 +- src/Model/User.php | 38 ++-- src/ServiceProvider.php | 52 ++++- src/StateInstance.php | 35 ++-- src/Store/LaravelSession.php | 152 ++++++++++++++ src/Traits/ActingAsAuth0User.php | 12 +- 47 files changed, 879 insertions(+), 407 deletions(-) create mode 100644 ecs.php create mode 100644 src/Cache/LaravelCacheItem.php create mode 100644 src/Cache/LaravelCachePool.php create mode 100644 src/Contract/Event/Configuration/Built.php create mode 100644 src/Event/Configuration/Built.php create mode 100644 src/Store/LaravelSession.php diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 169453f8..85d8ea84 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -13,7 +13,7 @@ jobs: strategy: max-parallel: 10 matrix: - php: ["7.4", "8.0", "8.1"] + php: "8.0", "8.1", "8.2"] if: (github.actor != 'dependabot[bot]') steps: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 87ea8d69..9df9d037 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,7 +14,7 @@ jobs: strategy: max-parallel: 10 matrix: - php: ["7.4", "8.0", "8.1"] + php: ["8.0", "8.1", "8.2"] steps: - name: Checkout code @@ -52,7 +52,7 @@ jobs: strategy: max-parallel: 10 matrix: - php: ["7.4", "8.0", "8.1"] + php: ["8.0", "8.1", "8.2"] steps: - name: Set up PHP ${{ matrix.php }} @@ -99,7 +99,7 @@ jobs: fail-fast: true max-parallel: 10 matrix: - php: ["7.4", "8.0", "8.1"] + php: ["8.0", "8.1", "8.2"] steps: - name: Set up PHP ${{ matrix.php }} @@ -132,48 +132,6 @@ jobs: - name: Execute PHPStan run: vendor/bin/phpstan analyze --no-progress - # psalm: - # name: Psalm - # runs-on: ubuntu-latest - # needs: ["dependencies"] - - # strategy: - # fail-fast: true - # max-parallel: 10 - # matrix: - # php: ["7.4", "8.0", "8.1"] - - # steps: - # - name: Set up PHP ${{ matrix.php }} - # uses: shivammathur/setup-php@v2 - # with: - # php-version: ${{ matrix.php }} - # coverage: none - # extensions: mbstring - # env: - # update: true - # COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # - name: Checkout code - # uses: actions/checkout@v3 - - # - name: Get composer cache directory - # id: composer-cache - # run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - # - name: Cache dependencies - # uses: actions/cache@v2 - # with: - # path: ${{ steps.composer-cache.outputs.dir }} - # key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - # restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - # - name: Install dependencies - # run: composer install --prefer-dist - - # - name: Execute Psalm - # run: vendor/bin/psalm --no-progress - pint: name: Laravel Pint runs-on: ubuntu-latest @@ -183,7 +141,7 @@ jobs: fail-fast: true max-parallel: 10 matrix: - php: ["8.0", "8.1"] + php: ["8.0", "8.1", "8.2"] steps: - name: Set up PHP ${{ matrix.php }} @@ -213,9 +171,6 @@ jobs: - name: Install dependencies run: composer install --prefer-dist - - name: Install Laravel Pint - run: composer require laravel/pint:* --dev --with-all-dependencies - - name: Execute Laravel Pint run: vendor/bin/pint --test @@ -228,7 +183,7 @@ jobs: fail-fast: true max-parallel: 10 matrix: - php: ["7.4", "8.0", "8.1"] + php: ["8.0", "8.1", "8.2"] steps: - name: Set up PHP ${{ matrix.php }} diff --git a/composer.json b/composer.json index 52a6bf71..d0c27ad2 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ ], "homepage": "https://github.com/auth0/laravel-auth0", "require": { - "php": "^7.4 || ^8.0", + "php": "^8.0", "ext-filter": "*", "ext-json": "*", "ext-mbstring": "*", @@ -42,15 +42,17 @@ }, "require-dev": { "laravel/laravel": "^8.4.4 || ^9.0", + "laravel/pint": "^1.2", "nunomaduro/larastan": "^1.0", "nyholm/psr7": "^1.4", "orchestra/testbench": "6.25.0", "pestphp/pest": "^1.21", "pestphp/pest-plugin-laravel": "^1.2", "phpstan/phpstan": "^1.7", - "phpstan/phpstan-strict-rules": "^1.3", + "phpstan/phpstan-strict-rules": "1.4.3", "phpunit/phpunit": "^9.5", "rector/rector": "^0.13.6", + "symplify/easy-coding-standard": "^11.1", "wikimedia/composer-merge-plugin": "^2.0" }, "autoload": { diff --git a/ecs.php b/ecs.php new file mode 100644 index 00000000..140eed84 --- /dev/null +++ b/ecs.php @@ -0,0 +1,89 @@ +sets([SetList::PSR_12, SetList::SYMPLIFY, SetList::COMMON, SetList::CLEAN_CODE]); + + $ecsConfig->paths([ + __DIR__ . '/bin', + __DIR__ . '/src', + __DIR__ . '/packages', + __DIR__ . '/packages-tests', + __DIR__ . '/rules', + __DIR__ . '/rules-tests', + __DIR__ . '/tests', + __DIR__ . '/utils', + __DIR__ . '/config', + __DIR__ . '/ecs.php', + __DIR__ . '/easy-ci.php', + __DIR__ . '/rector.php', + __DIR__ . '/scoper.php', + __DIR__ . '/build/build-preload.php', + ]); + + $ecsConfig->ruleWithConfiguration(NoSuperfluousPhpdocTagsFixer::class, [ + 'allow_mixed' => true, + ]); + + $ecsConfig->ruleWithConfiguration(GeneralPhpdocAnnotationRemoveFixer::class, [ + 'annotations' => [ + 'throw', + 'throws', + 'author', + 'authors', + 'package', + 'group', + 'required', + 'phpstan-ignore-line', + 'phpstan-ignore-next-line', + ], + ]); + + $ecsConfig->rule(StaticLambdaFixer::class); + + $ecsConfig->skip([ + '*/Source/*', + '*/Fixture/*', + '*/Expected/*', + + // buggy - @todo fix on Symplify master + DocBlockLineLengthFixer::class, + + PhpdocTypesFixer::class => [ + // double to Double false positive + __DIR__ . '/rules/Php74/Rector/Double/RealToFloatTypeCastRector.php', + // skip for enum types + __DIR__ . '/rules/Php70/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php', + ], + + // breaking and handled better by Rector PHPUnit code quality set, removed in symplify dev-main + PhpUnitStrictFixer::class, + + // skip add space on &$variable + FunctionTypehintSpaceFixer::class => [ + __DIR__ . '/src/PhpParser/Printer/BetterStandardPrinter.php', + __DIR__ . '/src/DependencyInjection/Loader/Configurator/RectorServiceConfigurator.php', + __DIR__ . '/rules/Php70/EregToPcreTransformer.php', + ], + + AssignmentInConditionSniff::class . '.FoundInWhileCondition', + + // null on purpose as no change + PhpdocNoEmptyReturnFixer::class => [ + __DIR__ . '/rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php', + ], + ]); +}; diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 048f34c2..550f8aad 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -11,21 +11,9 @@ parameters: - tests/constants.php ignoreErrors: - - '#Function (app|auth|event|redirect) not found.#' - - '#Constructor in (.*) has parameter (.*) with default value.#' - - '#Constructor in (.*) has parameter (.*) with null as default value.#' - - '#Method (.*) has parameter (.*) with a nullable type declaration.#' - - '#Method (.*) has parameter (.*) with null as default value.#' - - '#Method (.*) has a nullable return type declaration.#' - - '#Language construct isset\(\) should not be used.#' - '#Method (.*) has parameter (.*) with no value type specified in iterable type array.#' - - '#not allowed to extend#' - '#Cannot call method (.*) on mixed#' - '#no value type specified in iterable type array.#' - - '#is not final, but since the containing class is abstract, it should be.#' - - '#Class "Auth0\\Login\\Exception\\(.*)" is not allowed to extend "Exception".#' - - '#Class "Auth0\\Laravel\\Exception\\(.*)" is not allowed to extend "Exception".#' - '#Call to an undefined method Illuminate\\(.*).#' - - '#\$hash is never read, only written.#' reportUnmatchedIgnoredErrors: false diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 531c589e..889b9ba4 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -30,10 +30,10 @@ public function __construct( /** * @inheritdoc */ - public function login( - \Illuminate\Contracts\Auth\Authenticatable $user - ): self { - $this->getState()->setUser($user); + public function login(\Illuminate\Contracts\Auth\Authenticatable $user): self + { + $this->getState() + ->setUser($user); return $this; } @@ -42,7 +42,8 @@ public function login( */ public function logout(): self { - $this->getState()->setUser(null); + $this->getState() + ->setUser(null); app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); return $this; } @@ -68,7 +69,8 @@ public function guest(): bool */ public function user(): ?\Illuminate\Contracts\Auth\Authenticatable { - return $this->getState()->getUser() ?? $this->getUserFromToken() ?? $this->getUserFromSession() ?? null; + return $this->getState() + ->getUser() ?? $this->getUserFromToken() ?? $this->getUserFromSession() ?? null; } /** @@ -79,7 +81,8 @@ public function id() $response = null; if ($this->user() !== null) { - $id = $this->user()->getAuthIdentifier(); + $id = $this->user() + ->getAuthIdentifier(); if (is_string($id) || is_int($id)) { $response = $id; @@ -94,19 +97,18 @@ public function id() * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ - public function validate( - array $credentials = [] - ): bool { + public function validate(array $credentials = []): bool + { return false; } /** * @inheritdoc */ - public function setUser( - \Illuminate\Contracts\Auth\Authenticatable $user - ): self { - $user = $this->getState()->setUser($user); + public function setUser(\Illuminate\Contracts\Auth\Authenticatable $user): self + { + $user = $this->getState() + ->setUser($user); return $this; } @@ -115,19 +117,18 @@ public function setUser( */ public function hasUser(): bool { - return ! is_null($this->getState()->getUser()); + return $this->getState()->getUser() !== null; } /** * @inheritdoc */ - public function hasScope( - string $scope - ): bool { + public function hasScope(string $scope): bool + { $state = $this->getState(); return in_array($scope, $state->getAccessTokenScope() ?? [], true); } - + /** * Always returns false to keep third-party apps happy */ @@ -151,14 +152,25 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable try { // Attempt to decode the bearer token. - $decoded = app(\Auth0\Laravel\Auth0::class)->getSdk()->decode($token, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_TOKEN)->toArray(); + $decoded = app(\Auth0\Laravel\Auth0::class)->getSdk()->decode( + $token, + null, + null, + null, + null, + null, + null, + \Auth0\SDK\Token::TYPE_TOKEN + )->toArray(); } catch (\Auth0\SDK\Exception\InvalidTokenException $invalidToken) { // Invalid bearer token. return null; } // Query the UserProvider to retrieve tue user for the token. - $user = $this->getProvider()->getRepository()->fromAccessToken($decoded); + $user = $this->getProvider() + ->getRepository() + ->fromAccessToken($decoded); // Was a user retrieved successfully? if ($user !== null) { @@ -195,7 +207,9 @@ private function getUserFromSession(): ?\Illuminate\Contracts\Auth\Authenticatab } // Query the UserProvider to retrieve tue user for the session. - $user = $this->getProvider()->getRepository()->fromSession($session->user); + $user = $this->getProvider() + ->getRepository() + ->fromSession($session->user); // Was a user retrieved successfully? if ($user !== null) { diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php index 3bb74a20..c53c3975 100644 --- a/src/Auth/User/Provider.php +++ b/src/Auth/User/Provider.php @@ -14,9 +14,8 @@ final class Provider implements \Auth0\Laravel\Contract\Auth\User\Provider, \Ill /** * @inheritdoc */ - public function __construct( - \Auth0\Laravel\Contract\Auth\User\Repository $repository - ) { + public function __construct(\Auth0\Laravel\Contract\Auth\User\Repository $repository) + { $this->repository = $repository; } @@ -25,9 +24,8 @@ public function __construct( * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ - public function retrieveById( - $identifier - ): ?\Illuminate\Contracts\Auth\Authenticatable { + public function retrieveById($identifier): ?\Illuminate\Contracts\Auth\Authenticatable + { return null; } @@ -36,10 +34,8 @@ public function retrieveById( * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ - public function retrieveByToken( - $identifier, - $token - ): ?\Illuminate\Contracts\Auth\Authenticatable { + public function retrieveByToken($identifier, $token): ?\Illuminate\Contracts\Auth\Authenticatable + { return null; } @@ -48,9 +44,8 @@ public function retrieveByToken( * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ - public function retrieveByCredentials( - array $credentials - ): ?\Illuminate\Contracts\Auth\Authenticatable { + public function retrieveByCredentials(array $credentials): ?\Illuminate\Contracts\Auth\Authenticatable + { return null; } @@ -71,10 +66,8 @@ public function validateCredentials( * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ - public function updateRememberToken( - \Illuminate\Contracts\Auth\Authenticatable $user, - $token - ): void { + public function updateRememberToken(\Illuminate\Contracts\Auth\Authenticatable $user, $token): void + { } /** diff --git a/src/Auth/User/Repository.php b/src/Auth/User/Repository.php index 7e7295a4..1777cf74 100644 --- a/src/Auth/User/Repository.php +++ b/src/Auth/User/Repository.php @@ -9,22 +9,16 @@ final class Repository implements \Auth0\Laravel\Contract\Auth\User\Repository /** * @inheritdoc */ - public function fromSession( - array $user - ): ?\Illuminate\Contracts\Auth\Authenticatable { - return new \Auth0\Laravel\Model\Stateful\User( - $user - ); + public function fromSession(array $user): ?\Illuminate\Contracts\Auth\Authenticatable + { + return new \Auth0\Laravel\Model\Stateful\User($user); } /** * @inheritdoc */ - public function fromAccessToken( - array $user - ): ?\Illuminate\Contracts\Auth\Authenticatable { - return new \Auth0\Laravel\Model\Stateless\User( - $user - ); + public function fromAccessToken(array $user): ?\Illuminate\Contracts\Auth\Authenticatable + { + return new \Auth0\Laravel\Model\Stateless\User($user); } } diff --git a/src/Auth0.php b/src/Auth0.php index 09217ec8..1deb431c 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -4,6 +4,9 @@ namespace Auth0\Laravel; +use Auth0\Laravel\Cache\LaravelCachePool; +use Auth0\Laravel\Store\LaravelSession; + /** * Service that provides access to the Auth0 SDK. */ @@ -40,9 +43,8 @@ public function getSdk(): \Auth0\SDK\Contract\Auth0Interface /** * @inheritdoc */ - public function setSdk( - \Auth0\SDK\Contract\Auth0Interface $sdk - ): self { + public function setSdk(\Auth0\SDK\Contract\Auth0Interface $sdk): self + { $this->sdk = $sdk; $this->setSdkTelemetry(); return $this; @@ -54,7 +56,43 @@ public function setSdk( public function getConfiguration(): \Auth0\SDK\Configuration\SdkConfiguration { if ($this->configuration === null) { - $this->configuration = new \Auth0\SDK\Configuration\SdkConfiguration(app()->make('config')->get('auth0')); + $config = app() + ->make('config') + ->get('auth0'); + + if (! isset($config['tokenCache']) || ! isset($config['managementTokenCache'])) { + $cache = new LaravelCachePool(); + + if (! isset($config['tokenCache'])) { + $config['tokenCache'] = $cache; + } + + if (! isset($config['managementTokenCache'])) { + $config['managementTokenCache'] = $cache; + } + } + + $configuration = new \Auth0\SDK\Configuration\SdkConfiguration($config); + + // If no sessionStorage is defined, use an LaravelSession store instance. + if (! isset($config['sessionStorage'])) { + $configuration->setSessionStorage( + new LaravelSession($configuration, $configuration->getSessionStorageId()) + ); + } + + // If no transientStorage is defined, use an LaravelSession store instance. + if (! isset($config['transientStorage'])) { + $configuration->setTransientStorage( + new LaravelSession($configuration, $configuration->getSessionStorageId()) + ); + } + + // Give apps an opportunity to mutate the configuration before applying it. + $event = new \Auth0\Laravel\Event\Configuration\Built($configuration); + event($event); + + $this->configuration = $event->getConfiguration(); } return $this->configuration; @@ -63,9 +101,8 @@ public function getConfiguration(): \Auth0\SDK\Configuration\SdkConfiguration /** * @inheritdoc */ - public function setConfiguration( - \Auth0\SDK\Configuration\SdkConfiguration $configuration - ): self { + public function setConfiguration(\Auth0\SDK\Configuration\SdkConfiguration $configuration): self + { $this->configuration = $configuration; return $this; } diff --git a/src/Cache/LaravelCacheItem.php b/src/Cache/LaravelCacheItem.php new file mode 100644 index 00000000..258f2def --- /dev/null +++ b/src/Cache/LaravelCacheItem.php @@ -0,0 +1,92 @@ +key = $key; + $this->value = $value; + $this->is_hit = $is_hit; + } + + public function getKey(): string + { + return $this->key; + } + + public function get(): mixed + { + return $this->value; + } + + public function isHit(): bool + { + return $this->is_hit; + } + + public function set(mixed $value): static + { + $this->value = $value; + $this->is_hit = true; + return $this; + } + + public function expiresAt(mixed $expiration): static + { + if ($expiration instanceof DateTimeInterface) { + $this->expires = $expiration->getTimestamp(); + return $this; + } + + $this->expires = $expiration; + return $this; + } + + /** + * @param DateInterval|int|null $time + */ + public function expiresAfter(mixed $time): static + { + if ($time === null) { + $this->expires = null; + return $this; + } + + if ($time instanceof DateInterval) { + $dateTime = new DateTime(); + $dateTime->add($time); + $this->expires = $dateTime->getTimestamp(); + return $this; + } + + $this->expires = time() + $time; + return $this; + } + + public function expirationTimestamp(): ?int + { + return $this->expires; + } + + public static function miss(string $key): self + { + return new self($key, null, false); + } +} diff --git a/src/Cache/LaravelCachePool.php b/src/Cache/LaravelCachePool.php new file mode 100644 index 00000000..d3d0dc26 --- /dev/null +++ b/src/Cache/LaravelCachePool.php @@ -0,0 +1,192 @@ + + */ + private array $deferred = []; + + public function __construct() + { + $this->manager = app() + ->make(\Illuminate\Cache\CacheManager::class); + } + + public function getItem(string $key): CacheItemInterface + { + $value = $this->getStore() + ->get($key); + + if ($value === false) { + return LaravelCacheItem::miss($key); + } + + return $this->createItem($key, $value); + } + + /** + * @param string[] $keys + * + * @return CacheItemInterface[] + */ + public function getItems(array $keys = []): iterable + { + if ($keys === []) { + return []; + } + + $results = $this->getStore() + ->many($keys); + $items = []; + + foreach ($results as $key => $value) { + $key = (string) $key; + $items[$key] = $this->createItem($key, $value); + } + + return $items; + } + + /** + * @param string $key The key for which to return the corresponding Cache Item. + */ + public function hasItem(mixed $key): bool + { + return $this->getItem($key) + ->isHit(); + } + + public function clear(): bool + { + $this->deferred = []; + return $this->getStore() + ->flush(); + } + + /** + * @param string $key The key for which to return the corresponding Cache Item. + */ + public function deleteItem(mixed $key): bool + { + return $this->getStore() + ->forget($key); + } + + public function deleteItems(array $keys): bool + { + $deleted = true; + + foreach ($keys as $key) { + if (! $this->deleteItem($key)) { + $deleted = false; + } + } + + return $deleted; + } + + public function save(CacheItemInterface $item): bool + { + if (! $item instanceof LaravelCacheItem) { + return false; + } + + $value = serialize($item->get()); + $key = $item->getKey(); + $expires = $item->expirationTimestamp(); + $ttl = 0; + + if ($expires !== null) { + if ($expires <= time()) { + return $this->deleteItem($key); + } + + $ttl = $expires - time(); + } + + return $this->getStore() + ->put($key, $value, $ttl); + } + + public function saveDeferred(CacheItemInterface $item): bool + { + if (! $item instanceof LaravelCacheItem) { + return false; + } + + $this->deferred[$item->getKey()] = [ + 'item' => $item, + 'expiration' => $item->expirationTimestamp(), + ]; + + return true; + } + + public function commit(): bool + { + $success = true; + + foreach (array_keys($this->deferred) as $singleDeferred) { + $item = $this->getDeferred((string) $singleDeferred); + + if ($item !== null && ! $this->save($item)) { + $success = false; + } + } + + $this->deferred = []; + return $success; + } + + private function getStore(): \Illuminate\Contracts\Cache\Store + { + return $this->manager->getStore(); + } + + private function createItem(string $key, mixed $value): CacheItemInterface + { + if (! is_string($value)) { + return LaravelCacheItem::miss($key); + } + + $value = unserialize($value); + + if ($value === false || $value !== 'b:0;') { + return LaravelCacheItem::miss($key); + } + + return new LaravelCacheItem($key, $value, true); + } + + private function getDeferred(string $key): ?CacheItemInterface + { + if (! isset($this->deferred[$key])) { + return null; + } + + $deferred = $this->deferred[$key]; + $item = clone $deferred['item']; + $expires = $deferred['expiration']; + + if ($expires !== null && $expires <= time()) { + unset($this->deferred[$key]); + return null; + } + + return $item; + } +} diff --git a/src/Configuration.php b/src/Configuration.php index 33484996..876b208f 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -12,10 +12,8 @@ final class Configuration implements \Auth0\Laravel\Contract\Configuration /** * @inheritdoc */ - public static function stringToArrayOrNull( - ?string $config, - string $delimiter = ' ' - ): ?array { + public static function stringToArrayOrNull(?string $config, string $delimiter = ' '): ?array + { if (is_string($config) && strlen($config) >= 1 && strlen($delimiter) >= 1) { $response = explode($delimiter, $config); @@ -31,10 +29,8 @@ public static function stringToArrayOrNull( /** * @inheritdoc */ - public static function stringToBoolOrNull( - ?string $config, - ?bool $default = null - ): ?bool { + public static function stringToBoolOrNull(?string $config, ?bool $default = null): ?bool + { if (is_string($config) && strlen($config) >= 1) { $config = strtolower(trim($config)); diff --git a/src/Contract/Auth/Guard.php b/src/Contract/Auth/Guard.php index 55e688fb..1b4280c3 100644 --- a/src/Contract/Auth/Guard.php +++ b/src/Contract/Auth/Guard.php @@ -8,9 +8,6 @@ interface Guard { /** * Create a new authentication guard. - * - * @param \Illuminate\Contracts\Auth\UserProvider $provider - * @param \Illuminate\Http\Request $request */ public function __construct( \Illuminate\Contracts\Auth\UserProvider $provider, @@ -19,12 +16,8 @@ public function __construct( /** * Set the current user. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user */ - public function login( - \Illuminate\Contracts\Auth\Authenticatable $user - ): self; + public function login(\Illuminate\Contracts\Auth\Authenticatable $user): self; /** * Clear the current user. diff --git a/src/Contract/Auth/User/Provider.php b/src/Contract/Auth/User/Provider.php index 0fc8a772..5f5966c8 100644 --- a/src/Contract/Auth/User/Provider.php +++ b/src/Contract/Auth/User/Provider.php @@ -11,9 +11,7 @@ interface Provider * * @param \Auth0\Laravel\Auth\User\Repository $repository A repository instance. */ - public function __construct( - \Auth0\Laravel\Auth\User\Repository $repository - ); + public function __construct(\Auth0\Laravel\Auth\User\Repository $repository); /** * Returns the assigned user provider. diff --git a/src/Contract/Auth/User/Repository.php b/src/Contract/Auth/User/Repository.php index 9997375e..9224c85a 100644 --- a/src/Contract/Auth/User/Repository.php +++ b/src/Contract/Auth/User/Repository.php @@ -11,16 +11,12 @@ interface Repository * * @param array $user An array containing the raw Auth0 user data. */ - public function fromSession( - array $user - ): ?\Illuminate\Contracts\Auth\Authenticatable; + public function fromSession(array $user): ?\Illuminate\Contracts\Auth\Authenticatable; /** * Generate a \Auth0\Laravel\Model\Stateful\User instance from a parsed Access Token. * * @param array $user An array containing the raw Auth0 user data. */ - public function fromAccessToken( - array $user - ): ?\Illuminate\Contracts\Auth\Authenticatable; + public function fromAccessToken(array $user): ?\Illuminate\Contracts\Auth\Authenticatable; } diff --git a/src/Contract/Auth0.php b/src/Contract/Auth0.php index 619958bd..0129be4d 100644 --- a/src/Contract/Auth0.php +++ b/src/Contract/Auth0.php @@ -14,9 +14,7 @@ public function getSdk(): \Auth0\SDK\Contract\Auth0Interface; /** * Create/return instance of the Auth0-PHP SDK. */ - public function setSdk( - \Auth0\SDK\Contract\Auth0Interface $sdk - ): self; + public function setSdk(\Auth0\SDK\Contract\Auth0Interface $sdk): self; /** * Create/return instance of the Auth0-PHP SdkConfiguration. @@ -26,9 +24,7 @@ public function getConfiguration(): \Auth0\SDK\Configuration\SdkConfiguration; /** * Assign the Auth0-PHP SdkConfiguration. */ - public function setConfiguration( - \Auth0\SDK\Configuration\SdkConfiguration $configuration - ): self; + public function setConfiguration(\Auth0\SDK\Configuration\SdkConfiguration $configuration): self; /** * Create/create a request state instance, a storage singleton containing authenticated user data. diff --git a/src/Contract/Configuration.php b/src/Contract/Configuration.php index 908c4c66..38954dc0 100644 --- a/src/Contract/Configuration.php +++ b/src/Contract/Configuration.php @@ -12,10 +12,7 @@ interface Configuration * @param string|null $config The string contents to convert, i.e. 'one two three'. * @param string $delimiter The string delimiter to split the string contents with; defaults to space. */ - public static function stringToArrayOrNull( - ?string $config, - string $delimiter = ' ' - ): ?array; + public static function stringToArrayOrNull(?string $config, string $delimiter = ' '): ?array; /** * Converts a truthy string representation into a boolean. @@ -23,8 +20,5 @@ public static function stringToArrayOrNull( * @param string|null $config The string contents to convert, i.e. 'true' * @param bool|null $default The default boolean value to return if a valid string wasn't provided. */ - public static function stringToBoolOrNull( - ?string $config, - ?bool $default = null - ): ?bool; + public static function stringToBoolOrNull(?string $config, ?bool $default = null): ?bool; } diff --git a/src/Contract/Event/Configuration/Built.php b/src/Contract/Event/Configuration/Built.php new file mode 100644 index 00000000..6809ab54 --- /dev/null +++ b/src/Contract/Event/Configuration/Built.php @@ -0,0 +1,29 @@ +configuration = $configuration; + } + + /** + * @inheritdoc + */ + public function setConfiguration(SdkConfiguration $configuration): self + { + $this->configuration = $configuration; + return $this; + } + + /** + * @inheritdoc + */ + public function getConfiguration(): SdkConfiguration + { + return $this->configuration; + } +} diff --git a/src/Event/Stateful/AuthenticationFailed.php b/src/Event/Stateful/AuthenticationFailed.php index d8c93f93..93c85dfa 100644 --- a/src/Event/Stateful/AuthenticationFailed.php +++ b/src/Event/Stateful/AuthenticationFailed.php @@ -19,10 +19,8 @@ final class AuthenticationFailed extends \Auth0\Laravel\Event\Auth0Event impleme /** * @inheritdoc */ - public function __construct( - \Throwable $exception, - bool $throwException = true - ) { + public function __construct(\Throwable $exception, bool $throwException = true) + { $this->exception = $exception; $this->throwException = $throwException; } @@ -30,9 +28,8 @@ public function __construct( /** * @inheritdoc */ - public function setException( - \Throwable $exception - ): self { + public function setException(\Throwable $exception): self + { $this->exception = $exception; $this->mutated = true; return $this; @@ -49,9 +46,8 @@ public function getException(): \Throwable /** * @inheritdoc */ - public function setThrowException( - bool $throwException - ): self { + public function setThrowException(bool $throwException): self + { $this->throwException = $throwException; return $this; } diff --git a/src/Event/Stateful/AuthenticationSucceeded.php b/src/Event/Stateful/AuthenticationSucceeded.php index 8cad32aa..21db6fc2 100644 --- a/src/Event/Stateful/AuthenticationSucceeded.php +++ b/src/Event/Stateful/AuthenticationSucceeded.php @@ -14,18 +14,16 @@ final class AuthenticationSucceeded extends \Auth0\Laravel\Event\Auth0Event impl /** * @inheritdoc */ - public function __construct( - \Illuminate\Contracts\Auth\Authenticatable $user - ) { + public function __construct(\Illuminate\Contracts\Auth\Authenticatable $user) + { $this->user = $user; } /** * @inheritdoc */ - public function setUser( - \Illuminate\Contracts\Auth\Authenticatable $user - ): self { + public function setUser(\Illuminate\Contracts\Auth\Authenticatable $user): self + { $this->user = $user; $this->mutated = true; return $this; diff --git a/src/Exception/Stateful/CallbackException.php b/src/Exception/Stateful/CallbackException.php index 2717a482..00d882e4 100644 --- a/src/Exception/Stateful/CallbackException.php +++ b/src/Exception/Stateful/CallbackException.php @@ -14,10 +14,8 @@ final class CallbackException extends \Exception implements \Auth0\SDK\Exception /** * @inheritdoc */ - public static function apiException( - string $error, - string $errorDescription - ): self { + public static function apiException(string $error, string $errorDescription): self + { return new self(sprintf(self::MSG_API_RESPONSE, $error, $errorDescription)); } } diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index 5c9a4af5..b942634e 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -9,9 +9,8 @@ final class Callback implements \Auth0\Laravel\Contract\Http\Controller\Stateful /** * @inheritdoc */ - public function __invoke( - \Illuminate\Http\Request $request - ): \Illuminate\Http\RedirectResponse { + public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse + { // Check if the user already has a session: if (auth()->guard('auth0')->check()) { // They do; redirect to homepage. @@ -20,7 +19,11 @@ public function __invoke( try { if ($request->query('state') !== null && $request->query('code') !== null) { - app(\Auth0\Laravel\Auth0::class)->getSdk()->exchange(null, $request->query('code'), $request->query('state')); + app(\Auth0\Laravel\Auth0::class)->getSdk()->exchange( + null, + $request->query('code'), + $request->query('state') + ); } } catch (\Throwable $exception) { app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); @@ -59,7 +62,9 @@ public function __invoke( } // Ensure we have a valid user: - $user = auth()->guard('auth0')->user(); + $user = auth() + ->guard('auth0') + ->user(); if ($user !== null) { // Throw hookable event to allow custom application logic for successful logins: @@ -67,7 +72,9 @@ public function __invoke( event($event); // Apply any mutations to the user object: - auth()->guard('auth0')->setUser($event->getUser()); + auth() + ->guard('auth0') + ->setUser($event->getUser()); } return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); diff --git a/src/Http/Controller/Stateful/Login.php b/src/Http/Controller/Stateful/Login.php index a73bd8dc..366d95e2 100644 --- a/src/Http/Controller/Stateful/Login.php +++ b/src/Http/Controller/Stateful/Login.php @@ -11,9 +11,8 @@ final class Login implements \Auth0\Laravel\Contract\Http\Controller\Stateful\Lo * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ - public function __invoke( - \Illuminate\Http\Request $request - ): \Illuminate\Http\RedirectResponse { + public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse + { if (auth()->guard('auth0')->check()) { return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); } diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index 60ab5dbe..624e1552 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -9,16 +9,22 @@ final class Logout implements \Auth0\Laravel\Contract\Http\Controller\Stateful\L /** * @inheritdoc */ - public function __invoke( - \Illuminate\Http\Request $request - ): \Illuminate\Http\RedirectResponse { + public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse + { if (auth()->guard('auth0')->check()) { - auth()->guard('auth0')->logout(); + auth()->guard('auth0') + ->logout(); - $request->session()->invalidate(); - $request->session()->regenerateToken(); + $request->session() + ->invalidate(); + $request->session() + ->regenerateToken(); - return redirect()->away(app(\Auth0\Laravel\Auth0::class)->getSdk()->authentication()->getLogoutLink(url(http://github.com/app()->make('config')->get('auth0.routes.home', '/')))); + return redirect()->away( + app(\Auth0\Laravel\Auth0::class)->getSdk()->authentication()->getLogoutLink(url( + app()->make('config')->get('auth0.routes.home', '/') + )) + ); } return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); diff --git a/src/Http/Middleware/Stateful/Authenticate.php b/src/Http/Middleware/Stateful/Authenticate.php index 00a4e932..aaef10a5 100644 --- a/src/Http/Middleware/Stateful/Authenticate.php +++ b/src/Http/Middleware/Stateful/Authenticate.php @@ -8,22 +8,21 @@ * This middleware will configure the authenticated user for the session using a * previously established Auth0-PHP SDK session. If a session is not available, * a redirect will be issued to a route named 'login'. - * - * @package Auth0\Laravel\Http\Middleware */ final class Authenticate implements \Auth0\Laravel\Contract\Http\Middleware\Stateful\Authenticate { /** * @inheritdoc */ - public function handle( - \Illuminate\Http\Request $request, - \Closure $next - ) { - $user = auth()->guard('auth0')->user(); + public function handle(\Illuminate\Http\Request $request, \Closure $next) + { + $user = auth() + ->guard('auth0') + ->user(); if ($user !== null && $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { - auth()->guard('auth0')->login($user); + auth()->guard('auth0') + ->login($user); return $next($request); } diff --git a/src/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Http/Middleware/Stateful/AuthenticateOptional.php index d7e93ae0..cdecea66 100644 --- a/src/Http/Middleware/Stateful/AuthenticateOptional.php +++ b/src/Http/Middleware/Stateful/AuthenticateOptional.php @@ -8,22 +8,21 @@ * This middleware will configure the authenticated user for the session using a * previously established Auth0-PHP SDK session. If a session is not available, * the authenticated user will be set as null. - * - * @package Auth0\Laravel\Http\Middleware */ final class AuthenticateOptional implements \Auth0\Laravel\Contract\Http\Middleware\Stateful\AuthenticateOptional { /** * @inheritdoc */ - public function handle( - \Illuminate\Http\Request $request, - \Closure $next - ) { - $user = auth()->guard('auth0')->user(); + public function handle(\Illuminate\Http\Request $request, \Closure $next) + { + $user = auth() + ->guard('auth0') + ->user(); if ($user !== null && $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { - auth()->guard('auth0')->login($user); + auth()->guard('auth0') + ->login($user); } return $next($request); diff --git a/src/Http/Middleware/Stateless/Authorize.php b/src/Http/Middleware/Stateless/Authorize.php index eca524d9..5a3102ba 100644 --- a/src/Http/Middleware/Stateless/Authorize.php +++ b/src/Http/Middleware/Stateless/Authorize.php @@ -7,27 +7,25 @@ /** * This middleware will configure the authenticated user using an available access token. * If a token is not available, it will raise an exception. - * - * @package Auth0\Laravel\Http\Middleware */ final class Authorize implements \Auth0\Laravel\Contract\Http\Middleware\Stateless\Authorize { /** * @inheritdoc */ - public function handle( - \Illuminate\Http\Request $request, - \Closure $next, - string $scope = '' - ) { - $user = auth()->guard('auth0')->user(); + public function handle(\Illuminate\Http\Request $request, \Closure $next, string $scope = '') + { + $user = auth() + ->guard('auth0') + ->user(); if ($user !== null && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { if (strlen($scope) >= 1 && auth()->guard('auth0')->hasScope($scope) === false) { return abort(403, 'Unauthorized'); } - auth()->login($user); + auth() + ->login($user); return $next($request); } diff --git a/src/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Http/Middleware/Stateless/AuthorizeOptional.php index 1ae72a50..43921c71 100644 --- a/src/Http/Middleware/Stateless/AuthorizeOptional.php +++ b/src/Http/Middleware/Stateless/AuthorizeOptional.php @@ -6,22 +6,21 @@ /** * This middleware will configure the authenticated user using an available access token. - * - * @package Auth0\Laravel\Http\Middleware */ final class AuthorizeOptional implements \Auth0\Laravel\Contract\Http\Middleware\Stateless\AuthorizeOptional { /** * @inheritdoc */ - public function handle( - \Illuminate\Http\Request $request, - \Closure $next - ) { - $user = auth()->guard('auth0')->user(); + public function handle(\Illuminate\Http\Request $request, \Closure $next) + { + $user = auth() + ->guard('auth0') + ->user(); if ($user !== null && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { - auth()->guard('auth0')->login($user); + auth()->guard('auth0') + ->login($user); } return $next($request); diff --git a/src/Model/User.php b/src/Model/User.php index 7e186a3e..afc9fea4 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -14,37 +14,32 @@ abstract class User implements \Illuminate\Contracts\Auth\Authenticatable, \Auth /** * @inheritdoc */ - public function __construct( - array $attributes = [] - ) { + public function __construct(array $attributes = []) + { $this->fill($attributes); } /** * @inheritdoc */ - public function __get( - string $key - ) { + public function __get(string $key) + { return $this->getAttribute($key); } /** * @inheritdoc */ - public function __set( - string $key, - $value - ): void { + public function __set(string $key, $value): void + { $this->setAttribute($key, $value); } /** * @inheritdoc */ - public function fill( - array $attributes - ): self { + public function fill(array $attributes): self + { foreach ($attributes as $key => $value) { $this->setAttribute($key, $value); } @@ -55,10 +50,8 @@ public function fill( /** * @inheritdoc */ - public function setAttribute( - string $key, - $value - ): self { + public function setAttribute(string $key, $value): self + { $this->attributes[$key] = $value; return $this; } @@ -66,10 +59,8 @@ public function setAttribute( /** * @inheritdoc */ - public function getAttribute( - string $key, - $default = null - ) { + public function getAttribute(string $key, $default = null) + { return $this->attributes[$key] ?? $default; } @@ -110,9 +101,8 @@ public function getRememberToken(): string * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ - public function setRememberToken( - $value - ): void { + public function setRememberToken($value): void + { } /** diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 80759109..fa65d7ec 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -9,9 +9,8 @@ final class ServiceProvider extends \Spatie\LaravelPackageTools\PackageServicePr /** * @inheritdoc */ - public function configurePackage( - \Spatie\LaravelPackageTools\Package $package - ): void { + public function configurePackage(\Spatie\LaravelPackageTools\Package $package): void + { $package ->name('auth0') ->hasConfigFile(); @@ -24,11 +23,17 @@ public function registeringPackage(): void { app()->singleton(Auth0::class, static fn (): \Auth0\Laravel\Auth0 => new Auth0()); - app()->singleton('auth0', static fn (): \Auth0\Laravel\Auth0 => app()->make(Auth0::class)); + app() + ->singleton('auth0', static fn (): \Auth0\Laravel\Auth0 => app()->make(Auth0::class)); - app()->singleton(StateInstance::class, static fn (): \Auth0\Laravel\StateInstance => new StateInstance()); + app() + ->singleton(StateInstance::class, static fn (): \Auth0\Laravel\StateInstance => new StateInstance()); - app()->singleton(\Auth0\Laravel\Auth\User\Repository::class, static fn (): \Auth0\Laravel\Auth\User\Repository => new \Auth0\Laravel\Auth\User\Repository()); + app() + ->singleton( + \Auth0\Laravel\Auth\User\Repository::class, + static fn (): \Auth0\Laravel\Auth\User\Repository => new \Auth0\Laravel\Auth\User\Repository() + ); } /** @@ -36,14 +41,39 @@ public function registeringPackage(): void */ public function bootingPackage(): void { - auth()->provider('auth0', static fn ($app, array $config): \Auth0\Laravel\Auth\User\Provider => new \Auth0\Laravel\Auth\User\Provider(app()->make($config['repository']))); + auth()->provider( + 'auth0', + static fn ($app, array $config): \Auth0\Laravel\Auth\User\Provider => new \Auth0\Laravel\Auth\User\Provider( + app()->make( + $config['repository'] + ) + ) + ); - auth()->extend('auth0', static fn ($app, $name, array $config): \Auth0\Laravel\Auth\Guard => new \Auth0\Laravel\Auth\Guard(auth()->createUserProvider($config['provider']), $app->make('request'))); + auth() + ->extend( + 'auth0', + static fn ($app, $name, array $config): \Auth0\Laravel\Auth\Guard => new \Auth0\Laravel\Auth\Guard( + auth()->createUserProvider( + $config['provider'] + ), + $app->make( + 'request' + ) + ) + ); - $router = app()->make(\Illuminate\Routing\Router::class); + $router = app() + ->make(\Illuminate\Routing\Router::class); $router->aliasMiddleware('auth0.authenticate', \Auth0\Laravel\Http\Middleware\Stateful\Authenticate::class); - $router->aliasMiddleware('auth0.authenticate.optional', \Auth0\Laravel\Http\Middleware\Stateful\AuthenticateOptional::class); + $router->aliasMiddleware( + 'auth0.authenticate.optional', + \Auth0\Laravel\Http\Middleware\Stateful\AuthenticateOptional::class + ); $router->aliasMiddleware('auth0.authorize', \Auth0\Laravel\Http\Middleware\Stateless\Authorize::class); - $router->aliasMiddleware('auth0.authorize.optional', \Auth0\Laravel\Http\Middleware\Stateless\AuthorizeOptional::class); + $router->aliasMiddleware( + 'auth0.authorize.optional', + \Auth0\Laravel\Http\Middleware\Stateless\AuthorizeOptional::class + ); } } diff --git a/src/StateInstance.php b/src/StateInstance.php index 3adfab89..6eb6614a 100644 --- a/src/StateInstance.php +++ b/src/StateInstance.php @@ -67,9 +67,8 @@ public function getUser(): ?\Illuminate\Contracts\Auth\Authenticatable /** * @inheritdoc */ - public function setUser( - ?\Illuminate\Contracts\Auth\Authenticatable $user - ): self { + public function setUser(?\Illuminate\Contracts\Auth\Authenticatable $user): self + { $this->user = $user; return $this; } @@ -85,9 +84,8 @@ public function getDecoded(): ?array /** * @inheritdoc */ - public function setDecoded( - ?array $data - ): self { + public function setDecoded(?array $data): self + { $this->decoded = $data; return $this; } @@ -103,9 +101,8 @@ public function getIdToken(): ?string /** * @inheritdoc */ - public function setIdToken( - ?string $idToken - ): self { + public function setIdToken(?string $idToken): self + { $this->idToken = $idToken; return $this; } @@ -121,9 +118,8 @@ public function getAccessToken(): ?string /** * @inheritdoc */ - public function setAccessToken( - ?string $accessToken - ): self { + public function setAccessToken(?string $accessToken): self + { $this->accessToken = $accessToken; return $this; } @@ -139,9 +135,8 @@ public function getAccessTokenScope(): ?array /** * @inheritdoc */ - public function setAccessTokenScope( - ?array $accessTokenScope - ): self { + public function setAccessTokenScope(?array $accessTokenScope): self + { $this->accessTokenScope = $accessTokenScope; return $this; } @@ -157,9 +152,8 @@ public function getAccessTokenExpiration(): ?int /** * @inheritdoc */ - public function setAccessTokenExpiration( - ?int $accessTokenExpiration - ): self { + public function setAccessTokenExpiration(?int $accessTokenExpiration): self + { $this->accessTokenExpiration = $accessTokenExpiration; return $this; } @@ -189,9 +183,8 @@ public function getRefreshToken(): ?string /** * @inheritdoc */ - public function setRefreshToken( - ?string $refreshToken - ): self { + public function setRefreshToken(?string $refreshToken): self + { $this->refreshToken = $refreshToken; return $this; } diff --git a/src/Store/LaravelSession.php b/src/Store/LaravelSession.php new file mode 100644 index 00000000..40d06ea3 --- /dev/null +++ b/src/Store/LaravelSession.php @@ -0,0 +1,152 @@ +configuration = $configuration; + $this->sessionPrefix = $sessionPrefix; + } + + /** + * Dispatch event to toggle state deferrance. + * + * @param bool $deferring Whether to defer persisting the storage state. + */ + public function defer(bool $deferring): void + { + return; + } + + /** + * Dispatch event to set the value of a key-value pair. + * + * @param string $key Session key to set. + * @param mixed $value Value to use. + */ + public function set(string $key, $value): void + { + $this->boot(); + $this->getStore() + ->put($this->getPrefixedKey($key), $value); + } + + /** + * Dispatch event to retrieve the value of a key-value pair. + * + * @param string $key Session key to query. + * @param mixed $default Default to return if nothing was found. + * + * @return mixed + */ + public function get(string $key, $default = null) + { + $this->boot(); + return $this->getStore() + ->get($this->getPrefixedKey($key), $default); + } + + /** + * Dispatch event to clear all key-value pairs. + */ + public function purge(): void + { + $this->boot(); + + // It would be unwise for us to simply flush() a session here, as it is shared with the app ecosystem. + // Instead, iterate through the session data, and if they key is prefixed with our assigned string, delete it. + + $pairs = $this->getStore() + ->all(); + $prefix = $this->sessionPrefix . '_'; + + foreach (array_keys($pairs) as $key) { + if (substr($key, 0, strlen($prefix)) === $prefix) { + $this->delete($key); + } + } + } + + /** + * Dispatch event to delete key-value pair. + * + * @param string $key Session key to delete. + */ + public function delete(string $key): void + { + $this->boot(); + $this->getStore() + ->forget($this->getPrefixedKey($key)); + } + + /** + * Dispatch event to alert that a session should be prepared for an incoming request. + */ + private function boot(): void + { + if (! $this->booted) { + if (! $this->getStore()->isStarted()) { + $this->getStore() + ->start(); + } + + $this->booted = true; + } + + return; + } + + private function getStore(): \Illuminate\Session\Store + { + $request = request(); + + if ($request instanceof \Illuminate\Http\Request) { + return $request->session(); + } + + throw new Exception('A cache must be configured.'); + } + + private function getPrefixedKey(string $key): string + { + if ($this->sessionPrefix !== '') { + return $this->sessionPrefix . '_' . $key; + } + + return $key; + } +} diff --git a/src/Traits/ActingAsAuth0User.php b/src/Traits/ActingAsAuth0User.php index 120f0b50..c77b5129 100644 --- a/src/Traits/ActingAsAuth0User.php +++ b/src/Traits/ActingAsAuth0User.php @@ -10,22 +10,16 @@ trait ActingAsAuth0User { - abstract public function actingAs( - UserContract $user, - $guard = null - ); + abstract public function actingAs(UserContract $user, $guard = null); /** * use this method to impersonate a specific auth0 user * if you pass an attributes array, it will be merged with a set of default values * - * @param array $attributes - * * @return mixed */ - public function actingAsAuth0User( - array $attributes = [] - ) { + public function actingAsAuth0User(array $attributes = []) + { $defaults = [ 'sub' => 'some-auth0-user-id', 'azp' => 'some-auth0-appplication-client-id', From 5ff3934d207ec9eb456cb9bc647bd3606dc83b21 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Oct 2022 16:45:24 -0500 Subject: [PATCH 122/525] Update documentation for dropped PHP 7.4 support --- .github/ISSUE_TEMPLATE/Bug Report.yml | 1 - .github/workflows/tests.yml | 42 +++++++++++++++++++++++++++ README.md | 4 --- rector.php | 2 +- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index 932a5d61..d8317f1c 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -26,7 +26,6 @@ body: - PHP 8.2 - PHP 8.1 - PHP 8.0 - - PHP 7.4 - Other (specify in 'additional context') validations: required: true diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9df9d037..bf52a02d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -215,3 +215,45 @@ jobs: - name: Execute Rector run: vendor/bin/rector process src --dry-run + + rector: + name: EBS + runs-on: ubuntu-latest + needs: ["dependencies"] + + strategy: + fail-fast: true + max-parallel: 10 + matrix: + php: ["8.0", "8.1", "8.2"] + + steps: + - name: Set up PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + extensions: mbstring + env: + update: true + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + + - name: Install dependencies + run: composer install --prefer-dist + + - name: Execute Rector + run: vendor/bin/ecs check src --fix diff --git a/README.md b/README.md index 870bda87..933764c5 100644 --- a/README.md +++ b/README.md @@ -41,12 +41,8 @@ This SDK helps you integrate your [Laravel](https://laravel.com/) application wi | | | 8.0 | Nov 2023 | | | 8 | 8.1 | Jan 2023 | | | | 8.0 | Jan 2023 | -| | | 7.4 | Nov 2022 | | 6⁴ | 8 | 8.1 | Jan 2023 | | | | 8.0 | Jan 2023 | -| | | 7.4 | Nov 2022 | -| | 6 (LTS) | 8.0 | Sep 2022 | -| | | 7.4 | Sep 2022 | ¹ This library follows the [Laravel release support schedule](https://laravel.com/docs/releases#support-policy). We do not support framework versions after they stop receiving security fixes from Laravel. diff --git a/rector.php b/rector.php index cfe882bf..4cbf85c5 100644 --- a/rector.php +++ b/rector.php @@ -16,7 +16,7 @@ $rectorConfig->rule(TypedPropertyRector::class); - $rectorConfig->phpVersion(PhpVersion::PHP_74); + $rectorConfig->phpVersion(PhpVersion::PHP_80); $rectorConfig->phpstanConfig(__DIR__ . '/phpstan.neon.dist'); }; From 4d95b8d91e7d683ea678a5cb1187fa36f8b19a59 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Oct 2022 19:28:26 -0500 Subject: [PATCH 123/525] Code styling improvements (#308) * Apply fixes from StyleCI * Code styling improvements * Apply fixes from StyleCI * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Apply fixes from StyleCI * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Update .styleci.yml * Apply fixes from StyleCI * Remove ECS * Apply Pint style fixes * Update .styleci.yml * Apply fixes from StyleCI * Update Auth0Test.php * Update .styleci.yml Co-authored-by: StyleCI Bot --- .editorconfig | 30 +- .github/workflows/tests.yml | 42 --- .styleci.yml | 258 ++++++++++++++++++ composer.json | 185 +++++++------ config/auth0.php | 8 +- ecs.php | 89 ------ phpinsights.php | 10 +- src/Auth/Guard.php | 127 ++++----- src/Auth/User/Provider.php | 16 +- src/Auth/User/Repository.php | 4 +- src/Auth0.php | 30 +- src/Cache/LaravelCacheItem.php | 10 +- src/Cache/LaravelCachePool.php | 54 ++-- src/Configuration.php | 14 +- src/Contract/Auth/Guard.php | 2 +- src/Contract/Auth/User/Provider.php | 4 +- src/Contract/Auth/User/Repository.php | 4 +- src/Contract/Auth0.php | 2 +- src/Contract/Configuration.php | 8 +- src/Contract/Event/Configuration/Built.php | 4 +- .../Event/Stateful/AuthenticationFailed.php | 8 +- .../Stateful/AuthenticationSucceeded.php | 4 +- .../Exception/Stateful/CallbackException.php | 4 +- .../Http/Controller/Stateful/Callback.php | 2 +- .../Http/Controller/Stateful/Login.php | 2 +- .../Http/Controller/Stateful/Logout.php | 2 +- src/Contract/Model/User.php | 9 +- src/Contract/StateInstance.php | 4 +- src/Event/Auth0Event.php | 2 +- src/Event/Configuration/Built.php | 7 +- src/Event/Stateful/AuthenticationFailed.php | 12 +- .../Stateful/AuthenticationSucceeded.php | 7 +- src/Exception/Stateful/CallbackException.php | 2 +- src/Http/Controller/Stateful/Callback.php | 26 +- src/Http/Controller/Stateful/Login.php | 2 +- src/Http/Controller/Stateful/Logout.php | 18 +- src/Http/Middleware/Stateful/Authenticate.php | 15 +- .../Stateful/AuthenticateOptional.php | 14 +- src/Http/Middleware/Stateless/Authorize.php | 17 +- .../Stateless/AuthorizeOptional.php | 14 +- src/Model/User.php | 43 +-- src/ServiceProvider.php | 52 ++-- src/StateInstance.php | 42 +-- src/Store/LaravelSession.php | 47 ++-- src/Traits/ActingAsAuth0User.php | 10 +- tests/Pest.php | 30 +- tests/TestCase.php | 10 +- tests/Unit/Auth0Test.php | 78 +++--- tests/constants.php | 9 +- 49 files changed, 775 insertions(+), 618 deletions(-) create mode 100644 .styleci.yml delete mode 100644 ecs.php diff --git a/.editorconfig b/.editorconfig index 6471f462..1671c9b9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,12 +1,18 @@ -root = true - -[*] -charset = utf-8 -end_of_line = lf -trim_trailing_whitespace = true -insert_final_newline = true - -# We use 4 space indentation for PHP -[*.php] -indent_style = space -indent_size = 4 +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 + +[docker-compose.yml] +indent_size = 4 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bf52a02d..9df9d037 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -215,45 +215,3 @@ jobs: - name: Execute Rector run: vendor/bin/rector process src --dry-run - - rector: - name: EBS - runs-on: ubuntu-latest - needs: ["dependencies"] - - strategy: - fail-fast: true - max-parallel: 10 - matrix: - php: ["8.0", "8.1", "8.2"] - - steps: - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: mbstring - env: - update: true - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - - name: Install dependencies - run: composer install --prefer-dist - - - name: Execute Rector - run: vendor/bin/ecs check src --fix diff --git a/.styleci.yml b/.styleci.yml new file mode 100644 index 00000000..6f1da912 --- /dev/null +++ b/.styleci.yml @@ -0,0 +1,258 @@ +risky: true +version: 8.0 +preset: none +enabled: + - align_double_arrow + - align_phpdoc + - alpha_ordered_imports + - alpha_ordered_traits + - array_indentation + - array_push + - assign_null_coalescing_to_coalesce_equal + - backtick_to_shell_exec + - binary_operator_spaces + - blank_line_after_namespace + - blank_line_after_opening_tag + - blank_line_before_break + - blank_line_before_cases + - blank_line_before_continue + - blank_line_before_declare + - blank_line_before_do + - blank_line_before_exit + - blank_line_before_for + - blank_line_before_goto + - blank_line_before_if + - blank_line_before_include + - blank_line_before_return + - blank_line_before_switch + - blank_line_before_throw + - blank_line_before_try + - blank_line_before_while + - blank_line_before_yield + - cast_spaces + - class_reference_name_casing + - clean_namespace + - combine_consecutive_issets + - combine_consecutive_unsets + - combine_nested_dirname + - comment_to_phpdoc + - compact_nullable_typehint + - concat_with_spaces + - const_separation + - const_visibility_required + - declare_equal_normalize + - declare_strict_types + - deprecation_error_suppression + - die_to_exit + - dir_constant + - doctrine_annotation_array_assignment + - doctrine_annotation_braces + - doctrine_annotation_indentation + - doctrine_annotation_spaces + - elseif + - empty_loop_body_braces + - empty_loop_condition + - encoding + - ereg_to_preg + - escape_implicit_backslashes + - explicit_indirect_variable + - explicit_string_variable + - final_internal_class + - final_public_method_for_abstract_class + - fopen_flag_order + - fopen_flags + - full_opening_tag + - fully_qualified_strict_types + - function_declaration + - function_to_constant + - function_typehint_space + - get_class_to_class_keyword + - hash_to_slash_comment + - heredoc_indentation + - heredoc_to_nowdoc + - implode_call + - include + - indentation + - integer_literal_case + - is_null + - laravel_braces + - laravel_phpdoc_alignment + - laravel_phpdoc_order + - laravel_phpdoc_separation + - linebreak_after_opening_tag + - logical_operators + - lowercase_cast + - lowercase_constants + - lowercase_keywords + - lowercase_static_reference + - magic_constant_casing + - magic_method_casing + - mb_str_functions + - method_argument_space_strict + - method_chaining_indentation + - method_separation + - method_visibility_required + - modernize_strpos + - modernize_types_casting + - multiline_comment_opening_closing + - native_function_casing + - native_function_invocation_symfony + - native_function_type_declaration_casing + - new_with_braces + - no_alias_functions + - no_alternative_syntax + - no_binary_string + - no_blank_lines_after_class_opening + - no_blank_lines_after_phpdoc + - no_blank_lines_after_return + - no_blank_lines_after_throw + - no_blank_lines_around_break + - no_blank_lines_around_cases + - no_blank_lines_around_continue + - no_blank_lines_around_switch + - no_blank_lines_between_imports + - no_break_comment + - no_closing_tag + - no_empty_comment + - no_empty_phpdoc + - no_empty_statement + - no_extra_block_blank_lines + - no_extra_consecutive_blank_lines + - no_homoglyph_names + - no_leading_import_slash + - no_leading_namespace_whitespace + - no_multiline_whitespace_around_double_arrow + - no_multiline_whitespace_before_semicolons + - no_php4_constructor + - no_short_bool_cast + - no_short_echo_tag + - no_singleline_whitespace_before_semicolons + - no_space_around_double_colon + - no_spaces_after_function_name + - no_spaces_inside_offset + - no_spaces_inside_parenthesis + - no_spaces_outside_offset + - no_superfluous_elseif + - no_superfluous_phpdoc_tags_symfony + - no_trailing_comma_in_list_call + - no_trailing_comma_in_singleline_array + - no_trailing_comma_in_singleline_function_call + - no_trailing_whitespace + - no_trailing_whitespace_in_comment + - no_trailing_whitespace_in_string + - no_unneeded_control_parentheses + - no_unneeded_curly_braces + - no_unneeded_final_method + - no_unneeded_import_alias + - no_unreachable_default_argument_value + - no_unset_cast + - no_unused_imports + - no_unused_lambda_imports + - no_useless_else + - no_useless_return + - no_useless_sprintf + - no_whitespace_before_comma_in_array + - no_whitespace_in_blank_line + - non_printable_character + - normalize_index_brace + - not_operator_with_successor_space + - nullable_type_declarations + - object_operator_without_whitespace + - operator_linebreak_end + - ordered_class_elements + - php_unit_fqcn_annotation + - phpdoc_add_missing_param_annotation + - phpdoc_annotation_without_dot + - phpdoc_indent + - phpdoc_inline_inheritdoc + - phpdoc_inline_tag_normalizer + - phpdoc_link_to_see + - phpdoc_no_access + - phpdoc_no_empty_return + - phpdoc_no_package + - phpdoc_no_useless_inheritdoc + - phpdoc_property + - phpdoc_return_self_reference + - phpdoc_scalar + - phpdoc_single_line_var_spacing + - phpdoc_singular_inheritdoc + - phpdoc_summary + - phpdoc_to_comment + - phpdoc_trim + - phpdoc_trim_consecutive_blank_line_separation + - phpdoc_type_to_var + - phpdoc_types + - phpdoc_types_order + - phpdoc_var_order + - phpdoc_var_without_name + - pow_to_exponentiation + - pre_increment + - print_to_echo + - property_separation + - property_visibility_required + - protected_to_private + - psr4 + - random_api_migration + - regular_callable_call + - return_assignment + - return_type_declaration + - self_accessor + - self_static_accessor + - semicolon_after_instruction + - set_type_to_cast + - short_array_syntax + - short_list_syntax + - short_scalar_cast + - simple_to_complex_string_variable + - simplified_if_return + - single_blank_line_at_eof + - single_blank_line_before_namespace + - single_class_element_per_statement + - single_import_per_statement + - single_line_after_imports + - single_line_comment_spacing + - single_line_throw + - single_quote + - single_space_after_construct + - single_trait_insert_per_statement + - space_after_semicolon + - standardize_increment + - standardize_not_equals + - static_lambda + - strict_comparison + - strict_param + - string_length_to_empty + - string_line_ending + - switch_case_semicolon_to_colon + - switch_case_space + - switch_continue_to_break + - symfony_class_definition + - ternary_operator_spaces + - ternary_to_elvis_operator + - ternary_to_null_coalescing + - trailing_comma_in_multiline_array + - trailing_comma_in_multiline_call + - trailing_comma_in_multiline_definition + - trim_array_spaces + - unalign_equals + - unary_operator_spaces + - union_type_without_spaces + - unix_line_endings + - use_arrow_functions + - void_return + - whitespace_after_comma_in_array + - yoda_style +finder: + exclude: + - "modules" + - "node_modules" + - "nova" + - "nova-components" + - "storage" + - "spark" + - "vendor" + - "tests" + name: "*.php" + not-name: + - "*.blade.php" + - "_ide_helper.php" diff --git a/composer.json b/composer.json index d0c27ad2..92f3d860 100644 --- a/composer.json +++ b/composer.json @@ -1,98 +1,97 @@ { - "name": "auth0/login", - "description": "Auth0 Laravel SDK. Straight-forward and tested methods for implementing authentication, and accessing Auth0's Management API endpoints.", - "license": "MIT", - "type": "library", - "keywords": [ - "laravel", - "auth0", - "authentication", - "authorization", - "login", - "auth", - "jwt", - "json web token", - "jwk", - "json web key", - "oauth", - "openid", - "secure", - "protect", - "api" - ], - "authors": [ - { - "name": "Auth0", - "email": "support@auth0.com", - "homepage": "https://auth0.com/" - } - ], - "homepage": "https://github.com/auth0/laravel-auth0", - "require": { - "php": "^8.0", - "ext-filter": "*", - "ext-json": "*", - "ext-mbstring": "*", - "ext-openssl": "*", - "auth0/auth0-php": "^8.0", - "illuminate/contracts": "^8.0 || ^9.0", - "illuminate/http": "^8.0 || ^9.0", - "illuminate/support": "^8.0 || ^9.0", - "spatie/laravel-package-tools": "^1.9" - }, - "require-dev": { - "laravel/laravel": "^8.4.4 || ^9.0", - "laravel/pint": "^1.2", - "nunomaduro/larastan": "^1.0", - "nyholm/psr7": "^1.4", - "orchestra/testbench": "6.25.0", - "pestphp/pest": "^1.21", - "pestphp/pest-plugin-laravel": "^1.2", - "phpstan/phpstan": "^1.7", - "phpstan/phpstan-strict-rules": "1.4.3", - "phpunit/phpunit": "^9.5", - "rector/rector": "^0.13.6", - "symplify/easy-coding-standard": "^11.1", - "wikimedia/composer-merge-plugin": "^2.0" - }, - "autoload": { - "psr-4": { - "Auth0\\Laravel\\": "src" - } - }, - "autoload-dev": { - "psr-4": { - "Auth0\\Laravel\\Tests\\": "tests" - } - }, - "config": { - "allow-plugins": { - "pestphp/pest-plugin": true, - "wikimedia/composer-merge-plugin": true + "name": "auth0/login", + "description": "Auth0 Laravel SDK. Straight-forward and tested methods for implementing authentication, and accessing Auth0's Management API endpoints.", + "license": "MIT", + "type": "library", + "keywords": [ + "laravel", + "auth0", + "authentication", + "authorization", + "login", + "auth", + "jwt", + "json web token", + "jwk", + "json web key", + "oauth", + "openid", + "secure", + "protect", + "api" + ], + "authors": [ + { + "name": "Auth0", + "email": "support@auth0.com", + "homepage": "https://auth0.com/" + } + ], + "homepage": "https://github.com/auth0/laravel-auth0", + "require": { + "php": "^8.0", + "ext-filter": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "auth0/auth0-php": "^8.0", + "illuminate/contracts": "^8.0 || ^9.0", + "illuminate/http": "^8.0 || ^9.0", + "illuminate/support": "^8.0 || ^9.0", + "spatie/laravel-package-tools": "^1.9" + }, + "require-dev": { + "laravel/laravel": "^8.4.4 || ^9.0", + "laravel/pint": "^1.2", + "nunomaduro/larastan": "^1.0", + "nyholm/psr7": "^1.4", + "orchestra/testbench": "6.25.0", + "pestphp/pest": "^1.21", + "pestphp/pest-plugin-laravel": "^1.2", + "phpstan/phpstan": "^1.7", + "phpstan/phpstan-strict-rules": "1.4.3", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.6", + "wikimedia/composer-merge-plugin": "^2.0" + }, + "autoload": { + "psr-4": { + "Auth0\\Laravel\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Auth0\\Laravel\\Tests\\": "tests" + } }, - "optimize-autoloader": true, - "sort-packages": true - }, - "extra": { - "laravel": { - "aliases": { - "Auth0": "Auth0\\Laravel\\Facade\\Auth0" - }, - "providers": [ - "Auth0\\Laravel\\ServiceProvider" - ] + "config": { + "allow-plugins": { + "pestphp/pest-plugin": true, + "wikimedia/composer-merge-plugin": true + }, + "optimize-autoloader": true, + "sort-packages": true }, - "merge-plugin": { - "ignore-duplicates": false, - "include": [ - "composer.local.json" - ], - "merge-dev": true, - "merge-extra": false, - "merge-extra-deep": false, - "merge-scripts": false, - "recurse": true, - "replace": true + "extra": { + "laravel": { + "aliases": { + "Auth0": "Auth0\\Laravel\\Facade\\Auth0" + }, + "providers": [ + "Auth0\\Laravel\\ServiceProvider" + ] + }, + "merge-plugin": { + "ignore-duplicates": false, + "include": [ + "composer.local.json" + ], + "merge-dev": true, + "merge-extra": false, + "merge-extra-deep": false, + "merge-scripts": false, + "recurse": true, + "replace": true + } } - } } diff --git a/config/auth0.php b/config/auth0.php index e49d238a..23ad6f4a 100644 --- a/config/auth0.php +++ b/config/auth0.php @@ -4,7 +4,7 @@ /** * Please review available configuration options here: - * https://github.com/auth0/auth0-PHP#configuration-options + * https://github.com/auth0/auth0-PHP#configuration-options. */ return [ // Should be assigned either 'api', 'management', or 'webapp' to indicate your application's use case for the SDK. @@ -53,7 +53,7 @@ // Named routes within your Laravel application that the SDK may call during stateful requests for redirections. 'routes' => [ - 'home' => env('AUTH0_ROUTE_HOME', '/'), - 'login' => env('AUTH0_ROUTE_LOGIN', 'login') - ] + 'home' => env('AUTH0_ROUTE_HOME', '/'), + 'login' => env('AUTH0_ROUTE_LOGIN', 'login'), + ], ]; diff --git a/ecs.php b/ecs.php deleted file mode 100644 index 140eed84..00000000 --- a/ecs.php +++ /dev/null @@ -1,89 +0,0 @@ -sets([SetList::PSR_12, SetList::SYMPLIFY, SetList::COMMON, SetList::CLEAN_CODE]); - - $ecsConfig->paths([ - __DIR__ . '/bin', - __DIR__ . '/src', - __DIR__ . '/packages', - __DIR__ . '/packages-tests', - __DIR__ . '/rules', - __DIR__ . '/rules-tests', - __DIR__ . '/tests', - __DIR__ . '/utils', - __DIR__ . '/config', - __DIR__ . '/ecs.php', - __DIR__ . '/easy-ci.php', - __DIR__ . '/rector.php', - __DIR__ . '/scoper.php', - __DIR__ . '/build/build-preload.php', - ]); - - $ecsConfig->ruleWithConfiguration(NoSuperfluousPhpdocTagsFixer::class, [ - 'allow_mixed' => true, - ]); - - $ecsConfig->ruleWithConfiguration(GeneralPhpdocAnnotationRemoveFixer::class, [ - 'annotations' => [ - 'throw', - 'throws', - 'author', - 'authors', - 'package', - 'group', - 'required', - 'phpstan-ignore-line', - 'phpstan-ignore-next-line', - ], - ]); - - $ecsConfig->rule(StaticLambdaFixer::class); - - $ecsConfig->skip([ - '*/Source/*', - '*/Fixture/*', - '*/Expected/*', - - // buggy - @todo fix on Symplify master - DocBlockLineLengthFixer::class, - - PhpdocTypesFixer::class => [ - // double to Double false positive - __DIR__ . '/rules/Php74/Rector/Double/RealToFloatTypeCastRector.php', - // skip for enum types - __DIR__ . '/rules/Php70/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php', - ], - - // breaking and handled better by Rector PHPUnit code quality set, removed in symplify dev-main - PhpUnitStrictFixer::class, - - // skip add space on &$variable - FunctionTypehintSpaceFixer::class => [ - __DIR__ . '/src/PhpParser/Printer/BetterStandardPrinter.php', - __DIR__ . '/src/DependencyInjection/Loader/Configurator/RectorServiceConfigurator.php', - __DIR__ . '/rules/Php70/EregToPcreTransformer.php', - ], - - AssignmentInConditionSniff::class . '.FoundInWhileCondition', - - // null on purpose as no change - PhpdocNoEmptyReturnFixer::class => [ - __DIR__ . '/rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php', - ], - ]); -}; diff --git a/phpinsights.php b/phpinsights.php index 4760026b..e906663d 100644 --- a/phpinsights.php +++ b/phpinsights.php @@ -4,7 +4,7 @@ return [ 'preset' => 'laravel', - 'ide' => null, + 'ide' => null, 'exclude' => [], @@ -57,10 +57,10 @@ ], 'requirements' => [ - 'min-quality' => 100, - 'min-complexity' => 50, - 'min-architecture' => 100, - 'min-style' => 100, + 'min-quality' => 100, + 'min-complexity' => 50, + 'min-architecture' => 100, + 'min-style' => 100, 'disable-security-check' => false, ], ]; diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 889b9ba4..b41f0052 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -17,47 +17,49 @@ final class Guard implements \Auth0\Laravel\Contract\Auth\Guard, \Illuminate\Con private \Illuminate\Http\Request $request; /** - * @inheritdoc + * {@inheritdoc} */ public function __construct( \Illuminate\Contracts\Auth\UserProvider $provider, - \Illuminate\Http\Request $request + \Illuminate\Http\Request $request, ) { $this->provider = $provider; $this->request = $request; } /** - * @inheritdoc + * {@inheritdoc} */ public function login(\Illuminate\Contracts\Auth\Authenticatable $user): self { - $this->getState() - ->setUser($user); + $this->getState()-> + setUser($user); + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function logout(): self { - $this->getState() - ->setUser(null); + $this->getState()-> + setUser(null); app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function check(): bool { - return $this->user() !== null; + return null !== $this->user(); } /** - * @inheritdoc + * {@inheritdoc} */ public function guest(): bool { @@ -65,26 +67,26 @@ public function guest(): bool } /** - * @inheritdoc + * {@inheritdoc} */ public function user(): ?\Illuminate\Contracts\Auth\Authenticatable { - return $this->getState() - ->getUser() ?? $this->getUserFromToken() ?? $this->getUserFromSession() ?? null; + return $this->getState()-> + getUser() ?? $this->getUserFromToken() ?? $this->getUserFromSession() ?? null; } /** - * @inheritdoc + * {@inheritdoc} */ public function id() { $response = null; - if ($this->user() !== null) { - $id = $this->user() - ->getAuthIdentifier(); + if (null !== $this->user()) { + $id = $this->user()-> + getAuthIdentifier(); - if (is_string($id) || is_int($id)) { + if (\is_string($id) || \is_int($id)) { $response = $id; } } @@ -93,7 +95,7 @@ public function id() } /** - * @inheritdoc + * {@inheritdoc} * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ @@ -103,34 +105,36 @@ public function validate(array $credentials = []): bool } /** - * @inheritdoc + * {@inheritdoc} */ public function setUser(\Illuminate\Contracts\Auth\Authenticatable $user): self { - $user = $this->getState() - ->setUser($user); + $user = $this->getState()-> + setUser($user); + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function hasUser(): bool { - return $this->getState()->getUser() !== null; + return null !== $this->getState()->getUser(); } /** - * @inheritdoc + * {@inheritdoc} */ public function hasScope(string $scope): bool { $state = $this->getState(); - return in_array($scope, $state->getAccessTokenScope() ?? [], true); + + return \in_array($scope, $state->getAccessTokenScope() ?? [], true); } /** - * Always returns false to keep third-party apps happy + * Always returns false to keep third-party apps happy. */ public function viaRemember(): bool { @@ -146,7 +150,7 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable $token = $this->request->bearerToken(); // If a session is not available, return null. - if ($token === null) { + if (null === $token) { return null; } @@ -160,7 +164,7 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable null, null, null, - \Auth0\SDK\Token::TYPE_TOKEN + \Auth0\SDK\Token::TYPE_TOKEN, )->toArray(); } catch (\Auth0\SDK\Exception\InvalidTokenException $invalidToken) { // Invalid bearer token. @@ -168,26 +172,26 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable } // Query the UserProvider to retrieve tue user for the token. - $user = $this->getProvider() - ->getRepository() - ->fromAccessToken($decoded); + $user = $this->getProvider()-> + getRepository()-> + fromAccessToken($decoded); // Was a user retrieved successfully? - if ($user !== null) { + if (null !== $user) { if (! $user instanceof \Illuminate\Contracts\Auth\Authenticatable) { - die('User model returned fromAccessToken must implement \Illuminate\Contracts\Auth\Authenticatable.'); + exit('User model returned fromAccessToken must implement \Illuminate\Contracts\Auth\Authenticatable.'); } if (! $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { - die('User model returned fromAccessToken must implement \Auth0\Laravel\Contract\Model\Stateless\User.'); + exit('User model returned fromAccessToken must implement \Auth0\Laravel\Contract\Model\Stateless\User.'); } - $this->getState() - ->clear() - ->setDecoded($decoded) - ->setAccessToken($token) - ->setAccessTokenScope(explode(' ', $decoded['scope'] ?? '')) - ->setAccessTokenExpiration($decoded['exp'] ?? null); + $this->getState()-> + clear()-> + setDecoded($decoded)-> + setAccessToken($token)-> + setAccessTokenScope(explode(' ', $decoded['scope'] ?? ''))-> + setAccessTokenExpiration($decoded['exp'] ?? null); } return $user; @@ -202,33 +206,33 @@ private function getUserFromSession(): ?\Illuminate\Contracts\Auth\Authenticatab $session = app(\Auth0\Laravel\Auth0::class)->getSdk()->getCredentials(); // If a session is not available, return null. - if ($session === null) { + if (null === $session) { return null; } // Query the UserProvider to retrieve tue user for the session. - $user = $this->getProvider() - ->getRepository() - ->fromSession($session->user); + $user = $this->getProvider()-> + getRepository()-> + fromSession($session->user); // Was a user retrieved successfully? - if ($user !== null) { + if (null !== $user) { if (! $user instanceof \Illuminate\Contracts\Auth\Authenticatable) { - die('User model returned fromSession must implement \Illuminate\Contracts\Auth\Authenticatable.'); + exit('User model returned fromSession must implement \Illuminate\Contracts\Auth\Authenticatable.'); } if (! $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { - die('User model returned fromSession must implement \Auth0\Laravel\Contract\Model\Stateful\User.'); + exit('User model returned fromSession must implement \Auth0\Laravel\Contract\Model\Stateful\User.'); } - $this->getState() - ->clear() - ->setDecoded($session->user) - ->setIdToken($session->idToken) - ->setAccessToken($session->accessToken) - ->setAccessTokenScope($session->accessTokenScope) - ->setAccessTokenExpiration($session->accessTokenExpiration) - ->setRefreshToken($session->refreshToken); + $this->getState()-> + clear()-> + setDecoded($session->user)-> + setIdToken($session->idToken)-> + setAccessToken($session->accessToken)-> + setAccessTokenScope($session->accessTokenScope)-> + setAccessTokenExpiration($session->accessTokenExpiration)-> + setRefreshToken($session->refreshToken); $user = $this->handleSessionExpiration($user); } @@ -240,17 +244,17 @@ private function getUserFromSession(): ?\Illuminate\Contracts\Auth\Authenticatab * Handle instances of session token expiration. */ private function handleSessionExpiration( - ?\Illuminate\Contracts\Auth\Authenticatable $user + ?\Illuminate\Contracts\Auth\Authenticatable $user, ): ?\Illuminate\Contracts\Auth\Authenticatable { $state = $this->getState(); // Unless our token expired, we have nothing to do here. - if ($state->getAccessTokenExpired() !== true) { + if (true !== $state->getAccessTokenExpired()) { return $user; } // Do we have a refresh token? - if ($state->getRefreshToken() !== null) { + if (null !== $state->getRefreshToken()) { try { // Try to renew our token. app(\Auth0\Laravel\Auth0::class)->getSdk()->renew(); @@ -262,8 +266,9 @@ private function handleSessionExpiration( // Retrieve updated state data $refreshed = app(\Auth0\Laravel\Auth0::class)->getSdk()->getCredentials(); - if ($refreshed !== null && $refreshed->accessTokenExpired === false) { + if (null !== $refreshed && false === $refreshed->accessTokenExpired) { event(new \Auth0\Laravel\Event\Stateful\TokenRefreshSucceeded()); + return $user; } } diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php index c53c3975..c68bed2a 100644 --- a/src/Auth/User/Provider.php +++ b/src/Auth/User/Provider.php @@ -12,7 +12,7 @@ final class Provider implements \Auth0\Laravel\Contract\Auth\User\Provider, \Ill private \Auth0\Laravel\Contract\Auth\User\Repository $repository; /** - * @inheritdoc + * {@inheritdoc} */ public function __construct(\Auth0\Laravel\Contract\Auth\User\Repository $repository) { @@ -20,7 +20,7 @@ public function __construct(\Auth0\Laravel\Contract\Auth\User\Repository $reposi } /** - * @inheritdoc + * {@inheritdoc} * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ @@ -30,7 +30,7 @@ public function retrieveById($identifier): ?\Illuminate\Contracts\Auth\Authentic } /** - * @inheritdoc + * {@inheritdoc} * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ @@ -40,7 +40,7 @@ public function retrieveByToken($identifier, $token): ?\Illuminate\Contracts\Aut } /** - * @inheritdoc + * {@inheritdoc} * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ @@ -50,19 +50,19 @@ public function retrieveByCredentials(array $credentials): ?\Illuminate\Contract } /** - * @inheritdoc + * {@inheritdoc} * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ public function validateCredentials( \Illuminate\Contracts\Auth\Authenticatable $user, - array $credentials + array $credentials, ): bool { return false; } /** - * @inheritdoc + * {@inheritdoc} * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ @@ -71,7 +71,7 @@ public function updateRememberToken(\Illuminate\Contracts\Auth\Authenticatable $ } /** - * @inheritdoc + * {@inheritdoc} */ public function getRepository(): \Auth0\Laravel\Contract\Auth\User\Repository { diff --git a/src/Auth/User/Repository.php b/src/Auth/User/Repository.php index 1777cf74..8e90781e 100644 --- a/src/Auth/User/Repository.php +++ b/src/Auth/User/Repository.php @@ -7,7 +7,7 @@ final class Repository implements \Auth0\Laravel\Contract\Auth\User\Repository { /** - * @inheritdoc + * {@inheritdoc} */ public function fromSession(array $user): ?\Illuminate\Contracts\Auth\Authenticatable { @@ -15,7 +15,7 @@ public function fromSession(array $user): ?\Illuminate\Contracts\Auth\Authentica } /** - * @inheritdoc + * {@inheritdoc} */ public function fromAccessToken(array $user): ?\Illuminate\Contracts\Auth\Authenticatable { diff --git a/src/Auth0.php b/src/Auth0.php index 1deb431c..d721c215 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -13,7 +13,7 @@ final class Auth0 implements \Auth0\Laravel\Contract\Auth0 { /** - * The Laravel-Auth0 SDK version: + * The Laravel-Auth0 SDK version:. */ public const VERSION = '7.1.0'; @@ -28,11 +28,11 @@ final class Auth0 implements \Auth0\Laravel\Contract\Auth0 private ?\Auth0\SDK\Configuration\SdkConfiguration $configuration = null; /** - * @inheritdoc + * {@inheritdoc} */ public function getSdk(): \Auth0\SDK\Contract\Auth0Interface { - if ($this->sdk === null) { + if (null === $this->sdk) { $this->sdk = new \Auth0\SDK\Auth0($this->getConfiguration()); $this->setSdkTelemetry(); } @@ -41,24 +41,25 @@ public function getSdk(): \Auth0\SDK\Contract\Auth0Interface } /** - * @inheritdoc + * {@inheritdoc} */ public function setSdk(\Auth0\SDK\Contract\Auth0Interface $sdk): self { $this->sdk = $sdk; $this->setSdkTelemetry(); + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function getConfiguration(): \Auth0\SDK\Configuration\SdkConfiguration { - if ($this->configuration === null) { - $config = app() - ->make('config') - ->get('auth0'); + if (null === $this->configuration) { + $config = app()-> + make('config')-> + get('auth0'); if (! isset($config['tokenCache']) || ! isset($config['managementTokenCache'])) { $cache = new LaravelCachePool(); @@ -77,14 +78,14 @@ public function getConfiguration(): \Auth0\SDK\Configuration\SdkConfiguration // If no sessionStorage is defined, use an LaravelSession store instance. if (! isset($config['sessionStorage'])) { $configuration->setSessionStorage( - new LaravelSession($configuration, $configuration->getSessionStorageId()) + new LaravelSession($configuration, $configuration->getSessionStorageId()), ); } // If no transientStorage is defined, use an LaravelSession store instance. if (! isset($config['transientStorage'])) { $configuration->setTransientStorage( - new LaravelSession($configuration, $configuration->getSessionStorageId()) + new LaravelSession($configuration, $configuration->getSessionStorageId()), ); } @@ -99,18 +100,19 @@ public function getConfiguration(): \Auth0\SDK\Configuration\SdkConfiguration } /** - * @inheritdoc + * {@inheritdoc} */ public function setConfiguration(\Auth0\SDK\Configuration\SdkConfiguration $configuration): self { $this->configuration = $configuration; + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ - public function getState(): \Auth0\Laravel\Contract\StateInstance + public function getState(): Contract\StateInstance { return app()->make(\Auth0\Laravel\StateInstance::class); } diff --git a/src/Cache/LaravelCacheItem.php b/src/Cache/LaravelCacheItem.php index 258f2def..6dd930a0 100644 --- a/src/Cache/LaravelCacheItem.php +++ b/src/Cache/LaravelCacheItem.php @@ -45,6 +45,7 @@ public function set(mixed $value): static { $this->value = $value; $this->is_hit = true; + return $this; } @@ -52,20 +53,23 @@ public function expiresAt(mixed $expiration): static { if ($expiration instanceof DateTimeInterface) { $this->expires = $expiration->getTimestamp(); + return $this; } $this->expires = $expiration; + return $this; } /** - * @param DateInterval|int|null $time + * @param DateInterval|int|null $time */ public function expiresAfter(mixed $time): static { - if ($time === null) { + if (null === $time) { $this->expires = null; + return $this; } @@ -73,10 +77,12 @@ public function expiresAfter(mixed $time): static $dateTime = new DateTime(); $dateTime->add($time); $this->expires = $dateTime->getTimestamp(); + return $this; } $this->expires = time() + $time; + return $this; } diff --git a/src/Cache/LaravelCachePool.php b/src/Cache/LaravelCachePool.php index d3d0dc26..0aa5e1a9 100644 --- a/src/Cache/LaravelCachePool.php +++ b/src/Cache/LaravelCachePool.php @@ -22,16 +22,16 @@ final class LaravelCachePool implements CacheItemPoolInterface public function __construct() { - $this->manager = app() - ->make(\Illuminate\Cache\CacheManager::class); + $this->manager = app()-> + make(\Illuminate\Cache\CacheManager::class); } public function getItem(string $key): CacheItemInterface { - $value = $this->getStore() - ->get($key); + $value = $this->getStore()-> + get($key); - if ($value === false) { + if (false === $value) { return LaravelCacheItem::miss($key); } @@ -39,18 +39,17 @@ public function getItem(string $key): CacheItemInterface } /** - * @param string[] $keys - * + * @param string[] $keys * @return CacheItemInterface[] */ public function getItems(array $keys = []): iterable { - if ($keys === []) { + if ([] === $keys) { return []; } - $results = $this->getStore() - ->many($keys); + $results = $this->getStore()-> + many($keys); $items = []; foreach ($results as $key => $value) { @@ -62,28 +61,29 @@ public function getItems(array $keys = []): iterable } /** - * @param string $key The key for which to return the corresponding Cache Item. + * @param string $key the key for which to return the corresponding Cache Item */ public function hasItem(mixed $key): bool { - return $this->getItem($key) - ->isHit(); + return $this->getItem($key)-> + isHit(); } public function clear(): bool { $this->deferred = []; - return $this->getStore() - ->flush(); + + return $this->getStore()-> + flush(); } /** - * @param string $key The key for which to return the corresponding Cache Item. + * @param string $key the key for which to return the corresponding Cache Item */ public function deleteItem(mixed $key): bool { - return $this->getStore() - ->forget($key); + return $this->getStore()-> + forget($key); } public function deleteItems(array $keys): bool @@ -110,7 +110,7 @@ public function save(CacheItemInterface $item): bool $expires = $item->expirationTimestamp(); $ttl = 0; - if ($expires !== null) { + if (null !== $expires) { if ($expires <= time()) { return $this->deleteItem($key); } @@ -118,8 +118,8 @@ public function save(CacheItemInterface $item): bool $ttl = $expires - time(); } - return $this->getStore() - ->put($key, $value, $ttl); + return $this->getStore()-> + put($key, $value, $ttl); } public function saveDeferred(CacheItemInterface $item): bool @@ -129,7 +129,7 @@ public function saveDeferred(CacheItemInterface $item): bool } $this->deferred[$item->getKey()] = [ - 'item' => $item, + 'item' => $item, 'expiration' => $item->expirationTimestamp(), ]; @@ -143,12 +143,13 @@ public function commit(): bool foreach (array_keys($this->deferred) as $singleDeferred) { $item = $this->getDeferred((string) $singleDeferred); - if ($item !== null && ! $this->save($item)) { + if (null !== $item && ! $this->save($item)) { $success = false; } } $this->deferred = []; + return $success; } @@ -159,13 +160,13 @@ private function getStore(): \Illuminate\Contracts\Cache\Store private function createItem(string $key, mixed $value): CacheItemInterface { - if (! is_string($value)) { + if (! \is_string($value)) { return LaravelCacheItem::miss($key); } $value = unserialize($value); - if ($value === false || $value !== 'b:0;') { + if (false === $value || 'b:0;' !== $value) { return LaravelCacheItem::miss($key); } @@ -182,8 +183,9 @@ private function getDeferred(string $key): ?CacheItemInterface $item = clone $deferred['item']; $expires = $deferred['expiration']; - if ($expires !== null && $expires <= time()) { + if (null !== $expires && $expires <= time()) { unset($this->deferred[$key]); + return null; } diff --git a/src/Configuration.php b/src/Configuration.php index 876b208f..d6ac44ce 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -10,15 +10,15 @@ final class Configuration implements \Auth0\Laravel\Contract\Configuration { /** - * @inheritdoc + * {@inheritdoc} */ public static function stringToArrayOrNull(?string $config, string $delimiter = ' '): ?array { - if (is_string($config) && strlen($config) >= 1 && strlen($delimiter) >= 1) { + if (\is_string($config) && '' !== $config && '' !== $delimiter) { $response = explode($delimiter, $config); // @phpstan-ignore-next-line - if (is_array($response) && count($response) >= 1 && strlen(trim($response[0])) !== 0) { + if (\is_array($response) && \count($response) >= 1 && '' !== trim($response[0])) { return $response; } } @@ -27,14 +27,14 @@ public static function stringToArrayOrNull(?string $config, string $delimiter = } /** - * @inheritdoc + * {@inheritdoc} */ public static function stringToBoolOrNull(?string $config, ?bool $default = null): ?bool { - if (is_string($config) && strlen($config) >= 1) { - $config = strtolower(trim($config)); + if (\is_string($config) && '' !== $config) { + $config = mb_strtolower(trim($config)); - return $config === 'true'; + return 'true' === $config; } return $default; diff --git a/src/Contract/Auth/Guard.php b/src/Contract/Auth/Guard.php index 1b4280c3..4dfd5381 100644 --- a/src/Contract/Auth/Guard.php +++ b/src/Contract/Auth/Guard.php @@ -11,7 +11,7 @@ interface Guard */ public function __construct( \Illuminate\Contracts\Auth\UserProvider $provider, - \Illuminate\Http\Request $request + \Illuminate\Http\Request $request, ); /** diff --git a/src/Contract/Auth/User/Provider.php b/src/Contract/Auth/User/Provider.php index 5f5966c8..05556798 100644 --- a/src/Contract/Auth/User/Provider.php +++ b/src/Contract/Auth/User/Provider.php @@ -9,12 +9,12 @@ interface Provider /** * \Auth0\Laravel\Contract\Auth\User\Provider constructor. * - * @param \Auth0\Laravel\Auth\User\Repository $repository A repository instance. + * @param \Auth0\Laravel\Auth\User\Repository $repository a repository instance */ public function __construct(\Auth0\Laravel\Auth\User\Repository $repository); /** * Returns the assigned user provider. */ - public function getRepository(): \Auth0\Laravel\Contract\Auth\User\Repository; + public function getRepository(): Repository; } diff --git a/src/Contract/Auth/User/Repository.php b/src/Contract/Auth/User/Repository.php index 9224c85a..a9651bb0 100644 --- a/src/Contract/Auth/User/Repository.php +++ b/src/Contract/Auth/User/Repository.php @@ -9,14 +9,14 @@ interface Repository /** * Generate a \Auth0\Laravel\Model\Stateful\User instance from an available Auth0-PHP user session. * - * @param array $user An array containing the raw Auth0 user data. + * @param array $user an array containing the raw Auth0 user data */ public function fromSession(array $user): ?\Illuminate\Contracts\Auth\Authenticatable; /** * Generate a \Auth0\Laravel\Model\Stateful\User instance from a parsed Access Token. * - * @param array $user An array containing the raw Auth0 user data. + * @param array $user an array containing the raw Auth0 user data */ public function fromAccessToken(array $user): ?\Illuminate\Contracts\Auth\Authenticatable; } diff --git a/src/Contract/Auth0.php b/src/Contract/Auth0.php index 0129be4d..f49e03d7 100644 --- a/src/Contract/Auth0.php +++ b/src/Contract/Auth0.php @@ -29,5 +29,5 @@ public function setConfiguration(\Auth0\SDK\Configuration\SdkConfiguration $conf /** * Create/create a request state instance, a storage singleton containing authenticated user data. */ - public function getState(): \Auth0\Laravel\Contract\StateInstance; + public function getState(): StateInstance; } diff --git a/src/Contract/Configuration.php b/src/Contract/Configuration.php index 38954dc0..1902f52f 100644 --- a/src/Contract/Configuration.php +++ b/src/Contract/Configuration.php @@ -9,16 +9,16 @@ interface Configuration /** * Converts a delimited string into an array, or null, if nothing was provided. * - * @param string|null $config The string contents to convert, i.e. 'one two three'. - * @param string $delimiter The string delimiter to split the string contents with; defaults to space. + * @param string|null $config The string contents to convert, i.e. 'one two three'. + * @param string $delimiter the string delimiter to split the string contents with; defaults to space */ public static function stringToArrayOrNull(?string $config, string $delimiter = ' '): ?array; /** * Converts a truthy string representation into a boolean. * - * @param string|null $config The string contents to convert, i.e. 'true' - * @param bool|null $default The default boolean value to return if a valid string wasn't provided. + * @param string|null $config The string contents to convert, i.e. 'true' + * @param bool|null $default the default boolean value to return if a valid string wasn't provided */ public static function stringToBoolOrNull(?string $config, ?bool $default = null): ?bool; } diff --git a/src/Contract/Event/Configuration/Built.php b/src/Contract/Event/Configuration/Built.php index 6809ab54..4444d712 100644 --- a/src/Contract/Event/Configuration/Built.php +++ b/src/Contract/Event/Configuration/Built.php @@ -11,7 +11,7 @@ interface Built /** * AuthenticationFailed constructor. * - * @param SdkConfiguration $configuration An instance of Auth0\SDK\Configuration\SdkConfiguration for use with the Auth0-PHP SDK. + * @param SdkConfiguration $configuration an instance of Auth0\SDK\Configuration\SdkConfiguration for use with the Auth0-PHP SDK */ public function __construct(SdkConfiguration $configuration); @@ -23,7 +23,7 @@ public function getConfiguration(): SdkConfiguration; /** * Determine whether the provided exception will be thrown by the SDK. * - * @param SdkConfiguration $configuration An instance of Auth0\SDK\Configuration\SdkConfiguration for use with the Auth0-PHP SDK. + * @param SdkConfiguration $configuration an instance of Auth0\SDK\Configuration\SdkConfiguration for use with the Auth0-PHP SDK */ public function setConfiguration(SdkConfiguration $configuration): self; } diff --git a/src/Contract/Event/Stateful/AuthenticationFailed.php b/src/Contract/Event/Stateful/AuthenticationFailed.php index 2170fc81..427e3964 100644 --- a/src/Contract/Event/Stateful/AuthenticationFailed.php +++ b/src/Contract/Event/Stateful/AuthenticationFailed.php @@ -9,15 +9,15 @@ interface AuthenticationFailed /** * AuthenticationFailed constructor. * - * @param \Throwable $exception An exception instance in which to throw for the authentication failure. - * @param bool $throwException Whether or not $exception will be thrown. + * @param \Throwable $exception an exception instance in which to throw for the authentication failure + * @param bool $throwException whether or not $exception will be thrown */ public function __construct(\Throwable $exception, bool $throwException = true); /** * Overwrite the exception to be thrown. * - * @param \Throwable $exception An exception instance in which to throw for the authentication failure. + * @param \Throwable $exception an exception instance in which to throw for the authentication failure */ public function setException(\Throwable $exception): self; @@ -29,7 +29,7 @@ public function getException(): \Throwable; /** * Determine whether the provided exception will be thrown by the SDK. * - * @param bool $throwException Whether or not $exception will be thrown. + * @param bool $throwException whether or not $exception will be thrown */ public function setThrowException(bool $throwException): self; diff --git a/src/Contract/Event/Stateful/AuthenticationSucceeded.php b/src/Contract/Event/Stateful/AuthenticationSucceeded.php index 0fae19b0..b0b892e8 100644 --- a/src/Contract/Event/Stateful/AuthenticationSucceeded.php +++ b/src/Contract/Event/Stateful/AuthenticationSucceeded.php @@ -9,14 +9,14 @@ interface AuthenticationSucceeded /** * AuthenticationSucceeded constructor. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user An instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user. + * @param \Illuminate\Contracts\Auth\Authenticatable $user an instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user */ public function __construct(\Illuminate\Contracts\Auth\Authenticatable $user); /** * Overwrite the authenticated user. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user An instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user. + * @param \Illuminate\Contracts\Auth\Authenticatable $user an instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user */ public function setUser(\Illuminate\Contracts\Auth\Authenticatable $user): self; diff --git a/src/Contract/Exception/Stateful/CallbackException.php b/src/Contract/Exception/Stateful/CallbackException.php index 5ecd5d10..75eae4ee 100644 --- a/src/Contract/Exception/Stateful/CallbackException.php +++ b/src/Contract/Exception/Stateful/CallbackException.php @@ -9,8 +9,8 @@ interface CallbackException /** * Thrown when an API exception is encountered in an underlying network request. * - * @param string $error The error message to return. - * @param string $errorDescription The error description to return. + * @param string $error the error message to return + * @param string $errorDescription the error description to return */ public static function apiException(string $error, string $errorDescription): self; } diff --git a/src/Contract/Http/Controller/Stateful/Callback.php b/src/Contract/Http/Controller/Stateful/Callback.php index f16878fd..de9097f8 100644 --- a/src/Contract/Http/Controller/Stateful/Callback.php +++ b/src/Contract/Http/Controller/Stateful/Callback.php @@ -9,7 +9,7 @@ interface Callback /** * Process the session for the end user after returning from authenticating with Auth0. * - * @param \Illuminate\Http\Request $request The incoming request instance. + * @param \Illuminate\Http\Request $request the incoming request instance */ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse; } diff --git a/src/Contract/Http/Controller/Stateful/Login.php b/src/Contract/Http/Controller/Stateful/Login.php index b65839b4..1deba3b2 100644 --- a/src/Contract/Http/Controller/Stateful/Login.php +++ b/src/Contract/Http/Controller/Stateful/Login.php @@ -10,7 +10,7 @@ interface Login * Redirect to the configured Auth0 Universal Login Page if a session is not available. * Otherwise, redirect to the "/" route. * - * @param \Illuminate\Http\Request $request The incoming request instance. + * @param \Illuminate\Http\Request $request the incoming request instance */ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse; } diff --git a/src/Contract/Http/Controller/Stateful/Logout.php b/src/Contract/Http/Controller/Stateful/Logout.php index e7d35442..17c8cffd 100644 --- a/src/Contract/Http/Controller/Stateful/Logout.php +++ b/src/Contract/Http/Controller/Stateful/Logout.php @@ -10,7 +10,7 @@ interface Logout * Redirect to Auth0's logout endpoint if a session is available. * Otherwise, redirect to the "/" route. * - * @param \Illuminate\Http\Request $request The incoming request instance. + * @param \Illuminate\Http\Request $request the incoming request instance */ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse; } diff --git a/src/Contract/Model/User.php b/src/Contract/Model/User.php index 2f692444..65cdeb9a 100644 --- a/src/Contract/Model/User.php +++ b/src/Contract/Model/User.php @@ -9,7 +9,7 @@ interface User /** * \Auth0\Laravel\Model\User constructor. * - * @param array $attributes Attributes representing the user data. + * @param array $attributes attributes representing the user data */ public function __construct(array $attributes = []); @@ -23,7 +23,7 @@ public function __get(string $key); /** * Dynamically set attributes on the model. * - * @param mixed $value + * @param mixed $value */ public function __set(string $key, $value): void; @@ -35,15 +35,14 @@ public function fill(array $attributes): self; /** * Set a given attribute on the model. * - * @param mixed $value + * @param mixed $value */ public function setAttribute(string $key, $value): self; /** * Get an attribute from the model. * - * @param mixed $default - * + * @param mixed $default * @return mixed */ public function getAttribute(string $key, $default = null); diff --git a/src/Contract/StateInstance.php b/src/Contract/StateInstance.php index 9ca71d92..e6b91828 100644 --- a/src/Contract/StateInstance.php +++ b/src/Contract/StateInstance.php @@ -19,7 +19,7 @@ public function getUser(): ?\Illuminate\Contracts\Auth\Authenticatable; /** * Set the authenticated user context for the current request. * - * @param \Illuminate\Contracts\Auth\Authenticatable|null $user An authenticated user context. + * @param \Illuminate\Contracts\Auth\Authenticatable|null $user an authenticated user context */ public function setUser(?\Illuminate\Contracts\Auth\Authenticatable $user): self; @@ -86,7 +86,7 @@ public function getRefreshToken(): ?string; /** * Set the refresh token for the request context, if available. * - * @param string $refreshToken Refresh token returned from the code exchange. + * @param string $refreshToken refresh token returned from the code exchange */ public function setRefreshToken(?string $refreshToken): self; } diff --git a/src/Event/Auth0Event.php b/src/Event/Auth0Event.php index 42b7cda4..e89d2ba4 100644 --- a/src/Event/Auth0Event.php +++ b/src/Event/Auth0Event.php @@ -17,7 +17,7 @@ abstract class Auth0Event implements \Auth0\Laravel\Contract\Event\Auth0Event /** * Returns whether an event payload has been overwritten. */ - public function wasMutated(): bool + final public function wasMutated(): bool { return $this->mutated; } diff --git a/src/Event/Configuration/Built.php b/src/Event/Configuration/Built.php index 1c793e62..54869b1c 100644 --- a/src/Event/Configuration/Built.php +++ b/src/Event/Configuration/Built.php @@ -14,7 +14,7 @@ final class Built extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Lara private SdkConfiguration $configuration; /** - * @inheritdoc + * {@inheritdoc} */ public function __construct(SdkConfiguration $configuration) { @@ -22,16 +22,17 @@ public function __construct(SdkConfiguration $configuration) } /** - * @inheritdoc + * {@inheritdoc} */ public function setConfiguration(SdkConfiguration $configuration): self { $this->configuration = $configuration; + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function getConfiguration(): SdkConfiguration { diff --git a/src/Event/Stateful/AuthenticationFailed.php b/src/Event/Stateful/AuthenticationFailed.php index 93c85dfa..cbb8434d 100644 --- a/src/Event/Stateful/AuthenticationFailed.php +++ b/src/Event/Stateful/AuthenticationFailed.php @@ -17,7 +17,7 @@ final class AuthenticationFailed extends \Auth0\Laravel\Event\Auth0Event impleme private bool $throwException = true; /** - * @inheritdoc + * {@inheritdoc} */ public function __construct(\Throwable $exception, bool $throwException = true) { @@ -26,17 +26,18 @@ public function __construct(\Throwable $exception, bool $throwException = true) } /** - * @inheritdoc + * {@inheritdoc} */ public function setException(\Throwable $exception): self { $this->exception = $exception; $this->mutated = true; + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function getException(): \Throwable { @@ -44,16 +45,17 @@ public function getException(): \Throwable } /** - * @inheritdoc + * {@inheritdoc} */ public function setThrowException(bool $throwException): self { $this->throwException = $throwException; + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function getThrowException(): bool { diff --git a/src/Event/Stateful/AuthenticationSucceeded.php b/src/Event/Stateful/AuthenticationSucceeded.php index 21db6fc2..e3ac789e 100644 --- a/src/Event/Stateful/AuthenticationSucceeded.php +++ b/src/Event/Stateful/AuthenticationSucceeded.php @@ -12,7 +12,7 @@ final class AuthenticationSucceeded extends \Auth0\Laravel\Event\Auth0Event impl private \Illuminate\Contracts\Auth\Authenticatable $user; /** - * @inheritdoc + * {@inheritdoc} */ public function __construct(\Illuminate\Contracts\Auth\Authenticatable $user) { @@ -20,17 +20,18 @@ public function __construct(\Illuminate\Contracts\Auth\Authenticatable $user) } /** - * @inheritdoc + * {@inheritdoc} */ public function setUser(\Illuminate\Contracts\Auth\Authenticatable $user): self { $this->user = $user; $this->mutated = true; + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function getUser(): \Illuminate\Contracts\Auth\Authenticatable { diff --git a/src/Exception/Stateful/CallbackException.php b/src/Exception/Stateful/CallbackException.php index 00d882e4..7f3f9f58 100644 --- a/src/Exception/Stateful/CallbackException.php +++ b/src/Exception/Stateful/CallbackException.php @@ -12,7 +12,7 @@ final class CallbackException extends \Exception implements \Auth0\SDK\Exception public const MSG_API_RESPONSE = '%s: %s'; /** - * @inheritdoc + * {@inheritdoc} */ public static function apiException(string $error, string $errorDescription): self { diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index b942634e..1e822526 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -7,7 +7,7 @@ final class Callback implements \Auth0\Laravel\Contract\Http\Controller\Stateful\Callback { /** - * @inheritdoc + * {@inheritdoc} */ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse { @@ -18,11 +18,11 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re } try { - if ($request->query('state') !== null && $request->query('code') !== null) { + if (null !== $request->query('state') && null !== $request->query('code')) { app(\Auth0\Laravel\Auth0::class)->getSdk()->exchange( null, $request->query('code'), - $request->query('state') + $request->query('state'), ); } } catch (\Throwable $exception) { @@ -38,12 +38,12 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re } } - if ($request->query('error') !== null && $request->query('error_description') !== null) { + if (null !== $request->query('error') && null !== $request->query('error_description')) { // Workaround to aid static analysis, due to the mixed formatting of the query() response: $error = $request->query('error', ''); $errorDescription = $request->query('error_description', ''); - $error = is_string($error) ? $error : ''; - $errorDescription = is_string($errorDescription) ? $errorDescription : ''; + $error = \is_string($error) ? $error : ''; + $errorDescription = \is_string($errorDescription) ? $errorDescription : ''; // Clear the local session via the Auth0-PHP SDK: app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); @@ -62,19 +62,19 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re } // Ensure we have a valid user: - $user = auth() - ->guard('auth0') - ->user(); + $user = auth()-> + guard('auth0')-> + user(); - if ($user !== null) { + if (null !== $user) { // Throw hookable event to allow custom application logic for successful logins: $event = new \Auth0\Laravel\Event\Stateful\AuthenticationSucceeded($user); event($event); // Apply any mutations to the user object: - auth() - ->guard('auth0') - ->setUser($event->getUser()); + auth()-> + guard('auth0')-> + setUser($event->getUser()); } return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); diff --git a/src/Http/Controller/Stateful/Login.php b/src/Http/Controller/Stateful/Login.php index 366d95e2..cead8bda 100644 --- a/src/Http/Controller/Stateful/Login.php +++ b/src/Http/Controller/Stateful/Login.php @@ -7,7 +7,7 @@ final class Login implements \Auth0\Laravel\Contract\Http\Controller\Stateful\Login { /** - * @inheritdoc + * {@inheritdoc} * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index 624e1552..71634bef 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -7,23 +7,23 @@ final class Logout implements \Auth0\Laravel\Contract\Http\Controller\Stateful\Logout { /** - * @inheritdoc + * {@inheritdoc} */ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse { if (auth()->guard('auth0')->check()) { - auth()->guard('auth0') - ->logout(); + auth()->guard('auth0')-> + logout(); - $request->session() - ->invalidate(); - $request->session() - ->regenerateToken(); + $request->session()-> + invalidate(); + $request->session()-> + regenerateToken(); return redirect()->away( app(\Auth0\Laravel\Auth0::class)->getSdk()->authentication()->getLogoutLink(url( - app()->make('config')->get('auth0.routes.home', '/') - )) + app()->make('config')->get('auth0.routes.home', '/'), + )), ); } diff --git a/src/Http/Middleware/Stateful/Authenticate.php b/src/Http/Middleware/Stateful/Authenticate.php index aaef10a5..64d993b6 100644 --- a/src/Http/Middleware/Stateful/Authenticate.php +++ b/src/Http/Middleware/Stateful/Authenticate.php @@ -12,17 +12,18 @@ final class Authenticate implements \Auth0\Laravel\Contract\Http\Middleware\Stateful\Authenticate { /** - * @inheritdoc + * {@inheritdoc} */ public function handle(\Illuminate\Http\Request $request, \Closure $next) { - $user = auth() - ->guard('auth0') - ->user(); + $user = auth()-> + guard('auth0')-> + user(); + + if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { + auth()->guard('auth0')-> + login($user); - if ($user !== null && $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { - auth()->guard('auth0') - ->login($user); return $next($request); } diff --git a/src/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Http/Middleware/Stateful/AuthenticateOptional.php index cdecea66..18f0a8aa 100644 --- a/src/Http/Middleware/Stateful/AuthenticateOptional.php +++ b/src/Http/Middleware/Stateful/AuthenticateOptional.php @@ -12,17 +12,17 @@ final class AuthenticateOptional implements \Auth0\Laravel\Contract\Http\Middleware\Stateful\AuthenticateOptional { /** - * @inheritdoc + * {@inheritdoc} */ public function handle(\Illuminate\Http\Request $request, \Closure $next) { - $user = auth() - ->guard('auth0') - ->user(); + $user = auth()-> + guard('auth0')-> + user(); - if ($user !== null && $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { - auth()->guard('auth0') - ->login($user); + if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { + auth()->guard('auth0')-> + login($user); } return $next($request); diff --git a/src/Http/Middleware/Stateless/Authorize.php b/src/Http/Middleware/Stateless/Authorize.php index 5a3102ba..078bf85c 100644 --- a/src/Http/Middleware/Stateless/Authorize.php +++ b/src/Http/Middleware/Stateless/Authorize.php @@ -11,21 +11,22 @@ final class Authorize implements \Auth0\Laravel\Contract\Http\Middleware\Stateless\Authorize { /** - * @inheritdoc + * {@inheritdoc} */ public function handle(\Illuminate\Http\Request $request, \Closure $next, string $scope = '') { - $user = auth() - ->guard('auth0') - ->user(); + $user = auth()-> + guard('auth0')-> + user(); - if ($user !== null && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { - if (strlen($scope) >= 1 && auth()->guard('auth0')->hasScope($scope) === false) { + if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { + if ('' !== $scope && false === auth()->guard('auth0')->hasScope($scope)) { return abort(403, 'Unauthorized'); } - auth() - ->login($user); + auth()-> + login($user); + return $next($request); } diff --git a/src/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Http/Middleware/Stateless/AuthorizeOptional.php index 43921c71..0d088883 100644 --- a/src/Http/Middleware/Stateless/AuthorizeOptional.php +++ b/src/Http/Middleware/Stateless/AuthorizeOptional.php @@ -10,17 +10,17 @@ final class AuthorizeOptional implements \Auth0\Laravel\Contract\Http\Middleware\Stateless\AuthorizeOptional { /** - * @inheritdoc + * {@inheritdoc} */ public function handle(\Illuminate\Http\Request $request, \Closure $next) { - $user = auth() - ->guard('auth0') - ->user(); + $user = auth()-> + guard('auth0')-> + user(); - if ($user !== null && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { - auth()->guard('auth0') - ->login($user); + if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { + auth()->guard('auth0')-> + login($user); } return $next($request); diff --git a/src/Model/User.php b/src/Model/User.php index afc9fea4..44f90b2f 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -12,7 +12,7 @@ abstract class User implements \Illuminate\Contracts\Auth\Authenticatable, \Auth private array $attributes = []; /** - * @inheritdoc + * {@inheritdoc} */ public function __construct(array $attributes = []) { @@ -20,7 +20,7 @@ public function __construct(array $attributes = []) } /** - * @inheritdoc + * {@inheritdoc} */ public function __get(string $key) { @@ -28,7 +28,7 @@ public function __get(string $key) } /** - * @inheritdoc + * {@inheritdoc} */ public function __set(string $key, $value): void { @@ -36,9 +36,9 @@ public function __set(string $key, $value): void } /** - * @inheritdoc + * {@inheritdoc} */ - public function fill(array $attributes): self + final public function fill(array $attributes): self { foreach ($attributes as $key => $value) { $this->setAttribute($key, $value); @@ -48,67 +48,68 @@ public function fill(array $attributes): self } /** - * @inheritdoc + * {@inheritdoc} */ - public function setAttribute(string $key, $value): self + final public function setAttribute(string $key, $value): self { $this->attributes[$key] = $value; + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ - public function getAttribute(string $key, $default = null) + final public function getAttribute(string $key, $default = null) { return $this->attributes[$key] ?? $default; } /** - * @inheritdoc + * {@inheritdoc} */ - public function getAuthIdentifier() + final public function getAuthIdentifier() { return $this->attributes['sub'] ?? $this->attributes['user_id'] ?? $this->attributes['email'] ?? null; } /** - * @inheritdoc + * {@inheritdoc} */ - public function getAuthIdentifierName() + final public function getAuthIdentifierName() { return 'id'; } /** - * @inheritdoc + * {@inheritdoc} */ - public function getAuthPassword(): string + final public function getAuthPassword(): string { return ''; } /** - * @inheritdoc + * {@inheritdoc} */ - public function getRememberToken(): string + final public function getRememberToken(): string { return ''; } /** - * @inheritdoc + * {@inheritdoc} * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ - public function setRememberToken($value): void + final public function setRememberToken($value): void { } /** - * @inheritdoc + * {@inheritdoc} */ - public function getRememberTokenName(): string + final public function getRememberTokenName(): string { return ''; } diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index fa65d7ec..278ea65f 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -7,37 +7,37 @@ final class ServiceProvider extends \Spatie\LaravelPackageTools\PackageServiceProvider implements \Auth0\Laravel\Contract\ServiceProvider { /** - * @inheritdoc + * {@inheritdoc} */ public function configurePackage(\Spatie\LaravelPackageTools\Package $package): void { - $package - ->name('auth0') - ->hasConfigFile(); + $package-> + name('auth0')-> + hasConfigFile(); } /** - * @inheritdoc + * {@inheritdoc} */ public function registeringPackage(): void { app()->singleton(Auth0::class, static fn (): \Auth0\Laravel\Auth0 => new Auth0()); - app() - ->singleton('auth0', static fn (): \Auth0\Laravel\Auth0 => app()->make(Auth0::class)); + app()-> + singleton('auth0', static fn (): \Auth0\Laravel\Auth0 => app()->make(Auth0::class)); - app() - ->singleton(StateInstance::class, static fn (): \Auth0\Laravel\StateInstance => new StateInstance()); + app()-> + singleton(StateInstance::class, static fn (): \Auth0\Laravel\StateInstance => new StateInstance()); - app() - ->singleton( + app()-> + singleton( \Auth0\Laravel\Auth\User\Repository::class, - static fn (): \Auth0\Laravel\Auth\User\Repository => new \Auth0\Laravel\Auth\User\Repository() + static fn (): \Auth0\Laravel\Auth\User\Repository => new \Auth0\Laravel\Auth\User\Repository(), ); } /** - * @inheritdoc + * {@inheritdoc} */ public function bootingPackage(): void { @@ -45,35 +45,35 @@ public function bootingPackage(): void 'auth0', static fn ($app, array $config): \Auth0\Laravel\Auth\User\Provider => new \Auth0\Laravel\Auth\User\Provider( app()->make( - $config['repository'] - ) - ) + $config['repository'], + ), + ), ); - auth() - ->extend( + auth()-> + extend( 'auth0', static fn ($app, $name, array $config): \Auth0\Laravel\Auth\Guard => new \Auth0\Laravel\Auth\Guard( auth()->createUserProvider( - $config['provider'] + $config['provider'], ), $app->make( - 'request' - ) - ) + 'request', + ), + ), ); - $router = app() - ->make(\Illuminate\Routing\Router::class); + $router = app()-> + make(\Illuminate\Routing\Router::class); $router->aliasMiddleware('auth0.authenticate', \Auth0\Laravel\Http\Middleware\Stateful\Authenticate::class); $router->aliasMiddleware( 'auth0.authenticate.optional', - \Auth0\Laravel\Http\Middleware\Stateful\AuthenticateOptional::class + \Auth0\Laravel\Http\Middleware\Stateful\AuthenticateOptional::class, ); $router->aliasMiddleware('auth0.authorize', \Auth0\Laravel\Http\Middleware\Stateless\Authorize::class); $router->aliasMiddleware( 'auth0.authorize.optional', - \Auth0\Laravel\Http\Middleware\Stateless\AuthorizeOptional::class + \Auth0\Laravel\Http\Middleware\Stateless\AuthorizeOptional::class, ); } } diff --git a/src/StateInstance.php b/src/StateInstance.php index 6eb6614a..9b2e1b4b 100644 --- a/src/StateInstance.php +++ b/src/StateInstance.php @@ -42,7 +42,7 @@ final class StateInstance implements \Auth0\Laravel\Contract\StateInstance private ?string $refreshToken = null; /** - * @inheritdoc + * {@inheritdoc} */ public function clear(): self { @@ -53,11 +53,12 @@ public function clear(): self $this->accessTokenScope = null; $this->accessTokenExpiration = null; $this->refreshToken = null; + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function getUser(): ?\Illuminate\Contracts\Auth\Authenticatable { @@ -65,16 +66,17 @@ public function getUser(): ?\Illuminate\Contracts\Auth\Authenticatable } /** - * @inheritdoc + * {@inheritdoc} */ public function setUser(?\Illuminate\Contracts\Auth\Authenticatable $user): self { $this->user = $user; + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function getDecoded(): ?array { @@ -82,16 +84,17 @@ public function getDecoded(): ?array } /** - * @inheritdoc + * {@inheritdoc} */ public function setDecoded(?array $data): self { $this->decoded = $data; + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function getIdToken(): ?string { @@ -99,16 +102,17 @@ public function getIdToken(): ?string } /** - * @inheritdoc + * {@inheritdoc} */ public function setIdToken(?string $idToken): self { $this->idToken = $idToken; + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function getAccessToken(): ?string { @@ -116,16 +120,17 @@ public function getAccessToken(): ?string } /** - * @inheritdoc + * {@inheritdoc} */ public function setAccessToken(?string $accessToken): self { $this->accessToken = $accessToken; + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function getAccessTokenScope(): ?array { @@ -133,16 +138,17 @@ public function getAccessTokenScope(): ?array } /** - * @inheritdoc + * {@inheritdoc} */ public function setAccessTokenScope(?array $accessTokenScope): self { $this->accessTokenScope = $accessTokenScope; + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function getAccessTokenExpiration(): ?int { @@ -150,22 +156,23 @@ public function getAccessTokenExpiration(): ?int } /** - * @inheritdoc + * {@inheritdoc} */ public function setAccessTokenExpiration(?int $accessTokenExpiration): self { $this->accessTokenExpiration = $accessTokenExpiration; + return $this; } /** - * @inheritdoc + * {@inheritdoc} */ public function getAccessTokenExpired(): ?bool { $expires = $this->getAccessTokenExpiration(); - if ($expires === null) { + if (null === $expires) { return null; } @@ -173,7 +180,7 @@ public function getAccessTokenExpired(): ?bool } /** - * @inheritdoc + * {@inheritdoc} */ public function getRefreshToken(): ?string { @@ -181,11 +188,12 @@ public function getRefreshToken(): ?string } /** - * @inheritdoc + * {@inheritdoc} */ public function setRefreshToken(?string $refreshToken): self { $this->refreshToken = $refreshToken; + return $this; } } diff --git a/src/Store/LaravelSession.php b/src/Store/LaravelSession.php index 40d06ea3..a1022b8d 100644 --- a/src/Store/LaravelSession.php +++ b/src/Store/LaravelSession.php @@ -17,7 +17,7 @@ final class LaravelSession implements StoreInterface /** * Instance of SdkConfiguration, for shared configuration across classes. */ - // @phpstan-ignore-next-line + /** @phpstan-ignore-next-line */ private SdkConfiguration $configuration; /** @@ -33,8 +33,8 @@ final class LaravelSession implements StoreInterface /** * Psr14Store constructor. * - * @param SdkConfiguration $configuration Base configuration options for the SDK. See the SdkConfiguration class constructor for options. - * @param string $sessionPrefix A string to prefix session keys with. + * @param SdkConfiguration $configuration Base configuration options for the SDK. See the SdkConfiguration class constructor for options. + * @param string $sessionPrefix a string to prefix session keys with */ public function __construct(SdkConfiguration $configuration, string $sessionPrefix = 'auth0') { @@ -45,39 +45,38 @@ public function __construct(SdkConfiguration $configuration, string $sessionPref /** * Dispatch event to toggle state deferrance. * - * @param bool $deferring Whether to defer persisting the storage state. + * @param bool $deferring whether to defer persisting the storage state */ public function defer(bool $deferring): void { - return; } /** * Dispatch event to set the value of a key-value pair. * - * @param string $key Session key to set. - * @param mixed $value Value to use. + * @param string $key session key to set + * @param mixed $value value to use */ public function set(string $key, $value): void { $this->boot(); - $this->getStore() - ->put($this->getPrefixedKey($key), $value); + $this->getStore()-> + put($this->getPrefixedKey($key), $value); } /** * Dispatch event to retrieve the value of a key-value pair. * - * @param string $key Session key to query. - * @param mixed $default Default to return if nothing was found. - * + * @param string $key session key to query + * @param mixed $default default to return if nothing was found * @return mixed */ public function get(string $key, $default = null) { $this->boot(); - return $this->getStore() - ->get($this->getPrefixedKey($key), $default); + + return $this->getStore()-> + get($this->getPrefixedKey($key), $default); } /** @@ -90,12 +89,12 @@ public function purge(): void // It would be unwise for us to simply flush() a session here, as it is shared with the app ecosystem. // Instead, iterate through the session data, and if they key is prefixed with our assigned string, delete it. - $pairs = $this->getStore() - ->all(); + $pairs = $this->getStore()-> + all(); $prefix = $this->sessionPrefix . '_'; foreach (array_keys($pairs) as $key) { - if (substr($key, 0, strlen($prefix)) === $prefix) { + if (mb_substr($key, 0, mb_strlen($prefix)) === $prefix) { $this->delete($key); } } @@ -104,13 +103,13 @@ public function purge(): void /** * Dispatch event to delete key-value pair. * - * @param string $key Session key to delete. + * @param string $key session key to delete */ public function delete(string $key): void { $this->boot(); - $this->getStore() - ->forget($this->getPrefixedKey($key)); + $this->getStore()-> + forget($this->getPrefixedKey($key)); } /** @@ -120,14 +119,12 @@ private function boot(): void { if (! $this->booted) { if (! $this->getStore()->isStarted()) { - $this->getStore() - ->start(); + $this->getStore()-> + start(); } $this->booted = true; } - - return; } private function getStore(): \Illuminate\Session\Store @@ -143,7 +140,7 @@ private function getStore(): \Illuminate\Session\Store private function getPrefixedKey(string $key): string { - if ($this->sessionPrefix !== '') { + if ('' !== $this->sessionPrefix) { return $this->sessionPrefix . '_' . $key; } diff --git a/src/Traits/ActingAsAuth0User.php b/src/Traits/ActingAsAuth0User.php index c77b5129..79a65b47 100644 --- a/src/Traits/ActingAsAuth0User.php +++ b/src/Traits/ActingAsAuth0User.php @@ -14,17 +14,17 @@ abstract public function actingAs(UserContract $user, $guard = null); /** * use this method to impersonate a specific auth0 user - * if you pass an attributes array, it will be merged with a set of default values + * if you pass an attributes array, it will be merged with a set of default values. * * @return mixed */ public function actingAsAuth0User(array $attributes = []) { $defaults = [ - 'sub' => 'some-auth0-user-id', - 'azp' => 'some-auth0-appplication-client-id', - 'iat' => time(), - 'exp' => time() + 60 * 60, + 'sub' => 'some-auth0-user-id', + 'azp' => 'some-auth0-appplication-client-id', + 'iat' => time(), + 'exp' => time() + 60 * 60, 'scope' => '', ]; diff --git a/tests/Pest.php b/tests/Pest.php index c560eadc..06296a49 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -2,38 +2,38 @@ declare(strict_types=1); -uses(\Auth0\Laravel\Tests\TestCase::class) - ->beforeEach(function () { +uses(\Auth0\Laravel\Tests\TestCase::class)-> + beforeEach(function (): void { $this->service = createService(); - }) - ->in(__DIR__); + }, )-> + in(__DIR__); function createServiceConfiguration( - array $configuration = [] -): \Auth0\SDK\Configuration\SdkConfiguration { + array $configuration = [], +): Auth0\SDK\Configuration\SdkConfiguration { $defaults = [ - 'strategy' => 'none' + 'strategy' => 'none', ]; return new \Auth0\SDK\Configuration\SdkConfiguration(array_merge($defaults, $configuration)); } function createService( - ?\Auth0\SDK\Configuration\SdkConfiguration $configuration = null -): \Auth0\Laravel\Auth0 { - if ($configuration === null) { + ?Auth0\SDK\Configuration\SdkConfiguration $configuration = null, +): Auth0\Laravel\Auth0 { + if (null === $configuration) { $configuration = createServiceConfiguration(); } - return (new \Auth0\Laravel\Auth0)->setConfiguration($configuration); + return (new \Auth0\Laravel\Auth0())->setConfiguration($configuration); } function createSdk( - ?\Auth0\SDK\Configuration\SdkConfiguration $configuration = null -): \Auth0\SDK\Auth0 { - if ($configuration === null) { + ?Auth0\SDK\Configuration\SdkConfiguration $configuration = null, +): Auth0\SDK\Auth0 { + if (null === $configuration) { $configuration = createServiceConfiguration(); } - return (new \Auth0\SDK\Auth0($configuration)); + return new \Auth0\SDK\Auth0($configuration); } diff --git a/tests/TestCase.php b/tests/TestCase.php index 1eb4c18f..7df2ef4a 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -13,15 +13,15 @@ protected function setUp(): void parent::setUp(); } + public function refreshServiceProvider(): void + { + (new \Auth0\Laravel\ServiceProvider($this->app))->packageBooted(); + } + protected function getPackageProviders($app) { return [ \Auth0\Laravel\ServiceProvider::class, ]; } - - public function refreshServiceProvider(): void - { - (new \Auth0\Laravel\ServiceProvider($this->app))->packageBooted(); - } } diff --git a/tests/Unit/Auth0Test.php b/tests/Unit/Auth0Test.php index 6464f0c3..d8a1de1a 100644 --- a/tests/Unit/Auth0Test.php +++ b/tests/Unit/Auth0Test.php @@ -2,53 +2,53 @@ declare(strict_types=1); -test('the service is created successfully', function() { - expect($this->service) - ->toBeInstanceOf(\Auth0\Laravel\Auth0::class); -}); - -test('the service instantiates it\'s own configuration if none is assigned', function() { - $service = new \Auth0\Laravel\Auth0; - - expect($service->getConfiguration()) - ->toBeInstanceOf(\Auth0\SDK\Configuration\SdkConfiguration::class); -})->throws(\Auth0\SDK\Exception\ConfigurationException::class); - -test('the service\'s getSdk() method returns an Auth0 SDK instance', function() { - expect($this->service->getSdk()) - ->toBeInstanceOf(\Auth0\SDK\Auth0::class); -}); - -test('the service\'s getConfiguration method returns an SdkConfiguration instance', function() { - expect($this->service->getConfiguration()) - ->toBeInstanceOf(\Auth0\SDK\Configuration\SdkConfiguration::class); -}); - -test('the service\'s getState method returns a StateInstance instance', function() { - expect($this->service->getState()) - ->toBeInstanceOf(\Auth0\Laravel\StateInstance::class); -}); - -test('the service\'s setSdk() method allows overwriting the Auth0 instance', function() { +test('the service is created successfully', function (): void { + expect($this->service)-> + toBeInstanceOf(\Auth0\Laravel\Auth0::class); +}, ); + +test('the service instantiates it\'s own configuration if none is assigned', function (): void { + $service = new \Auth0\Laravel\Auth0(); + + expect($service->getConfiguration())-> + toBeInstanceOf(\Auth0\SDK\Configuration\SdkConfiguration::class); +}, )->throws(\Auth0\SDK\Exception\ConfigurationException::class); + +test('the service\'s getSdk() method returns an Auth0 SDK instance', function (): void { + expect($this->service->getSdk())-> + toBeInstanceOf(\Auth0\SDK\Auth0::class); +}, ); + +test('the service\'s getConfiguration method returns an SdkConfiguration instance', function (): void { + expect($this->service->getConfiguration())-> + toBeInstanceOf(\Auth0\SDK\Configuration\SdkConfiguration::class); +}, ); + +test('the service\'s getState method returns a StateInstance instance', function (): void { + expect($this->service->getState())-> + toBeInstanceOf(\Auth0\Laravel\StateInstance::class); +}, ); + +test('the service\'s setSdk() method allows overwriting the Auth0 instance', function (): void { $oldSdk = $this->service->getSdk(); $newSdk = createSdk(); $this->service->setSdk($newSdk); - expect($this->service->getSdk()) - ->toBe($newSdk) - ->not() - ->toBe($oldSdk); -}); + expect($this->service->getSdk())-> + toBe($newSdk)-> + not()-> + toBe($oldSdk); +}, ); -test('the service\'s setConfiguration() method allows overwriting the SdkConfiguration instance', function() { +test('the service\'s setConfiguration() method allows overwriting the SdkConfiguration instance', function (): void { $oldConfiguration = $this->service->getConfiguration(); $newConfiguration = createServiceConfiguration(); $this->service->setConfiguration($newConfiguration); - expect($this->service->getConfiguration()) - ->toBe($newConfiguration) - ->not() - ->toBe($oldConfiguration); -}); + expect($this->service->getConfiguration())-> + toBe($newConfiguration)-> + not()-> + toBe($oldConfiguration); +}, ); diff --git a/tests/constants.php b/tests/constants.php index d0505384..bf70fd4e 100644 --- a/tests/constants.php +++ b/tests/constants.php @@ -6,15 +6,14 @@ * Laravel polyfills, since we don't want to test against the complete framework suite, * just fill in the method gaps with placeholders. */ - if (! function_exists('auth')) { - function auth(... $params) { - + function auth(...$params): void + { } } if (! function_exists('abort')) { - function abort(... $params) { - + function abort(...$params): void + { } } From 4ca5641ef97a0dc89d32b8ba787c01c86a0a41f3 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Oct 2022 20:18:20 -0500 Subject: [PATCH 124/525] Reintroduce Psalm and fix linter warnings --- .github/workflows/tests.yml | 42 +++++++++++++++++ composer.json | 2 + psalm.xml.dist | 10 ++--- src/Auth/Guard.php | 45 ++++++++++--------- src/Auth0.php | 4 ++ src/Configuration.php | 2 +- src/Contract/Auth/Guard.php | 24 +++++++++- src/Http/Controller/Stateful/Callback.php | 39 +++++++++++----- src/Http/Controller/Stateful/Login.php | 16 ++++++- src/Http/Controller/Stateful/Logout.php | 19 ++++++-- src/Http/Middleware/Stateful/Authenticate.php | 21 ++++++--- .../Stateful/AuthenticateOptional.php | 21 ++++++--- src/Http/Middleware/Stateless/Authorize.php | 27 +++++++---- .../Stateless/AuthorizeOptional.php | 21 ++++++--- src/ServiceProvider.php | 5 +++ 15 files changed, 231 insertions(+), 67 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9df9d037..e811636d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -132,6 +132,48 @@ jobs: - name: Execute PHPStan run: vendor/bin/phpstan analyze --no-progress + psalm: + name: Psalm + runs-on: ubuntu-latest + needs: ["dependencies"] + + strategy: + fail-fast: true + max-parallel: 10 + matrix: + php: ["7.4", "8.0", "8.1", "8.2"] + + steps: + - name: Set up PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + extensions: mbstring + env: + update: true + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + + - name: Install dependencies + run: composer install --prefer-dist + + - name: Execute Psalm + run: vendor/bin/psalm --no-progress + pint: name: Laravel Pint runs-on: ubuntu-latest diff --git a/composer.json b/composer.json index 92f3d860..a16f1a4c 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,9 @@ "phpstan/phpstan": "^1.7", "phpstan/phpstan-strict-rules": "1.4.3", "phpunit/phpunit": "^9.5", + "psalm/plugin-laravel": "^2.0", "rector/rector": "^0.13.6", + "vimeo/psalm": "^4.28", "wikimedia/composer-merge-plugin": "^2.0" }, "autoload": { diff --git a/psalm.xml.dist b/psalm.xml.dist index 06744c2b..e469154a 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -11,7 +11,6 @@ - @@ -19,8 +18,9 @@ - - - - + + + + + diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index b41f0052..d3b4616e 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -4,6 +4,8 @@ namespace Auth0\Laravel\Auth; +use Auth0\Laravel\Contract\Auth\User\Provider; + final class Guard implements \Auth0\Laravel\Contract\Auth\Guard, \Illuminate\Contracts\Auth\Guard { /** @@ -81,10 +83,10 @@ public function user(): ?\Illuminate\Contracts\Auth\Authenticatable public function id() { $response = null; + $user = $this->user(); - if (null !== $this->user()) { - $id = $this->user()-> - getAuthIdentifier(); + if (null !== $user) { + $id = $user->getAuthIdentifier(); if (\is_string($id) || \is_int($id)) { $response = $id; @@ -106,6 +108,8 @@ public function validate(array $credentials = []): bool /** * {@inheritdoc} + * + * @psalm-suppress UnusedVariable */ public function setUser(\Illuminate\Contracts\Auth\Authenticatable $user): self { @@ -157,14 +161,8 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable try { // Attempt to decode the bearer token. $decoded = app(\Auth0\Laravel\Auth0::class)->getSdk()->decode( - $token, - null, - null, - null, - null, - null, - null, - \Auth0\SDK\Token::TYPE_TOKEN, + token: $token, + tokenType: \Auth0\SDK\Token::TYPE_TOKEN )->toArray(); } catch (\Auth0\SDK\Exception\InvalidTokenException $invalidToken) { // Invalid bearer token. @@ -172,16 +170,18 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable } // Query the UserProvider to retrieve tue user for the token. - $user = $this->getProvider()-> + $provider = $this->getProvider(); + + /** + * @var Provider $provider + */ + + $user = $provider-> getRepository()-> fromAccessToken($decoded); // Was a user retrieved successfully? if (null !== $user) { - if (! $user instanceof \Illuminate\Contracts\Auth\Authenticatable) { - exit('User model returned fromAccessToken must implement \Illuminate\Contracts\Auth\Authenticatable.'); - } - if (! $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { exit('User model returned fromAccessToken must implement \Auth0\Laravel\Contract\Model\Stateless\User.'); } @@ -210,17 +210,20 @@ private function getUserFromSession(): ?\Illuminate\Contracts\Auth\Authenticatab return null; } + // Query the UserProvider to retrieve tue user for the token. + $provider = $this->getProvider(); + + /** + * @var Provider $provider + */ + // Query the UserProvider to retrieve tue user for the session. - $user = $this->getProvider()-> + $user = $provider-> getRepository()-> fromSession($session->user); // Was a user retrieved successfully? if (null !== $user) { - if (! $user instanceof \Illuminate\Contracts\Auth\Authenticatable) { - exit('User model returned fromSession must implement \Illuminate\Contracts\Auth\Authenticatable.'); - } - if (! $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { exit('User model returned fromSession must implement \Auth0\Laravel\Contract\Model\Stateful\User.'); } diff --git a/src/Auth0.php b/src/Auth0.php index d721c215..543870c4 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -61,6 +61,10 @@ public function getConfiguration(): \Auth0\SDK\Configuration\SdkConfiguration make('config')-> get('auth0'); + /** + * @var array $config + */ + if (! isset($config['tokenCache']) || ! isset($config['managementTokenCache'])) { $cache = new LaravelCachePool(); diff --git a/src/Configuration.php b/src/Configuration.php index d6ac44ce..99da8956 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -18,7 +18,7 @@ public static function stringToArrayOrNull(?string $config, string $delimiter = $response = explode($delimiter, $config); // @phpstan-ignore-next-line - if (\is_array($response) && \count($response) >= 1 && '' !== trim($response[0])) { + if (\count($response) >= 1 && '' !== trim($response[0])) { return $response; } } diff --git a/src/Contract/Auth/Guard.php b/src/Contract/Auth/Guard.php index 4dfd5381..c4a4f009 100644 --- a/src/Contract/Auth/Guard.php +++ b/src/Contract/Auth/Guard.php @@ -4,6 +4,8 @@ namespace Auth0\Laravel\Contract\Auth; +use Illuminate\Contracts\Auth\Authenticatable; + interface Guard { /** @@ -17,7 +19,7 @@ public function __construct( /** * Set the current user. */ - public function login(\Illuminate\Contracts\Auth\Authenticatable $user): self; + public function login(Authenticatable $user): self; /** * Clear the current user. @@ -32,5 +34,23 @@ public function hasUser(): bool; /** * Get the currently authenticated user. */ - public function user(): ?\Illuminate\Contracts\Auth\Authenticatable; + public function user(): ?Authenticatable; + + /** + * Set the currently authenticated user. + */ + public function setUser(Authenticatable $user): self; + + /** + * Determine if an authenticated user is available. + */ + public function check(): bool; + + /** + * Returns true if the given user has the specified scope. + * + * @param string $scope + * @return bool + */ + public function hasScope(string $scope): bool; } diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index 1e822526..6a0e19ca 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -4,6 +4,8 @@ namespace Auth0\Laravel\Http\Controller\Stateful; +use Auth0\Laravel\Contract\Auth\Guard; + final class Callback implements \Auth0\Laravel\Contract\Http\Controller\Stateful\Callback { /** @@ -11,18 +13,37 @@ final class Callback implements \Auth0\Laravel\Contract\Http\Controller\Stateful */ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse { + $auth = auth(); + + /** + * @var \Illuminate\Contracts\Auth\Factory $auth + */ + + $guard = $auth->guard('auth0'); + + /** + * @var Guard $guard + */ + // Check if the user already has a session: - if (auth()->guard('auth0')->check()) { + if ($guard->check()) { // They do; redirect to homepage. return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); } + $code = (is_string($request->query('code')) && '' !== $request->query('code')) ? $request->query('code') : null; + $state = (is_string($request->query('state')) && '' !== $request->query('state')) ? $request->query('state') : null; + + /** + * @var string|null $code + * @var string|null $state + */ + try { - if (null !== $request->query('state') && null !== $request->query('code')) { + if (null !== $code && null !== $state) { app(\Auth0\Laravel\Auth0::class)->getSdk()->exchange( - null, - $request->query('code'), - $request->query('state'), + code: $code, + state: $state ); } } catch (\Throwable $exception) { @@ -62,9 +83,7 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re } // Ensure we have a valid user: - $user = auth()-> - guard('auth0')-> - user(); + $user = $guard->user(); if (null !== $user) { // Throw hookable event to allow custom application logic for successful logins: @@ -72,9 +91,7 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re event($event); // Apply any mutations to the user object: - auth()-> - guard('auth0')-> - setUser($event->getUser()); + $guard->setUser($event->getUser()); } return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); diff --git a/src/Http/Controller/Stateful/Login.php b/src/Http/Controller/Stateful/Login.php index cead8bda..e958c782 100644 --- a/src/Http/Controller/Stateful/Login.php +++ b/src/Http/Controller/Stateful/Login.php @@ -4,6 +4,8 @@ namespace Auth0\Laravel\Http\Controller\Stateful; +use Auth0\Laravel\Contract\Auth\Guard; + final class Login implements \Auth0\Laravel\Contract\Http\Controller\Stateful\Login { /** @@ -13,7 +15,19 @@ final class Login implements \Auth0\Laravel\Contract\Http\Controller\Stateful\Lo */ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse { - if (auth()->guard('auth0')->check()) { + $auth = auth(); + + /** + * @var \Illuminate\Contracts\Auth\Factory $auth + */ + + $guard = $auth->guard('auth0'); + + /** + * @var Guard $guard + */ + + if ($guard->check()) { return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); } diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index 71634bef..1c21aebe 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -4,6 +4,8 @@ namespace Auth0\Laravel\Http\Controller\Stateful; +use Auth0\Laravel\Contract\Auth\Guard; + final class Logout implements \Auth0\Laravel\Contract\Http\Controller\Stateful\Logout { /** @@ -11,9 +13,20 @@ final class Logout implements \Auth0\Laravel\Contract\Http\Controller\Stateful\L */ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse { - if (auth()->guard('auth0')->check()) { - auth()->guard('auth0')-> - logout(); + $auth = auth(); + + /** + * @var \Illuminate\Contracts\Auth\Factory $auth + */ + + $guard = $auth->guard('auth0'); + + /** + * @var Guard $guard + */ + + if ($guard->check()) { + $guard->logout(); $request->session()-> invalidate(); diff --git a/src/Http/Middleware/Stateful/Authenticate.php b/src/Http/Middleware/Stateful/Authenticate.php index 64d993b6..1ad7c500 100644 --- a/src/Http/Middleware/Stateful/Authenticate.php +++ b/src/Http/Middleware/Stateful/Authenticate.php @@ -4,6 +4,8 @@ namespace Auth0\Laravel\Http\Middleware\Stateful; +use Auth0\Laravel\Contract\Auth\Guard; + /** * This middleware will configure the authenticated user for the session using a * previously established Auth0-PHP SDK session. If a session is not available, @@ -16,13 +18,22 @@ final class Authenticate implements \Auth0\Laravel\Contract\Http\Middleware\Stat */ public function handle(\Illuminate\Http\Request $request, \Closure $next) { - $user = auth()-> - guard('auth0')-> - user(); + $auth = auth(); + + /** + * @var \Illuminate\Contracts\Auth\Factory $auth + */ + + $guard = $auth->guard('auth0'); + + /** + * @var Guard $guard + */ + + $user = $guard->user(); if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { - auth()->guard('auth0')-> - login($user); + $guard->login($user); return $next($request); } diff --git a/src/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Http/Middleware/Stateful/AuthenticateOptional.php index 18f0a8aa..5758e959 100644 --- a/src/Http/Middleware/Stateful/AuthenticateOptional.php +++ b/src/Http/Middleware/Stateful/AuthenticateOptional.php @@ -4,6 +4,8 @@ namespace Auth0\Laravel\Http\Middleware\Stateful; +use Auth0\Laravel\Contract\Auth\Guard; + /** * This middleware will configure the authenticated user for the session using a * previously established Auth0-PHP SDK session. If a session is not available, @@ -16,13 +18,22 @@ final class AuthenticateOptional implements \Auth0\Laravel\Contract\Http\Middlew */ public function handle(\Illuminate\Http\Request $request, \Closure $next) { - $user = auth()-> - guard('auth0')-> - user(); + $auth = auth(); + + /** + * @var \Illuminate\Contracts\Auth\Factory $auth + */ + + $guard = $auth->guard('auth0'); + + /** + * @var Guard $guard + */ + + $user = $guard->user(); if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { - auth()->guard('auth0')-> - login($user); + $guard->login($user); } return $next($request); diff --git a/src/Http/Middleware/Stateless/Authorize.php b/src/Http/Middleware/Stateless/Authorize.php index 078bf85c..6756630c 100644 --- a/src/Http/Middleware/Stateless/Authorize.php +++ b/src/Http/Middleware/Stateless/Authorize.php @@ -4,6 +4,8 @@ namespace Auth0\Laravel\Http\Middleware\Stateless; +use Auth0\Laravel\Contract\Auth\Guard; + /** * This middleware will configure the authenticated user using an available access token. * If a token is not available, it will raise an exception. @@ -15,21 +17,30 @@ final class Authorize implements \Auth0\Laravel\Contract\Http\Middleware\Statele */ public function handle(\Illuminate\Http\Request $request, \Closure $next, string $scope = '') { - $user = auth()-> - guard('auth0')-> - user(); + $auth = auth(); + + /** + * @var \Illuminate\Contracts\Auth\Factory $auth + */ + + $guard = $auth->guard('auth0'); + + /** + * @var Guard $guard + */ + + $user = $guard->user(); if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { - if ('' !== $scope && false === auth()->guard('auth0')->hasScope($scope)) { - return abort(403, 'Unauthorized'); + if ('' !== $scope && false === $guard->hasScope($scope)) { + abort(403, 'Forbidden'); } - auth()-> - login($user); + $guard->login($user); return $next($request); } - return abort(403, 'Unauthorized'); + abort(401, 'Unauthorized'); } } diff --git a/src/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Http/Middleware/Stateless/AuthorizeOptional.php index 0d088883..92fb1cff 100644 --- a/src/Http/Middleware/Stateless/AuthorizeOptional.php +++ b/src/Http/Middleware/Stateless/AuthorizeOptional.php @@ -4,6 +4,8 @@ namespace Auth0\Laravel\Http\Middleware\Stateless; +use Auth0\Laravel\Contract\Auth\Guard; + /** * This middleware will configure the authenticated user using an available access token. */ @@ -14,13 +16,22 @@ final class AuthorizeOptional implements \Auth0\Laravel\Contract\Http\Middleware */ public function handle(\Illuminate\Http\Request $request, \Closure $next) { - $user = auth()-> - guard('auth0')-> - user(); + $auth = auth(); + + /** + * @var \Illuminate\Contracts\Auth\Factory $auth + */ + + $guard = $auth->guard('auth0'); + + /** + * @var Guard $guard + */ + + $user = $guard->user(); if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { - auth()->guard('auth0')-> - login($user); + $guard->login($user); } return $next($request); diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 278ea65f..eac91936 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -4,6 +4,9 @@ namespace Auth0\Laravel; +/** + * @psalm-suppress PropertyNotSetInConstructor + */ final class ServiceProvider extends \Spatie\LaravelPackageTools\PackageServiceProvider implements \Auth0\Laravel\Contract\ServiceProvider { /** @@ -38,6 +41,8 @@ public function registeringPackage(): void /** * {@inheritdoc} + * + * @psalm-suppress UndefinedInterfaceMethod */ public function bootingPackage(): void { From efb63fd9289b50653103be8831a6872528eeee28 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Oct 2022 20:18:49 -0500 Subject: [PATCH 125/525] Psalm: Remove 7.4 test --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e811636d..643b1a30 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -141,7 +141,7 @@ jobs: fail-fast: true max-parallel: 10 matrix: - php: ["7.4", "8.0", "8.1", "8.2"] + php: "8.0", "8.1", "8.2"] steps: - name: Set up PHP ${{ matrix.php }} From a85e4bab64307f11c2ee77e99dabaa915647a502 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Oct 2022 20:19:14 -0500 Subject: [PATCH 126/525] Typo fix --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 643b1a30..ff0a89c3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -141,7 +141,7 @@ jobs: fail-fast: true max-parallel: 10 matrix: - php: "8.0", "8.1", "8.2"] + php: ["8.0", "8.1", "8.2"] steps: - name: Set up PHP ${{ matrix.php }} From f612aacc8dbd600bc30997209dda2b7f6551c95b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Oct 2022 20:20:40 -0500 Subject: [PATCH 127/525] Typo fix --- .github/workflows/security.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 85d8ea84..b7f2badc 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -13,7 +13,7 @@ jobs: strategy: max-parallel: 10 matrix: - php: "8.0", "8.1", "8.2"] + php: ["8.0", "8.1", "8.2"] if: (github.actor != 'dependabot[bot]') steps: @@ -70,7 +70,6 @@ jobs: SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} SEMGREP_REPO_NAME: "auth0/laravel-auth0" SEMGREP_REPO_URL: "https://github.com/auth0/laravel-auth0" - # - name: Check to see if the SARIF a was generated # id: sarif_file_exists # uses: andstor/file-existence-action@v1 From f309c989fd78fb5a109de2103db82110ff025203 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Oct 2022 20:23:52 -0500 Subject: [PATCH 128/525] Code style fixes --- src/Http/Middleware/Stateless/Authorize.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Middleware/Stateless/Authorize.php b/src/Http/Middleware/Stateless/Authorize.php index 6756630c..4ee14d38 100644 --- a/src/Http/Middleware/Stateless/Authorize.php +++ b/src/Http/Middleware/Stateless/Authorize.php @@ -32,7 +32,7 @@ public function handle(\Illuminate\Http\Request $request, \Closure $next, string $user = $guard->user(); if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { - if ('' !== $scope && false === $guard->hasScope($scope)) { + if ('' !== $scope && !$guard->hasScope($scope)) { abort(403, 'Forbidden'); } From f66e4782585d14917580a260c27460b08b390326 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Oct 2022 20:26:21 -0500 Subject: [PATCH 129/525] Apply fixes from StyleCI (#310) Co-authored-by: StyleCI Bot --- src/Auth/Guard.php | 3 +-- src/Auth0.php | 1 - src/Contract/Auth/Guard.php | 3 --- src/Http/Controller/Stateful/Callback.php | 9 ++++----- src/Http/Controller/Stateful/Login.php | 2 -- src/Http/Controller/Stateful/Logout.php | 2 -- src/Http/Middleware/Stateful/Authenticate.php | 2 -- src/Http/Middleware/Stateful/AuthenticateOptional.php | 2 -- src/Http/Middleware/Stateless/Authorize.php | 4 +--- src/Http/Middleware/Stateless/AuthorizeOptional.php | 2 -- 10 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index d3b4616e..083c876c 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -162,7 +162,7 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable // Attempt to decode the bearer token. $decoded = app(\Auth0\Laravel\Auth0::class)->getSdk()->decode( token: $token, - tokenType: \Auth0\SDK\Token::TYPE_TOKEN + tokenType: \Auth0\SDK\Token::TYPE_TOKEN, )->toArray(); } catch (\Auth0\SDK\Exception\InvalidTokenException $invalidToken) { // Invalid bearer token. @@ -175,7 +175,6 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable /** * @var Provider $provider */ - $user = $provider-> getRepository()-> fromAccessToken($decoded); diff --git a/src/Auth0.php b/src/Auth0.php index 543870c4..c26a6c43 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -64,7 +64,6 @@ public function getConfiguration(): \Auth0\SDK\Configuration\SdkConfiguration /** * @var array $config */ - if (! isset($config['tokenCache']) || ! isset($config['managementTokenCache'])) { $cache = new LaravelCachePool(); diff --git a/src/Contract/Auth/Guard.php b/src/Contract/Auth/Guard.php index c4a4f009..44e04105 100644 --- a/src/Contract/Auth/Guard.php +++ b/src/Contract/Auth/Guard.php @@ -48,9 +48,6 @@ public function check(): bool; /** * Returns true if the given user has the specified scope. - * - * @param string $scope - * @return bool */ public function hasScope(string $scope): bool; } diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index 6a0e19ca..02677d10 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -18,7 +18,6 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re /** * @var \Illuminate\Contracts\Auth\Factory $auth */ - $guard = $auth->guard('auth0'); /** @@ -31,10 +30,10 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); } - $code = (is_string($request->query('code')) && '' !== $request->query('code')) ? $request->query('code') : null; - $state = (is_string($request->query('state')) && '' !== $request->query('state')) ? $request->query('state') : null; + $code = (\is_string($request->query('code')) && '' !== $request->query('code')) ? $request->query('code') : null; + $state = (\is_string($request->query('state')) && '' !== $request->query('state')) ? $request->query('state') : null; - /** + /* * @var string|null $code * @var string|null $state */ @@ -43,7 +42,7 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re if (null !== $code && null !== $state) { app(\Auth0\Laravel\Auth0::class)->getSdk()->exchange( code: $code, - state: $state + state: $state, ); } } catch (\Throwable $exception) { diff --git a/src/Http/Controller/Stateful/Login.php b/src/Http/Controller/Stateful/Login.php index e958c782..3723adce 100644 --- a/src/Http/Controller/Stateful/Login.php +++ b/src/Http/Controller/Stateful/Login.php @@ -20,13 +20,11 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re /** * @var \Illuminate\Contracts\Auth\Factory $auth */ - $guard = $auth->guard('auth0'); /** * @var Guard $guard */ - if ($guard->check()) { return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); } diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index 1c21aebe..141a2c13 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -18,13 +18,11 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re /** * @var \Illuminate\Contracts\Auth\Factory $auth */ - $guard = $auth->guard('auth0'); /** * @var Guard $guard */ - if ($guard->check()) { $guard->logout(); diff --git a/src/Http/Middleware/Stateful/Authenticate.php b/src/Http/Middleware/Stateful/Authenticate.php index 1ad7c500..b4f6113d 100644 --- a/src/Http/Middleware/Stateful/Authenticate.php +++ b/src/Http/Middleware/Stateful/Authenticate.php @@ -23,13 +23,11 @@ public function handle(\Illuminate\Http\Request $request, \Closure $next) /** * @var \Illuminate\Contracts\Auth\Factory $auth */ - $guard = $auth->guard('auth0'); /** * @var Guard $guard */ - $user = $guard->user(); if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { diff --git a/src/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Http/Middleware/Stateful/AuthenticateOptional.php index 5758e959..f34cd340 100644 --- a/src/Http/Middleware/Stateful/AuthenticateOptional.php +++ b/src/Http/Middleware/Stateful/AuthenticateOptional.php @@ -23,13 +23,11 @@ public function handle(\Illuminate\Http\Request $request, \Closure $next) /** * @var \Illuminate\Contracts\Auth\Factory $auth */ - $guard = $auth->guard('auth0'); /** * @var Guard $guard */ - $user = $guard->user(); if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { diff --git a/src/Http/Middleware/Stateless/Authorize.php b/src/Http/Middleware/Stateless/Authorize.php index 4ee14d38..5a0121a5 100644 --- a/src/Http/Middleware/Stateless/Authorize.php +++ b/src/Http/Middleware/Stateless/Authorize.php @@ -22,17 +22,15 @@ public function handle(\Illuminate\Http\Request $request, \Closure $next, string /** * @var \Illuminate\Contracts\Auth\Factory $auth */ - $guard = $auth->guard('auth0'); /** * @var Guard $guard */ - $user = $guard->user(); if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { - if ('' !== $scope && !$guard->hasScope($scope)) { + if ('' !== $scope && ! $guard->hasScope($scope)) { abort(403, 'Forbidden'); } diff --git a/src/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Http/Middleware/Stateless/AuthorizeOptional.php index 92fb1cff..7ae90280 100644 --- a/src/Http/Middleware/Stateless/AuthorizeOptional.php +++ b/src/Http/Middleware/Stateless/AuthorizeOptional.php @@ -21,13 +21,11 @@ public function handle(\Illuminate\Http\Request $request, \Closure $next) /** * @var \Illuminate\Contracts\Auth\Factory $auth */ - $guard = $auth->guard('auth0'); /** * @var Guard $guard */ - $user = $guard->user(); if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { From 31dafc40e54384c7004820dd18f223905d1dc4e7 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Oct 2022 20:30:47 -0500 Subject: [PATCH 130/525] Code quality improvements --- src/Http/Controller/Stateful/Callback.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index 02677d10..44ce2da3 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -30,8 +30,16 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); } - $code = (\is_string($request->query('code')) && '' !== $request->query('code')) ? $request->query('code') : null; - $state = (\is_string($request->query('state')) && '' !== $request->query('state')) ? $request->query('state') : null; + $code = $request->query('code'); + $state = $request->query('state'); + + if (! is_string($code) || '' === $code) { + $code = null; + } + + if (! is_string($state) || '' === $state) { + $state = null; + } /* * @var string|null $code From 72465fa6cfd8e0ec0923daf8712ba4c56ea62425 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Oct 2022 20:31:47 -0500 Subject: [PATCH 131/525] Apply fixes from StyleCI (#311) Co-authored-by: StyleCI Bot --- src/Http/Controller/Stateful/Callback.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index 44ce2da3..63c88141 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -33,11 +33,11 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re $code = $request->query('code'); $state = $request->query('state'); - if (! is_string($code) || '' === $code) { + if (! \is_string($code) || '' === $code) { $code = null; } - if (! is_string($state) || '' === $state) { + if (! \is_string($state) || '' === $state) { $state = null; } From e0b0dee3458a20d22a1793fa926b6206dabe39da Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Oct 2022 20:49:17 -0500 Subject: [PATCH 132/525] Ensure session regeneration happens immediately after callback --- src/Http/Controller/Stateful/Callback.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index 63c88141..cc56f895 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -93,6 +93,8 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re $user = $guard->user(); if (null !== $user) { + $request->session()->regenerate(); + // Throw hookable event to allow custom application logic for successful logins: $event = new \Auth0\Laravel\Event\Stateful\AuthenticationSucceeded($user); event($event); From 73db3a1bfc27a946b386b2d9fb6a44864267099e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 11 Oct 2022 11:25:20 -0500 Subject: [PATCH 133/525] Release 7.2.0 (#312) --- CHANGELOG.md | 7 +++++++ src/Auth0.php | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b62a3f8b..f6ab1006 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## [7.2.0](https://github.com/auth0/laravel-auth0/tree/7.2.0) (2022-10-10) +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.1.0...7.2.0) + +**Changed** +- [SDK-3669] Add StoreInterface bridge for Laravel Sessions [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims)) +- Added viaRemember function to guard [\#306](https://github.com/auth0/laravel-auth0/pull/306) ([tonyfox-disguise](https://github.com/tonyfox-disguise)) + ## [7.1.0](https://github.com/auth0/laravel-auth0/tree/7.1.0) (2022-08-08) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.0.1...7.1.0) diff --git a/src/Auth0.php b/src/Auth0.php index c26a6c43..ee2da227 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -15,7 +15,7 @@ final class Auth0 implements \Auth0\Laravel\Contract\Auth0 /** * The Laravel-Auth0 SDK version:. */ - public const VERSION = '7.1.0'; + public const VERSION = '7.2.0'; /** * An instance of the Auth0-PHP SDK. From 636f6a1257608623fc3bea676328d30b351ff074 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 11 Oct 2022 11:42:23 -0500 Subject: [PATCH 134/525] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6ab1006..e563d116 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,10 @@ [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.1.0...7.2.0) **Changed** -- [SDK-3669] Add StoreInterface bridge for Laravel Sessions [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims)) -- Added viaRemember function to guard [\#306](https://github.com/auth0/laravel-auth0/pull/306) ([tonyfox-disguise](https://github.com/tonyfox-disguise)) +- `Auth0\Laravel\Store\LaravelSession` has been added as the default `sessionStorage` and `transientStorage` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native Laravel Session APIs by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims)) +- `Auth0\Laravel\Cache\LaravelCachePool` and `Auth0\Laravel\Cache\ LaravelCacheItem` have been added as the default `tokenCache` and `managementTokenCache` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native Laravel Cache APIs by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims)) +- `Auth0\Laravel\Auth\Guard` now supports viaRemember [\#306](https://github.com/auth0/laravel-auth0/pull/306) ([tonyfox-disguise](https://github.com/tonyfox-disguise)) +- `Auth0\Laravel\Http\Middleware\Stateless\Authorize` now returns a 401 status instead of 403 for unauthenticated users. [\#304](https://github.com/auth0/laravel-auth0/issues/304) ([jeovajr](https://github.com/jeovajr)) ## [7.1.0](https://github.com/auth0/laravel-auth0/tree/7.1.0) (2022-08-08) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.0.1...7.1.0) From 3347d584a9e47dab35a6f16d1955d280df642f30 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 11 Oct 2022 11:50:07 -0500 Subject: [PATCH 135/525] Update CHANGELOG.md --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e563d116..c1389be7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,16 @@ ## [7.2.0](https://github.com/auth0/laravel-auth0/tree/7.2.0) (2022-10-10) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.1.0...7.2.0) +Thank you to [tonyfox-disguise](https://github.com/tonyfox-disguise), [jeovajr](https://github.com/jeovajr) and [nie7321](https://github.com/nie7321) for their contributions to this release. + **Changed** -- `Auth0\Laravel\Store\LaravelSession` has been added as the default `sessionStorage` and `transientStorage` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native Laravel Session APIs by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims)) +- `Auth0\Laravel\Store\LaravelSession` has been added as the default `sessionStorage` and `transientStorage` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native Laravel Session APIs by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims))¹ - `Auth0\Laravel\Cache\LaravelCachePool` and `Auth0\Laravel\Cache\ LaravelCacheItem` have been added as the default `tokenCache` and `managementTokenCache` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native Laravel Cache APIs by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims)) - `Auth0\Laravel\Auth\Guard` now supports viaRemember [\#306](https://github.com/auth0/laravel-auth0/pull/306) ([tonyfox-disguise](https://github.com/tonyfox-disguise)) - `Auth0\Laravel\Http\Middleware\Stateless\Authorize` now returns a 401 status instead of 403 for unauthenticated users. [\#304](https://github.com/auth0/laravel-auth0/issues/304) ([jeovajr](https://github.com/jeovajr)) +- PHP 8.0 and Laravel 8.0 are now the minimum supported runtime and framework versions. Please review our [support matrix](https://github.com/auth0/laravel-auth0#requirements) for more information. + +¹ This change may require your application's users to reauthenticate. ## [7.1.0](https://github.com/auth0/laravel-auth0/tree/7.1.0) (2022-08-08) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.0.1...7.1.0) From 1193a32390bb50dea91e454e28e07e5133b0b0e4 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 11 Oct 2022 11:54:49 -0500 Subject: [PATCH 136/525] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1389be7..debddc0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ Thank you to [tonyfox-disguise](https://github.com/tonyfox-disguise), [jeovajr]( - `Auth0\Laravel\Http\Middleware\Stateless\Authorize` now returns a 401 status instead of 403 for unauthenticated users. [\#304](https://github.com/auth0/laravel-auth0/issues/304) ([jeovajr](https://github.com/jeovajr)) - PHP 8.0 and Laravel 8.0 are now the minimum supported runtime and framework versions. Please review our [support matrix](https://github.com/auth0/laravel-auth0#requirements) for more information. -¹ This change may require your application's users to reauthenticate. +¹ This change may require your application's users to reauthenticate. You can avoid this by changing the `sessionStorage` and `transientStorage` options in your SDK configuration to their previous default instances of `Auth0\SDK\Store\CookieStore`, but it is recommended you migrate to the new `LaravelSession` default. ## [7.1.0](https://github.com/auth0/laravel-auth0/tree/7.1.0) (2022-08-08) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.0.1...7.1.0) From 6a3192feb58fc7cd15005a6732032c783e519b7a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 11 Oct 2022 11:55:40 -0500 Subject: [PATCH 137/525] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index debddc0d..63d26b23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ Thank you to [tonyfox-disguise](https://github.com/tonyfox-disguise), [jeovajr]( **Changed** - `Auth0\Laravel\Store\LaravelSession` has been added as the default `sessionStorage` and `transientStorage` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native Laravel Session APIs by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims))¹ -- `Auth0\Laravel\Cache\LaravelCachePool` and `Auth0\Laravel\Cache\ LaravelCacheItem` have been added as the default `tokenCache` and `managementTokenCache` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native Laravel Cache APIs by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims)) +- `Auth0\Laravel\Cache\LaravelCachePool` and `Auth0\Laravel\Cache\LaravelCacheItem` have been added as the default `tokenCache` and `managementTokenCache` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native Laravel Cache APIs by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims)) - `Auth0\Laravel\Auth\Guard` now supports viaRemember [\#306](https://github.com/auth0/laravel-auth0/pull/306) ([tonyfox-disguise](https://github.com/tonyfox-disguise)) - `Auth0\Laravel\Http\Middleware\Stateless\Authorize` now returns a 401 status instead of 403 for unauthenticated users. [\#304](https://github.com/auth0/laravel-auth0/issues/304) ([jeovajr](https://github.com/jeovajr)) - PHP 8.0 and Laravel 8.0 are now the minimum supported runtime and framework versions. Please review our [support matrix](https://github.com/auth0/laravel-auth0#requirements) for more information. From 497c44bdeaedb8545ad7aa8aed10bb32031fc205 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 11 Oct 2022 11:57:27 -0500 Subject: [PATCH 138/525] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63d26b23..0a3bf896 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ Thank you to [tonyfox-disguise](https://github.com/tonyfox-disguise), [jeovajr]( - `Auth0\Laravel\Http\Middleware\Stateless\Authorize` now returns a 401 status instead of 403 for unauthenticated users. [\#304](https://github.com/auth0/laravel-auth0/issues/304) ([jeovajr](https://github.com/jeovajr)) - PHP 8.0 and Laravel 8.0 are now the minimum supported runtime and framework versions. Please review our [support matrix](https://github.com/auth0/laravel-auth0#requirements) for more information. -¹ This change may require your application's users to reauthenticate. You can avoid this by changing the `sessionStorage` and `transientStorage` options in your SDK configuration to their previous default instances of `Auth0\SDK\Store\CookieStore`, but it is recommended you migrate to the new `LaravelSession` default. +¹ This change may require your application's users to re-authenticate. You can avoid this by changing the `sessionStorage` and `transientStorage` options in your SDK configuration to their previous default instances of `Auth0\SDK\Store\CookieStore`, but it is recommended you migrate to the new `LaravelSession` default. ## [7.1.0](https://github.com/auth0/laravel-auth0/tree/7.1.0) (2022-08-08) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.0.1...7.1.0) From 29b9666d6f59426e6564e2c07d4f1deba2940a62 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 11 Oct 2022 12:02:29 -0500 Subject: [PATCH 139/525] Update CHANGELOG.md --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a3bf896..085a6fa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,11 @@ Thank you to [tonyfox-disguise](https://github.com/tonyfox-disguise), [jeovajr](https://github.com/jeovajr) and [nie7321](https://github.com/nie7321) for their contributions to this release. **Changed** -- `Auth0\Laravel\Store\LaravelSession` has been added as the default `sessionStorage` and `transientStorage` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native Laravel Session APIs by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims))¹ -- `Auth0\Laravel\Cache\LaravelCachePool` and `Auth0\Laravel\Cache\LaravelCacheItem` have been added as the default `tokenCache` and `managementTokenCache` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native Laravel Cache APIs by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims)) -- `Auth0\Laravel\Auth\Guard` now supports viaRemember [\#306](https://github.com/auth0/laravel-auth0/pull/306) ([tonyfox-disguise](https://github.com/tonyfox-disguise)) +- `Auth0\Laravel\Store\LaravelSession` has been added as the default `sessionStorage` and `transientStorage` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Session APIs](https://laravel.com/docs/9.x/session) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims))¹ +- `Auth0\Laravel\Cache\LaravelCachePool` and `Auth0\Laravel\Cache\LaravelCacheItem` have been added as the default `tokenCache` and `managementTokenCache` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Cache APIs](https://laravel.com/docs/9.x/cache) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims)) +- `Auth0\Laravel\Auth\Guard` now supports the `viaRemember` method. [\#306](https://github.com/auth0/laravel-auth0/pull/306) ([tonyfox-disguise](https://github.com/tonyfox-disguise)) - `Auth0\Laravel\Http\Middleware\Stateless\Authorize` now returns a 401 status instead of 403 for unauthenticated users. [\#304](https://github.com/auth0/laravel-auth0/issues/304) ([jeovajr](https://github.com/jeovajr)) -- PHP 8.0 and Laravel 8.0 are now the minimum supported runtime and framework versions. Please review our [support matrix](https://github.com/auth0/laravel-auth0#requirements) for more information. +- PHP 8.0 is now the minimum supported runtime version. Please review the [README](README.md) for more information on support windows. ¹ This change may require your application's users to re-authenticate. You can avoid this by changing the `sessionStorage` and `transientStorage` options in your SDK configuration to their previous default instances of `Auth0\SDK\Store\CookieStore`, but it is recommended you migrate to the new `LaravelSession` default. From 4aae0a242d8816911a60b26672dcb9091c134ff3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Oct 2022 22:47:42 -0300 Subject: [PATCH 140/525] Update orchestra/testbench requirement from 6.25.0 to 6.25.1 (#313) Updates the requirements on [orchestra/testbench](https://github.com/orchestral/testbench) to permit the latest version. - [Release notes](https://github.com/orchestral/testbench/releases) - [Changelog](https://github.com/orchestral/testbench/blob/7.x/CHANGELOG-6.x.md) - [Commits](https://github.com/orchestral/testbench/compare/v6.25.0...v6.25.1) --- updated-dependencies: - dependency-name: orchestra/testbench dependency-type: direct:development ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a16f1a4c..74b9ded2 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "laravel/pint": "^1.2", "nunomaduro/larastan": "^1.0", "nyholm/psr7": "^1.4", - "orchestra/testbench": "6.25.0", + "orchestra/testbench": "6.25.1", "pestphp/pest": "^1.21", "pestphp/pest-plugin-laravel": "^1.2", "phpstan/phpstan": "^1.7", From 942c1940c17c5c82bb3deaef11e50524b9d8b573 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 12 Oct 2022 21:11:36 -0500 Subject: [PATCH 141/525] Update dependencies --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index a16f1a4c..fd0b4654 100644 --- a/composer.json +++ b/composer.json @@ -37,8 +37,7 @@ "auth0/auth0-php": "^8.0", "illuminate/contracts": "^8.0 || ^9.0", "illuminate/http": "^8.0 || ^9.0", - "illuminate/support": "^8.0 || ^9.0", - "spatie/laravel-package-tools": "^1.9" + "illuminate/support": "^8.0 || ^9.0" }, "require-dev": { "laravel/laravel": "^8.4.4 || ^9.0", From 5b9841308942cd952e308bbd9049db10fbcc883e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 12 Oct 2022 21:15:51 -0500 Subject: [PATCH 142/525] Refactor DI and ServiceProvider for improved Octane compatibility --- src/Auth/Guard.php | 67 ++++++++++------- src/Auth/User/Provider.php | 22 ++---- src/Auth0.php | 62 ++++++++-------- src/Cache/LaravelCachePool.php | 10 +-- src/Contract/Auth/Guard.php | 8 -- src/Contract/Auth/User/Provider.php | 7 -- src/Contract/ServiceProvider.php | 14 ---- src/ServiceProvider.php | 111 +++++++++++----------------- src/Store/LaravelSession.php | 11 +-- tests/Unit/Auth0Test.php | 4 +- 10 files changed, 130 insertions(+), 186 deletions(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 083c876c..318e2c2f 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -5,30 +5,11 @@ namespace Auth0\Laravel\Auth; use Auth0\Laravel\Contract\Auth\User\Provider; +use Auth0\SDK\Configuration\SdkConfiguration; +use RuntimeException; final class Guard implements \Auth0\Laravel\Contract\Auth\Guard, \Illuminate\Contracts\Auth\Guard { - /** - * The user provider implementation. - */ - private \Illuminate\Contracts\Auth\UserProvider $provider; - - /** - * The request instance. - */ - private \Illuminate\Http\Request $request; - - /** - * {@inheritdoc} - */ - public function __construct( - \Illuminate\Contracts\Auth\UserProvider $provider, - \Illuminate\Http\Request $request, - ) { - $this->provider = $provider; - $this->request = $request; - } - /** * {@inheritdoc} */ @@ -73,8 +54,23 @@ public function guest(): bool */ public function user(): ?\Illuminate\Contracts\Auth\Authenticatable { - return $this->getState()-> - getUser() ?? $this->getUserFromToken() ?? $this->getUserFromSession() ?? null; + $user = $this->getState()->getUser(); + + if (! $user instanceof \Illuminate\Contracts\Auth\Authenticatable) { + $configuration = app(\Auth0\Laravel\Auth0::class)->getConfiguration(); + + $apiOnly = in_array($configuration->getStrategy(), [SdkConfiguration::STRATEGY_API, SdkConfiguration::STRATEGY_MANAGEMENT_API], true); + + if ($apiOnly) { + $user = $this->getUserFromToken(); + } + + if (! $apiOnly) { + $user = $this->getUserFromSession(); + } + } + + return $user; } /** @@ -151,10 +147,18 @@ public function viaRemember(): bool private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable { // Retrieve an available bearer token from the request. - $token = $this->request->bearerToken(); + $request = request(); + + if (! $request instanceof \Illuminate\Http\Request) { + return null; + } + + $token = $request->bearerToken(); + + $token = $token ?? $_GET['token'] ?? null; // If a session is not available, return null. - if (null === $token) { + if (! is_string($token)) { return null; } @@ -299,6 +303,17 @@ private function getState(): \Auth0\Laravel\StateInstance */ private function getProvider(): \Illuminate\Contracts\Auth\UserProvider { - return $this->provider; + static $provider = null; + + if (null === $provider) { + $configured = config('auth.guards.auth0.provider') ?? \Auth0\Laravel\Auth\User\Provider::class; + $provider = app()->make('auth')->createUserProvider($configured); + + if (! $provider instanceof \Illuminate\Contracts\Auth\UserProvider) { + throw new RuntimeException('Auth0: Unable to invoke UserProvider from application configuration.'); + } + } + + return $provider; } } diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php index c68bed2a..f58e26f7 100644 --- a/src/Auth/User/Provider.php +++ b/src/Auth/User/Provider.php @@ -6,19 +6,6 @@ final class Provider implements \Auth0\Laravel\Contract\Auth\User\Provider, \Illuminate\Contracts\Auth\UserProvider { - /** - * A repository instance. - */ - private \Auth0\Laravel\Contract\Auth\User\Repository $repository; - - /** - * {@inheritdoc} - */ - public function __construct(\Auth0\Laravel\Contract\Auth\User\Repository $repository) - { - $this->repository = $repository; - } - /** * {@inheritdoc} * @@ -75,6 +62,13 @@ public function updateRememberToken(\Illuminate\Contracts\Auth\Authenticatable $ */ public function getRepository(): \Auth0\Laravel\Contract\Auth\User\Repository { - return $this->repository; + static $repository = null; + + if (null === $repository) { + $configured = config('auth.providers.auth0.repository') ?? \Auth0\Laravel\Auth\User\Repository::class; + $repository = app()->make($configured); + } + + return $repository; } } diff --git a/src/Auth0.php b/src/Auth0.php index ee2da227..7870b8de 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -6,6 +6,8 @@ use Auth0\Laravel\Cache\LaravelCachePool; use Auth0\Laravel\Store\LaravelSession; +use Auth0\SDK\Configuration\SdkConfiguration as Configuration; +use Auth0\SDK\Contract\Auth0Interface as SDK; /** * Service that provides access to the Auth0 SDK. @@ -20,32 +22,32 @@ final class Auth0 implements \Auth0\Laravel\Contract\Auth0 /** * An instance of the Auth0-PHP SDK. */ - private ?\Auth0\SDK\Contract\Auth0Interface $sdk = null; + private static ?SDK $sdk = null; /** * An instance of the Auth0-PHP SDK's SdkConfiguration, which handles configuration state. */ - private ?\Auth0\SDK\Configuration\SdkConfiguration $configuration = null; + private static ?Configuration $configuration = null; /** * {@inheritdoc} */ - public function getSdk(): \Auth0\SDK\Contract\Auth0Interface + public function getSdk(): SDK { - if (null === $this->sdk) { - $this->sdk = new \Auth0\SDK\Auth0($this->getConfiguration()); - $this->setSdkTelemetry(); + if (null === self::$sdk) { + self::$sdk = new \Auth0\SDK\Auth0($this->getConfiguration()); } - return $this->sdk; + $this->setSdkTelemetry(); + return self::$sdk; } /** * {@inheritdoc} */ - public function setSdk(\Auth0\SDK\Contract\Auth0Interface $sdk): self + public function setSdk(SDK $sdk): self { - $this->sdk = $sdk; + self::$sdk = $sdk; $this->setSdkTelemetry(); return $this; @@ -54,12 +56,10 @@ public function setSdk(\Auth0\SDK\Contract\Auth0Interface $sdk): self /** * {@inheritdoc} */ - public function getConfiguration(): \Auth0\SDK\Configuration\SdkConfiguration + public function getConfiguration(): Configuration { - if (null === $this->configuration) { - $config = app()-> - make('config')-> - get('auth0'); + if (null === self::$configuration) { + $config = config('auth0'); /** * @var array $config @@ -76,38 +76,40 @@ public function getConfiguration(): \Auth0\SDK\Configuration\SdkConfiguration } } - $configuration = new \Auth0\SDK\Configuration\SdkConfiguration($config); + $configuration = new Configuration($config); - // If no sessionStorage is defined, use an LaravelSession store instance. - if (! isset($config['sessionStorage'])) { - $configuration->setSessionStorage( - new LaravelSession($configuration, $configuration->getSessionStorageId()), - ); - } + if (! in_array($configuration->getStrategy(), [Configuration::STRATEGY_API, Configuration::STRATEGY_MANAGEMENT_API], true)) { + // If no sessionStorage is defined, use an LaravelSession store instance. + if (! isset($config['sessionStorage'])) { + $configuration->setSessionStorage( + new LaravelSession($configuration->getSessionStorageId()), + ); + } - // If no transientStorage is defined, use an LaravelSession store instance. - if (! isset($config['transientStorage'])) { - $configuration->setTransientStorage( - new LaravelSession($configuration, $configuration->getSessionStorageId()), - ); + // If no transientStorage is defined, use an LaravelSession store instance. + if (! isset($config['transientStorage'])) { + $configuration->setTransientStorage( + new LaravelSession($configuration->getTransientStorageId()), + ); + } } // Give apps an opportunity to mutate the configuration before applying it. $event = new \Auth0\Laravel\Event\Configuration\Built($configuration); event($event); - $this->configuration = $event->getConfiguration(); + self::$configuration = $event->getConfiguration(); } - return $this->configuration; + return self::$configuration; } /** * {@inheritdoc} */ - public function setConfiguration(\Auth0\SDK\Configuration\SdkConfiguration $configuration): self + public function setConfiguration(Configuration $configuration): self { - $this->configuration = $configuration; + self::$configuration = $configuration; return $this; } diff --git a/src/Cache/LaravelCachePool.php b/src/Cache/LaravelCachePool.php index 0aa5e1a9..30b573ae 100644 --- a/src/Cache/LaravelCachePool.php +++ b/src/Cache/LaravelCachePool.php @@ -13,19 +13,11 @@ */ final class LaravelCachePool implements CacheItemPoolInterface { - private \Illuminate\Cache\CacheManager $manager; - /** * @var array */ private array $deferred = []; - public function __construct() - { - $this->manager = app()-> - make(\Illuminate\Cache\CacheManager::class); - } - public function getItem(string $key): CacheItemInterface { $value = $this->getStore()-> @@ -155,7 +147,7 @@ public function commit(): bool private function getStore(): \Illuminate\Contracts\Cache\Store { - return $this->manager->getStore(); + return app()->make(\Illuminate\Cache\CacheManager::class)->getStore(); } private function createItem(string $key, mixed $value): CacheItemInterface diff --git a/src/Contract/Auth/Guard.php b/src/Contract/Auth/Guard.php index 44e04105..6bee220e 100644 --- a/src/Contract/Auth/Guard.php +++ b/src/Contract/Auth/Guard.php @@ -8,14 +8,6 @@ interface Guard { - /** - * Create a new authentication guard. - */ - public function __construct( - \Illuminate\Contracts\Auth\UserProvider $provider, - \Illuminate\Http\Request $request, - ); - /** * Set the current user. */ diff --git a/src/Contract/Auth/User/Provider.php b/src/Contract/Auth/User/Provider.php index 05556798..c7871944 100644 --- a/src/Contract/Auth/User/Provider.php +++ b/src/Contract/Auth/User/Provider.php @@ -6,13 +6,6 @@ interface Provider { - /** - * \Auth0\Laravel\Contract\Auth\User\Provider constructor. - * - * @param \Auth0\Laravel\Auth\User\Repository $repository a repository instance - */ - public function __construct(\Auth0\Laravel\Auth\User\Repository $repository); - /** * Returns the assigned user provider. */ diff --git a/src/Contract/ServiceProvider.php b/src/Contract/ServiceProvider.php index 2e64738f..c36565ea 100644 --- a/src/Contract/ServiceProvider.php +++ b/src/Contract/ServiceProvider.php @@ -6,18 +6,4 @@ interface ServiceProvider { - /** - * Configure package details for Laravel's consumption. - */ - public function configurePackage(\Spatie\LaravelPackageTools\Package $package): void; - - /** - * Register application services. - */ - public function registeringPackage(): void; - - /** - * Register middleware and guard. - */ - public function bootingPackage(): void; } diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index eac91936..2dcc6441 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -4,81 +4,60 @@ namespace Auth0\Laravel; -/** - * @psalm-suppress PropertyNotSetInConstructor - */ -final class ServiceProvider extends \Spatie\LaravelPackageTools\PackageServiceProvider implements \Auth0\Laravel\Contract\ServiceProvider +use Auth0\Laravel\Auth\User\Repository; +use Auth0\Laravel\Auth\User\Provider; +use Auth0\Laravel\Auth\Guard; +use Auth0\Laravel\Http\Controller\Stateful\Callback; +use Auth0\Laravel\Http\Controller\Stateful\Login; +use Auth0\Laravel\Http\Controller\Stateful\Logout; +use Auth0\Laravel\Http\Middleware\Stateful\Authenticate; +use Auth0\Laravel\Http\Middleware\Stateful\AuthenticateOptional; +use Auth0\Laravel\Http\Middleware\Stateless\Authorize; +use Auth0\Laravel\Http\Middleware\Stateless\AuthorizeOptional; + +final class ServiceProvider extends \Illuminate\Support\ServiceProvider implements \Auth0\Laravel\Contract\ServiceProvider { - /** - * {@inheritdoc} - */ - public function configurePackage(\Spatie\LaravelPackageTools\Package $package): void + public function provides() { - $package-> - name('auth0')-> - hasConfigFile(); + return [Auth0::class, StateInstance::class, Repository::class, Guard::class, Provider::class, Authenticate::class, AuthenticateOptional::class, Authorize::class, AuthorizeOptional::class, Login::class, Logout::class, Callback::class]; } - /** - * {@inheritdoc} - */ - public function registeringPackage(): void + public function register(): self { - app()->singleton(Auth0::class, static fn (): \Auth0\Laravel\Auth0 => new Auth0()); - - app()-> - singleton('auth0', static fn (): \Auth0\Laravel\Auth0 => app()->make(Auth0::class)); - - app()-> - singleton(StateInstance::class, static fn (): \Auth0\Laravel\StateInstance => new StateInstance()); - - app()-> - singleton( - \Auth0\Laravel\Auth\User\Repository::class, - static fn (): \Auth0\Laravel\Auth\User\Repository => new \Auth0\Laravel\Auth\User\Repository(), - ); + $this->mergeConfigFrom(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'config', 'auth0.php']), 'auth0'); + + app()->singleton(Auth0::class, fn (): Auth0 => new Auth0()); + app()->singleton(StateInstance::class, static fn (): StateInstance => new StateInstance()); + app()->singleton(Repository::class, static fn (): Repository => new Repository()); + app()->singleton(Guard::class, static fn (): Guard => new Guard()); + app()->singleton(Provider::class, static fn (): Provider => new Provider()); + app()->singleton(Authenticate::class, static fn (): Authenticate => new Authenticate()); + app()->singleton(AuthenticateOptional::class, static fn (): AuthenticateOptional => new AuthenticateOptional()); + app()->singleton(Authorize::class, static fn (): Authorize => new Authorize()); + app()->singleton(AuthorizeOptional::class, static fn (): AuthorizeOptional => new AuthorizeOptional()); + app()->singleton(Login::class, static fn (): Login => new Login()); + app()->singleton(Logout::class, static fn (): Logout => new Logout()); + app()->singleton(Callback::class, static fn (): Callback => new Callback()); + + app()->singleton('auth0', static fn (): Auth0 => app()->make(Auth0::class)); + + app()->terminating(function () { + app()->instance(StateInstance::class, null); + }); + + return $this; } - /** - * {@inheritdoc} - * - * @psalm-suppress UndefinedInterfaceMethod - */ - public function bootingPackage(): void + public function boot(\Illuminate\Routing\Router $router, \Illuminate\Auth\AuthManager $auth): self { - auth()->provider( - 'auth0', - static fn ($app, array $config): \Auth0\Laravel\Auth\User\Provider => new \Auth0\Laravel\Auth\User\Provider( - app()->make( - $config['repository'], - ), - ), - ); + $auth->extend('auth0', static fn (): Guard => new Guard()); + $auth->provider('auth0', static fn (): Provider => new Provider()); - auth()-> - extend( - 'auth0', - static fn ($app, $name, array $config): \Auth0\Laravel\Auth\Guard => new \Auth0\Laravel\Auth\Guard( - auth()->createUserProvider( - $config['provider'], - ), - $app->make( - 'request', - ), - ), - ); + $router->aliasMiddleware('auth0.authenticate', Authenticate::class); + $router->aliasMiddleware('auth0.authenticate.optional', AuthenticateOptional::class); + $router->aliasMiddleware('auth0.authorize', Authorize::class); + $router->aliasMiddleware('auth0.authorize.optional', AuthorizeOptional::class); - $router = app()-> - make(\Illuminate\Routing\Router::class); - $router->aliasMiddleware('auth0.authenticate', \Auth0\Laravel\Http\Middleware\Stateful\Authenticate::class); - $router->aliasMiddleware( - 'auth0.authenticate.optional', - \Auth0\Laravel\Http\Middleware\Stateful\AuthenticateOptional::class, - ); - $router->aliasMiddleware('auth0.authorize', \Auth0\Laravel\Http\Middleware\Stateless\Authorize::class); - $router->aliasMiddleware( - 'auth0.authorize.optional', - \Auth0\Laravel\Http\Middleware\Stateless\AuthorizeOptional::class, - ); + return $this; } } diff --git a/src/Store/LaravelSession.php b/src/Store/LaravelSession.php index a1022b8d..5b56b019 100644 --- a/src/Store/LaravelSession.php +++ b/src/Store/LaravelSession.php @@ -4,7 +4,6 @@ namespace Auth0\Laravel\Store; -use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\SDK\Contract\StoreInterface; use Exception; @@ -14,12 +13,6 @@ */ final class LaravelSession implements StoreInterface { - /** - * Instance of SdkConfiguration, for shared configuration across classes. - */ - /** @phpstan-ignore-next-line */ - private SdkConfiguration $configuration; - /** * Session base name, configurable on instantiation. */ @@ -33,12 +26,10 @@ final class LaravelSession implements StoreInterface /** * Psr14Store constructor. * - * @param SdkConfiguration $configuration Base configuration options for the SDK. See the SdkConfiguration class constructor for options. * @param string $sessionPrefix a string to prefix session keys with */ - public function __construct(SdkConfiguration $configuration, string $sessionPrefix = 'auth0') + public function __construct(string $sessionPrefix = 'auth0') { - $this->configuration = $configuration; $this->sessionPrefix = $sessionPrefix; } diff --git a/tests/Unit/Auth0Test.php b/tests/Unit/Auth0Test.php index d8a1de1a..68dd5cd4 100644 --- a/tests/Unit/Auth0Test.php +++ b/tests/Unit/Auth0Test.php @@ -12,7 +12,7 @@ expect($service->getConfiguration())-> toBeInstanceOf(\Auth0\SDK\Configuration\SdkConfiguration::class); -}, )->throws(\Auth0\SDK\Exception\ConfigurationException::class); +}, ); test('the service\'s getSdk() method returns an Auth0 SDK instance', function (): void { expect($this->service->getSdk())-> @@ -26,7 +26,7 @@ test('the service\'s getState method returns a StateInstance instance', function (): void { expect($this->service->getState())-> - toBeInstanceOf(\Auth0\Laravel\StateInstance::class); + toBeInstanceOf(\Auth0\Laravel\Contract\StateInstance::class); }, ); test('the service\'s setSdk() method allows overwriting the Auth0 instance', function (): void { From a272fa0ff8275a83373a5d42ae10ced8b9ac2488 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 12 Oct 2022 21:21:28 -0500 Subject: [PATCH 143/525] Refactor DI and ServiceProvider for improved Octane compatibility --- src/Auth/Guard.php | 6 ++---- src/Auth0.php | 3 ++- src/ServiceProvider.php | 8 ++++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 318e2c2f..d7ce61c6 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -59,7 +59,7 @@ public function user(): ?\Illuminate\Contracts\Auth\Authenticatable if (! $user instanceof \Illuminate\Contracts\Auth\Authenticatable) { $configuration = app(\Auth0\Laravel\Auth0::class)->getConfiguration(); - $apiOnly = in_array($configuration->getStrategy(), [SdkConfiguration::STRATEGY_API, SdkConfiguration::STRATEGY_MANAGEMENT_API], true); + $apiOnly = \in_array($configuration->getStrategy(), [SdkConfiguration::STRATEGY_API, SdkConfiguration::STRATEGY_MANAGEMENT_API], true); if ($apiOnly) { $user = $this->getUserFromToken(); @@ -155,10 +155,8 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable $token = $request->bearerToken(); - $token = $token ?? $_GET['token'] ?? null; - // If a session is not available, return null. - if (! is_string($token)) { + if (! \is_string($token)) { return null; } diff --git a/src/Auth0.php b/src/Auth0.php index 7870b8de..c237a615 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -39,6 +39,7 @@ public function getSdk(): SDK } $this->setSdkTelemetry(); + return self::$sdk; } @@ -78,7 +79,7 @@ public function getConfiguration(): Configuration $configuration = new Configuration($config); - if (! in_array($configuration->getStrategy(), [Configuration::STRATEGY_API, Configuration::STRATEGY_MANAGEMENT_API], true)) { + if (! \in_array($configuration->getStrategy(), [Configuration::STRATEGY_API, Configuration::STRATEGY_MANAGEMENT_API], true)) { // If no sessionStorage is defined, use an LaravelSession store instance. if (! isset($config['sessionStorage'])) { $configuration->setSessionStorage( diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 2dcc6441..7aba311e 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -4,9 +4,9 @@ namespace Auth0\Laravel; -use Auth0\Laravel\Auth\User\Repository; -use Auth0\Laravel\Auth\User\Provider; use Auth0\Laravel\Auth\Guard; +use Auth0\Laravel\Auth\User\Provider; +use Auth0\Laravel\Auth\User\Repository; use Auth0\Laravel\Http\Controller\Stateful\Callback; use Auth0\Laravel\Http\Controller\Stateful\Login; use Auth0\Laravel\Http\Controller\Stateful\Logout; @@ -26,7 +26,7 @@ public function register(): self { $this->mergeConfigFrom(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'config', 'auth0.php']), 'auth0'); - app()->singleton(Auth0::class, fn (): Auth0 => new Auth0()); + app()->singleton(Auth0::class, static fn (): Auth0 => new Auth0()); app()->singleton(StateInstance::class, static fn (): StateInstance => new StateInstance()); app()->singleton(Repository::class, static fn (): Repository => new Repository()); app()->singleton(Guard::class, static fn (): Guard => new Guard()); @@ -41,7 +41,7 @@ public function register(): self app()->singleton('auth0', static fn (): Auth0 => app()->make(Auth0::class)); - app()->terminating(function () { + app()->terminating(static function (): void { app()->instance(StateInstance::class, null); }); From 077823ee373434b6bb87845592d668ede93f61bc Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 12 Oct 2022 21:42:18 -0500 Subject: [PATCH 144/525] Refactor DI and ServiceProvider for improved Octane compatibility --- phpstan.neon.dist | 1 + src/Auth/Guard.php | 26 ++++++++++++------- src/Auth/User/Provider.php | 7 ++++- src/Auth0.php | 2 +- src/Cache/LaravelCachePool.php | 2 +- src/Http/Controller/Stateful/Callback.php | 4 +-- src/Http/Controller/Stateful/Login.php | 2 +- src/Http/Controller/Stateful/Logout.php | 6 ++--- src/Http/Middleware/Stateful/Authenticate.php | 2 +- src/ServiceProvider.php | 2 +- src/Store/LaravelSession.php | 2 ++ src/Traits/ActingAsAuth0User.php | 2 +- 12 files changed, 36 insertions(+), 22 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 550f8aad..54b1acc7 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,6 @@ includes: - vendor/phpstan/phpstan-strict-rules/rules.neon + - vendor/nunomaduro/larastan/extension.neon parameters: level: max diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index d7ce61c6..736a7f4a 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -149,6 +149,7 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable // Retrieve an available bearer token from the request. $request = request(); + // @phpstan-ignore-next-line if (! $request instanceof \Illuminate\Http\Request) { return null; } @@ -176,6 +177,7 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable /** * @var Provider $provider + * @var array{scope: string|null, exp: int|null} $decoded */ $user = $provider-> getRepository()-> @@ -221,7 +223,7 @@ private function getUserFromSession(): ?\Illuminate\Contracts\Auth\Authenticatab // Query the UserProvider to retrieve tue user for the session. $user = $provider-> getRepository()-> - fromSession($session->user); + fromSession($session->user); // @phpstan-ignore-line // Was a user retrieved successfully? if (null !== $user) { @@ -231,12 +233,12 @@ private function getUserFromSession(): ?\Illuminate\Contracts\Auth\Authenticatab $this->getState()-> clear()-> - setDecoded($session->user)-> - setIdToken($session->idToken)-> - setAccessToken($session->accessToken)-> - setAccessTokenScope($session->accessTokenScope)-> - setAccessTokenExpiration($session->accessTokenExpiration)-> - setRefreshToken($session->refreshToken); + setDecoded($session->user)-> // @phpstan-ignore-line + setIdToken($session->idToken)-> // @phpstan-ignore-line + setAccessToken($session->accessToken)-> // @phpstan-ignore-line + setAccessTokenScope($session->accessTokenScope)-> // @phpstan-ignore-line + setAccessTokenExpiration($session->accessTokenExpiration)-> // @phpstan-ignore-line + setRefreshToken($session->refreshToken); // @phpstan-ignore-line $user = $this->handleSessionExpiration($user); } @@ -270,6 +272,7 @@ private function handleSessionExpiration( // Retrieve updated state data $refreshed = app(\Auth0\Laravel\Auth0::class)->getSdk()->getCredentials(); + // @phpstan-ignore-next-line if (null !== $refreshed && false === $refreshed->accessTokenExpired) { event(new \Auth0\Laravel\Event\Stateful\TokenRefreshSucceeded()); @@ -293,7 +296,7 @@ private function handleSessionExpiration( */ private function getState(): \Auth0\Laravel\StateInstance { - return app()->make(\Auth0\Laravel\StateInstance::class); + return app(\Auth0\Laravel\StateInstance::class); } /** @@ -305,7 +308,12 @@ private function getProvider(): \Illuminate\Contracts\Auth\UserProvider if (null === $provider) { $configured = config('auth.guards.auth0.provider') ?? \Auth0\Laravel\Auth\User\Provider::class; - $provider = app()->make('auth')->createUserProvider($configured); + + /** + * @var string|null $configured + */ + + $provider = app('auth')->createUserProvider($configured); if (! $provider instanceof \Illuminate\Contracts\Auth\UserProvider) { throw new RuntimeException('Auth0: Unable to invoke UserProvider from application configuration.'); diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php index f58e26f7..2fd9760b 100644 --- a/src/Auth/User/Provider.php +++ b/src/Auth/User/Provider.php @@ -66,7 +66,12 @@ public function getRepository(): \Auth0\Laravel\Contract\Auth\User\Repository if (null === $repository) { $configured = config('auth.providers.auth0.repository') ?? \Auth0\Laravel\Auth\User\Repository::class; - $repository = app()->make($configured); + + /** + * @var string|null $configured + */ + + $repository = app($configured); } return $repository; diff --git a/src/Auth0.php b/src/Auth0.php index c237a615..eed47ca6 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -120,7 +120,7 @@ public function setConfiguration(Configuration $configuration): self */ public function getState(): Contract\StateInstance { - return app()->make(\Auth0\Laravel\StateInstance::class); + return app(\Auth0\Laravel\StateInstance::class); } /** diff --git a/src/Cache/LaravelCachePool.php b/src/Cache/LaravelCachePool.php index 30b573ae..1b3bf61a 100644 --- a/src/Cache/LaravelCachePool.php +++ b/src/Cache/LaravelCachePool.php @@ -147,7 +147,7 @@ public function commit(): bool private function getStore(): \Illuminate\Contracts\Cache\Store { - return app()->make(\Illuminate\Cache\CacheManager::class)->getStore(); + return app(\Illuminate\Cache\CacheManager::class)->getStore(); } private function createItem(string $key, mixed $value): CacheItemInterface diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index cc56f895..46a748ef 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -27,7 +27,7 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re // Check if the user already has a session: if ($guard->check()) { // They do; redirect to homepage. - return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); + return redirect()->intended(config('auth0.routes.home', '/')); // @phpstan-ignore-line } $code = $request->query('code'); @@ -103,6 +103,6 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re $guard->setUser($event->getUser()); } - return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); + return redirect()->intended(config('auth0.routes.home', '/')); // @phpstan-ignore-line } } diff --git a/src/Http/Controller/Stateful/Login.php b/src/Http/Controller/Stateful/Login.php index 3723adce..2b8fca3f 100644 --- a/src/Http/Controller/Stateful/Login.php +++ b/src/Http/Controller/Stateful/Login.php @@ -26,7 +26,7 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re * @var Guard $guard */ if ($guard->check()) { - return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); + return redirect()->intended(config('auth0.routes.home', '/')); // @phpstan-ignore-line } return redirect()->away(app(\Auth0\Laravel\Auth0::class)->getSdk()->login()); diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index 141a2c13..2098e627 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -32,12 +32,10 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re regenerateToken(); return redirect()->away( - app(\Auth0\Laravel\Auth0::class)->getSdk()->authentication()->getLogoutLink(url( - app()->make('config')->get('auth0.routes.home', '/'), - )), + app(\Auth0\Laravel\Auth0::class)->getSdk()->authentication()->getLogoutLink(url(http://github.com/config('auth0.routes.home',%20'/'))), // @phpstan-ignore-line ); } - return redirect()->intended(app()->make('config')->get('auth0.routes.home', '/')); + return redirect()->intended(config('auth0.routes.home', '/')); // @phpstan-ignore-line } } diff --git a/src/Http/Middleware/Stateful/Authenticate.php b/src/Http/Middleware/Stateful/Authenticate.php index b4f6113d..e8901985 100644 --- a/src/Http/Middleware/Stateful/Authenticate.php +++ b/src/Http/Middleware/Stateful/Authenticate.php @@ -36,6 +36,6 @@ public function handle(\Illuminate\Http\Request $request, \Closure $next) return $next($request); } - return redirect(app()->make('config')->get('auth0.routes.login', 'login')); + return redirect(config('auth0.routes.login', 'login')); // @phpstan-ignore-line } } diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 7aba311e..5d28f801 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -39,7 +39,7 @@ public function register(): self app()->singleton(Logout::class, static fn (): Logout => new Logout()); app()->singleton(Callback::class, static fn (): Callback => new Callback()); - app()->singleton('auth0', static fn (): Auth0 => app()->make(Auth0::class)); + app()->singleton('auth0', static fn (): Auth0 => app(Auth0::class)); app()->terminating(static function (): void { app()->instance(StateInstance::class, null); diff --git a/src/Store/LaravelSession.php b/src/Store/LaravelSession.php index 5b56b019..3019d194 100644 --- a/src/Store/LaravelSession.php +++ b/src/Store/LaravelSession.php @@ -122,10 +122,12 @@ private function getStore(): \Illuminate\Session\Store { $request = request(); + // @phpstan-ignore-next-line if ($request instanceof \Illuminate\Http\Request) { return $request->session(); } + // @phpstan-ignore-next-line throw new Exception('A cache must be configured.'); } diff --git a/src/Traits/ActingAsAuth0User.php b/src/Traits/ActingAsAuth0User.php index 79a65b47..10a3b880 100644 --- a/src/Traits/ActingAsAuth0User.php +++ b/src/Traits/ActingAsAuth0User.php @@ -31,7 +31,7 @@ public function actingAsAuth0User(array $attributes = []) $auth0user = new User(array_merge($defaults, $attributes)); if ($auth0user->getAttribute('scope')) { - app()->make(StateInstance::class)->setAccessTokenScope(explode(' ', $auth0user->getAttribute('scope'))); + app(StateInstance::class)->setAccessTokenScope(explode(' ', $auth0user->getAttribute('scope'))); } return $this->actingAs($auth0user, 'auth0'); From c6a9b96ecb3f54c98711f60c50c3db89a0d35c6e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 12 Oct 2022 21:44:22 -0500 Subject: [PATCH 145/525] Refactor DI and ServiceProvider for improved Octane compatibility --- src/Auth/Guard.php | 6 ++---- src/Auth/User/Provider.php | 4 +--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 736a7f4a..9001e357 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -238,7 +238,7 @@ private function getUserFromSession(): ?\Illuminate\Contracts\Auth\Authenticatab setAccessToken($session->accessToken)-> // @phpstan-ignore-line setAccessTokenScope($session->accessTokenScope)-> // @phpstan-ignore-line setAccessTokenExpiration($session->accessTokenExpiration)-> // @phpstan-ignore-line - setRefreshToken($session->refreshToken); // @phpstan-ignore-line + setRefreshToken($session->refreshToken); /** @phpstan-ignore-line */ $user = $this->handleSessionExpiration($user); } @@ -307,12 +307,10 @@ private function getProvider(): \Illuminate\Contracts\Auth\UserProvider static $provider = null; if (null === $provider) { - $configured = config('auth.guards.auth0.provider') ?? \Auth0\Laravel\Auth\User\Provider::class; - /** * @var string|null $configured */ - + $configured = config('auth.guards.auth0.provider') ?? \Auth0\Laravel\Auth\User\Provider::class; $provider = app('auth')->createUserProvider($configured); if (! $provider instanceof \Illuminate\Contracts\Auth\UserProvider) { diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php index 2fd9760b..9d3d2152 100644 --- a/src/Auth/User/Provider.php +++ b/src/Auth/User/Provider.php @@ -65,12 +65,10 @@ public function getRepository(): \Auth0\Laravel\Contract\Auth\User\Repository static $repository = null; if (null === $repository) { - $configured = config('auth.providers.auth0.repository') ?? \Auth0\Laravel\Auth\User\Repository::class; - /** * @var string|null $configured */ - + $configured = config('auth.providers.auth0.repository') ?? \Auth0\Laravel\Auth\User\Repository::class; $repository = app($configured); } From 2fcafaef6409586d30f4570fa689997469dd7de3 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 12 Oct 2022 21:44:53 -0500 Subject: [PATCH 146/525] Refactor DI and ServiceProvider for improved Octane compatibility --- src/Auth/Guard.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 9001e357..622ce8b7 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -239,7 +239,6 @@ private function getUserFromSession(): ?\Illuminate\Contracts\Auth\Authenticatab setAccessTokenScope($session->accessTokenScope)-> // @phpstan-ignore-line setAccessTokenExpiration($session->accessTokenExpiration)-> // @phpstan-ignore-line setRefreshToken($session->refreshToken); /** @phpstan-ignore-line */ - $user = $this->handleSessionExpiration($user); } From 65cd9ed85443dc5f77765933051fa04c53f156f0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 12 Oct 2022 21:58:41 -0500 Subject: [PATCH 147/525] Refactor DI and ServiceProvider for improved Octane compatibility --- src/Auth/Guard.php | 43 +++++++++++-------- src/Auth/User/Provider.php | 12 +++--- src/Auth/User/Repository.php | 6 ++- src/Auth0.php | 4 +- src/Contract/Auth/User/Repository.php | 6 ++- src/Contract/Auth0.php | 11 +++-- .../Stateful/AuthenticationSucceeded.php | 12 +++--- src/Contract/StateInstance.php | 8 ++-- src/Event/Configuration/Built.php | 10 ++--- .../Stateful/AuthenticationSucceeded.php | 10 +++-- src/Http/Controller/Stateful/Callback.php | 5 +-- src/StateInstance.php | 8 ++-- 12 files changed, 78 insertions(+), 57 deletions(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 622ce8b7..cc3fd27e 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -4,8 +4,13 @@ namespace Auth0\Laravel\Auth; +use Auth0\Laravel\Auth0; use Auth0\Laravel\Contract\Auth\User\Provider; +use Auth0\Laravel\Contract\StateInstance; +use Auth0\Laravel\StateInstance as ConcreteStateInstance; use Auth0\SDK\Configuration\SdkConfiguration; +use Illuminate\Contracts\Auth\Authenticatable; +use Illuminate\Contracts\Auth\UserProvider; use RuntimeException; final class Guard implements \Auth0\Laravel\Contract\Auth\Guard, \Illuminate\Contracts\Auth\Guard @@ -13,7 +18,7 @@ final class Guard implements \Auth0\Laravel\Contract\Auth\Guard, \Illuminate\Con /** * {@inheritdoc} */ - public function login(\Illuminate\Contracts\Auth\Authenticatable $user): self + public function login(Authenticatable $user): self { $this->getState()-> setUser($user); @@ -28,7 +33,7 @@ public function logout(): self { $this->getState()-> setUser(null); - app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); + app(Auth0::class)->getSdk()->clear(); return $this; } @@ -52,12 +57,12 @@ public function guest(): bool /** * {@inheritdoc} */ - public function user(): ?\Illuminate\Contracts\Auth\Authenticatable + public function user(): ?Authenticatable { $user = $this->getState()->getUser(); - if (! $user instanceof \Illuminate\Contracts\Auth\Authenticatable) { - $configuration = app(\Auth0\Laravel\Auth0::class)->getConfiguration(); + if (! $user instanceof Authenticatable) { + $configuration = app(Auth0::class)->getConfiguration(); $apiOnly = \in_array($configuration->getStrategy(), [SdkConfiguration::STRATEGY_API, SdkConfiguration::STRATEGY_MANAGEMENT_API], true); @@ -107,7 +112,7 @@ public function validate(array $credentials = []): bool * * @psalm-suppress UnusedVariable */ - public function setUser(\Illuminate\Contracts\Auth\Authenticatable $user): self + public function setUser(Authenticatable $user): self { $user = $this->getState()-> setUser($user); @@ -144,7 +149,7 @@ public function viaRemember(): bool /** * Get the user context from a provided access token. */ - private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable + private function getUserFromToken(): ?Authenticatable { // Retrieve an available bearer token from the request. $request = request(); @@ -163,7 +168,7 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable try { // Attempt to decode the bearer token. - $decoded = app(\Auth0\Laravel\Auth0::class)->getSdk()->decode( + $decoded = app(Auth0::class)->getSdk()->decode( token: $token, tokenType: \Auth0\SDK\Token::TYPE_TOKEN, )->toArray(); @@ -203,10 +208,10 @@ private function getUserFromToken(): ?\Illuminate\Contracts\Auth\Authenticatable /** * Get the user context from an Auth0-PHP SDK session.. */ - private function getUserFromSession(): ?\Illuminate\Contracts\Auth\Authenticatable + private function getUserFromSession(): ?Authenticatable { // Retrieve an available session from the Auth0-PHP SDK. - $session = app(\Auth0\Laravel\Auth0::class)->getSdk()->getCredentials(); + $session = app(Auth0::class)->getSdk()->getCredentials(); // If a session is not available, return null. if (null === $session) { @@ -249,8 +254,8 @@ private function getUserFromSession(): ?\Illuminate\Contracts\Auth\Authenticatab * Handle instances of session token expiration. */ private function handleSessionExpiration( - ?\Illuminate\Contracts\Auth\Authenticatable $user, - ): ?\Illuminate\Contracts\Auth\Authenticatable { + ?Authenticatable $user, + ): ?Authenticatable { $state = $this->getState(); // Unless our token expired, we have nothing to do here. @@ -262,14 +267,14 @@ private function handleSessionExpiration( if (null !== $state->getRefreshToken()) { try { // Try to renew our token. - app(\Auth0\Laravel\Auth0::class)->getSdk()->renew(); + app(Auth0::class)->getSdk()->renew(); } catch (\Auth0\SDK\Exception\StateException $tokenRefreshFailed) { // Renew failed. Inform application. event(new \Auth0\Laravel\Event\Stateful\TokenRefreshFailed()); } // Retrieve updated state data - $refreshed = app(\Auth0\Laravel\Auth0::class)->getSdk()->getCredentials(); + $refreshed = app(Auth0::class)->getSdk()->getCredentials(); // @phpstan-ignore-next-line if (null !== $refreshed && false === $refreshed->accessTokenExpired) { @@ -282,7 +287,7 @@ private function handleSessionExpiration( // We didn't have a refresh token, or the refresh failed. // Clear session. $state->clear(); - app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); + app(Auth0::class)->getSdk()->clear(); // Inform host application. event(new \Auth0\Laravel\Event\Stateful\TokenExpired()); @@ -293,15 +298,15 @@ private function handleSessionExpiration( /** * Return the current request's StateInstance singleton. */ - private function getState(): \Auth0\Laravel\StateInstance + private function getState(): StateInstance { - return app(\Auth0\Laravel\StateInstance::class); + return app(ConcreteStateInstance::class); } /** * Return the current request's StateInstance singleton. */ - private function getProvider(): \Illuminate\Contracts\Auth\UserProvider + private function getProvider(): UserProvider { static $provider = null; @@ -312,7 +317,7 @@ private function getProvider(): \Illuminate\Contracts\Auth\UserProvider $configured = config('auth.guards.auth0.provider') ?? \Auth0\Laravel\Auth\User\Provider::class; $provider = app('auth')->createUserProvider($configured); - if (! $provider instanceof \Illuminate\Contracts\Auth\UserProvider) { + if (! $provider instanceof UserProvider) { throw new RuntimeException('Auth0: Unable to invoke UserProvider from application configuration.'); } } diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php index 9d3d2152..487fd927 100644 --- a/src/Auth/User/Provider.php +++ b/src/Auth/User/Provider.php @@ -4,6 +4,8 @@ namespace Auth0\Laravel\Auth\User; +use Illuminate\Contracts\Auth\Authenticatable; + final class Provider implements \Auth0\Laravel\Contract\Auth\User\Provider, \Illuminate\Contracts\Auth\UserProvider { /** @@ -11,7 +13,7 @@ final class Provider implements \Auth0\Laravel\Contract\Auth\User\Provider, \Ill * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ - public function retrieveById($identifier): ?\Illuminate\Contracts\Auth\Authenticatable + public function retrieveById($identifier): ?Authenticatable { return null; } @@ -21,7 +23,7 @@ public function retrieveById($identifier): ?\Illuminate\Contracts\Auth\Authentic * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ - public function retrieveByToken($identifier, $token): ?\Illuminate\Contracts\Auth\Authenticatable + public function retrieveByToken($identifier, $token): ?Authenticatable { return null; } @@ -31,7 +33,7 @@ public function retrieveByToken($identifier, $token): ?\Illuminate\Contracts\Aut * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ - public function retrieveByCredentials(array $credentials): ?\Illuminate\Contracts\Auth\Authenticatable + public function retrieveByCredentials(array $credentials): ?Authenticatable { return null; } @@ -42,7 +44,7 @@ public function retrieveByCredentials(array $credentials): ?\Illuminate\Contract * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ public function validateCredentials( - \Illuminate\Contracts\Auth\Authenticatable $user, + Authenticatable $user, array $credentials, ): bool { return false; @@ -53,7 +55,7 @@ public function validateCredentials( * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ - public function updateRememberToken(\Illuminate\Contracts\Auth\Authenticatable $user, $token): void + public function updateRememberToken(Authenticatable $user, $token): void { } diff --git a/src/Auth/User/Repository.php b/src/Auth/User/Repository.php index 8e90781e..5a9995a2 100644 --- a/src/Auth/User/Repository.php +++ b/src/Auth/User/Repository.php @@ -4,12 +4,14 @@ namespace Auth0\Laravel\Auth\User; +use Illuminate\Contracts\Auth\Authenticatable; + final class Repository implements \Auth0\Laravel\Contract\Auth\User\Repository { /** * {@inheritdoc} */ - public function fromSession(array $user): ?\Illuminate\Contracts\Auth\Authenticatable + public function fromSession(array $user): ?Authenticatable { return new \Auth0\Laravel\Model\Stateful\User($user); } @@ -17,7 +19,7 @@ public function fromSession(array $user): ?\Illuminate\Contracts\Auth\Authentica /** * {@inheritdoc} */ - public function fromAccessToken(array $user): ?\Illuminate\Contracts\Auth\Authenticatable + public function fromAccessToken(array $user): ?Authenticatable { return new \Auth0\Laravel\Model\Stateless\User($user); } diff --git a/src/Auth0.php b/src/Auth0.php index eed47ca6..3fd9c078 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -118,9 +118,9 @@ public function setConfiguration(Configuration $configuration): self /** * {@inheritdoc} */ - public function getState(): Contract\StateInstance + public function getState(): \Auth0\Laravel\Contract\StateInstance { - return app(\Auth0\Laravel\StateInstance::class); + return app(StateInstance::class); } /** diff --git a/src/Contract/Auth/User/Repository.php b/src/Contract/Auth/User/Repository.php index a9651bb0..5f74e165 100644 --- a/src/Contract/Auth/User/Repository.php +++ b/src/Contract/Auth/User/Repository.php @@ -4,6 +4,8 @@ namespace Auth0\Laravel\Contract\Auth\User; +use Illuminate\Contracts\Auth\Authenticatable; + interface Repository { /** @@ -11,12 +13,12 @@ interface Repository * * @param array $user an array containing the raw Auth0 user data */ - public function fromSession(array $user): ?\Illuminate\Contracts\Auth\Authenticatable; + public function fromSession(array $user): ?Authenticatable; /** * Generate a \Auth0\Laravel\Model\Stateful\User instance from a parsed Access Token. * * @param array $user an array containing the raw Auth0 user data */ - public function fromAccessToken(array $user): ?\Illuminate\Contracts\Auth\Authenticatable; + public function fromAccessToken(array $user): ?Authenticatable; } diff --git a/src/Contract/Auth0.php b/src/Contract/Auth0.php index f49e03d7..5089fb7d 100644 --- a/src/Contract/Auth0.php +++ b/src/Contract/Auth0.php @@ -4,27 +4,30 @@ namespace Auth0\Laravel\Contract; +use Auth0\SDK\Configuration\SdkConfiguration as Configuration; +use Auth0\SDK\Contract\Auth0Interface as SDK; + interface Auth0 { /** * Create/return instance of the Auth0-PHP SDK. */ - public function getSdk(): \Auth0\SDK\Contract\Auth0Interface; + public function getSdk(): SDK; /** * Create/return instance of the Auth0-PHP SDK. */ - public function setSdk(\Auth0\SDK\Contract\Auth0Interface $sdk): self; + public function setSdk(SDK $sdk): self; /** * Create/return instance of the Auth0-PHP SdkConfiguration. */ - public function getConfiguration(): \Auth0\SDK\Configuration\SdkConfiguration; + public function getConfiguration(): Configuration; /** * Assign the Auth0-PHP SdkConfiguration. */ - public function setConfiguration(\Auth0\SDK\Configuration\SdkConfiguration $configuration): self; + public function setConfiguration(Configuration $configuration): self; /** * Create/create a request state instance, a storage singleton containing authenticated user data. diff --git a/src/Contract/Event/Stateful/AuthenticationSucceeded.php b/src/Contract/Event/Stateful/AuthenticationSucceeded.php index b0b892e8..6b23708b 100644 --- a/src/Contract/Event/Stateful/AuthenticationSucceeded.php +++ b/src/Contract/Event/Stateful/AuthenticationSucceeded.php @@ -4,24 +4,26 @@ namespace Auth0\Laravel\Contract\Event\Stateful; +use Illuminate\Contracts\Auth\Authenticatable; + interface AuthenticationSucceeded { /** * AuthenticationSucceeded constructor. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user an instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user + * @param Authenticatable $user an instance of Authenticatable representing the authenticated user */ - public function __construct(\Illuminate\Contracts\Auth\Authenticatable $user); + public function __construct(Authenticatable $user); /** * Overwrite the authenticated user. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user an instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user + * @param Authenticatable $user an instance of Authenticatable representing the authenticated user */ - public function setUser(\Illuminate\Contracts\Auth\Authenticatable $user): self; + public function setUser(Authenticatable $user): self; /** * Return the authenticated user. */ - public function getUser(): \Illuminate\Contracts\Auth\Authenticatable; + public function getUser(): Authenticatable; } diff --git a/src/Contract/StateInstance.php b/src/Contract/StateInstance.php index e6b91828..fe356552 100644 --- a/src/Contract/StateInstance.php +++ b/src/Contract/StateInstance.php @@ -4,6 +4,8 @@ namespace Auth0\Laravel\Contract; +use Illuminate\Contracts\Auth\Authenticatable; + interface StateInstance { /** @@ -14,14 +16,14 @@ public function clear(): self; /** * Return the authenticated user context for the current request. */ - public function getUser(): ?\Illuminate\Contracts\Auth\Authenticatable; + public function getUser(): ?Authenticatable; /** * Set the authenticated user context for the current request. * - * @param \Illuminate\Contracts\Auth\Authenticatable|null $user an authenticated user context + * @param Authenticatable|null $user an authenticated user context */ - public function setUser(?\Illuminate\Contracts\Auth\Authenticatable $user): self; + public function setUser(?Authenticatable $user): self; /** * Retrieve the decoded token data for the request context, if available. diff --git a/src/Event/Configuration/Built.php b/src/Event/Configuration/Built.php index 54869b1c..31076df1 100644 --- a/src/Event/Configuration/Built.php +++ b/src/Event/Configuration/Built.php @@ -4,19 +4,19 @@ namespace Auth0\Laravel\Event\Configuration; -use Auth0\SDK\Configuration\SdkConfiguration; +use Auth0\SDK\Configuration\SdkConfiguration as Configuration; final class Built extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Configuration\Built { /** * Whether or not $exception will be thrown. */ - private SdkConfiguration $configuration; + private Configuration $configuration; /** * {@inheritdoc} */ - public function __construct(SdkConfiguration $configuration) + public function __construct(Configuration $configuration) { $this->configuration = $configuration; } @@ -24,7 +24,7 @@ public function __construct(SdkConfiguration $configuration) /** * {@inheritdoc} */ - public function setConfiguration(SdkConfiguration $configuration): self + public function setConfiguration(Configuration $configuration): self { $this->configuration = $configuration; @@ -34,7 +34,7 @@ public function setConfiguration(SdkConfiguration $configuration): self /** * {@inheritdoc} */ - public function getConfiguration(): SdkConfiguration + public function getConfiguration(): Configuration { return $this->configuration; } diff --git a/src/Event/Stateful/AuthenticationSucceeded.php b/src/Event/Stateful/AuthenticationSucceeded.php index e3ac789e..7c869776 100644 --- a/src/Event/Stateful/AuthenticationSucceeded.php +++ b/src/Event/Stateful/AuthenticationSucceeded.php @@ -4,17 +4,19 @@ namespace Auth0\Laravel\Event\Stateful; +use Illuminate\Contracts\Auth\Authenticatable; + final class AuthenticationSucceeded extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Stateful\AuthenticationSucceeded { /** * An instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user. */ - private \Illuminate\Contracts\Auth\Authenticatable $user; + private Authenticatable $user; /** * {@inheritdoc} */ - public function __construct(\Illuminate\Contracts\Auth\Authenticatable $user) + public function __construct(Authenticatable $user) { $this->user = $user; } @@ -22,7 +24,7 @@ public function __construct(\Illuminate\Contracts\Auth\Authenticatable $user) /** * {@inheritdoc} */ - public function setUser(\Illuminate\Contracts\Auth\Authenticatable $user): self + public function setUser(Authenticatable $user): self { $this->user = $user; $this->mutated = true; @@ -33,7 +35,7 @@ public function setUser(\Illuminate\Contracts\Auth\Authenticatable $user): self /** * {@inheritdoc} */ - public function getUser(): \Illuminate\Contracts\Auth\Authenticatable + public function getUser(): Authenticatable { return $this->user; } diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index 46a748ef..131c8ce4 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -13,16 +13,15 @@ final class Callback implements \Auth0\Laravel\Contract\Http\Controller\Stateful */ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse { - $auth = auth(); - /** * @var \Illuminate\Contracts\Auth\Factory $auth */ - $guard = $auth->guard('auth0'); + $auth = auth(); /** * @var Guard $guard */ + $guard = $auth->guard('auth0'); // Check if the user already has a session: if ($guard->check()) { diff --git a/src/StateInstance.php b/src/StateInstance.php index 9b2e1b4b..fbdf369e 100644 --- a/src/StateInstance.php +++ b/src/StateInstance.php @@ -4,12 +4,14 @@ namespace Auth0\Laravel; +use Illuminate\Contracts\Auth\Authenticatable; + final class StateInstance implements \Auth0\Laravel\Contract\StateInstance { /** * An authenticated user context for the current request. */ - private ?\Illuminate\Contracts\Auth\Authenticatable $user = null; + private ?Authenticatable $user = null; /** * Decoded token data from the request context. @@ -60,7 +62,7 @@ public function clear(): self /** * {@inheritdoc} */ - public function getUser(): ?\Illuminate\Contracts\Auth\Authenticatable + public function getUser(): ?Authenticatable { return $this->user; } @@ -68,7 +70,7 @@ public function getUser(): ?\Illuminate\Contracts\Auth\Authenticatable /** * {@inheritdoc} */ - public function setUser(?\Illuminate\Contracts\Auth\Authenticatable $user): self + public function setUser(?Authenticatable $user): self { $this->user = $user; From 5f3916e3f643d8dcfd1338fc9609542084a556ec Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 12 Oct 2022 21:59:19 -0500 Subject: [PATCH 148/525] Refactor DI and ServiceProvider for improved Octane compatibility --- src/Auth0.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Auth0.php b/src/Auth0.php index 3fd9c078..7ce785b4 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -118,7 +118,7 @@ public function setConfiguration(Configuration $configuration): self /** * {@inheritdoc} */ - public function getState(): \Auth0\Laravel\Contract\StateInstance + public function getState(): Contract\StateInstance { return app(StateInstance::class); } From cdec5f09b61278845e2d40a5fafca7f84aa090d7 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 13:17:22 -0500 Subject: [PATCH 149/525] Delete phpinsights.php --- phpinsights.php | 66 ------------------------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 phpinsights.php diff --git a/phpinsights.php b/phpinsights.php deleted file mode 100644 index e906663d..00000000 --- a/phpinsights.php +++ /dev/null @@ -1,66 +0,0 @@ - 'laravel', - 'ide' => null, - - 'exclude' => [], - - 'add' => [ - \NunoMaduro\PhpInsights\Domain\Metrics\Code\Comments::class => [ - \SlevomatCodingStandard\Sniffs\Classes\RequireMultiLineMethodSignatureSniff::class, - ], - ], - - 'remove' => [ - \NunoMaduro\PhpInsights\Domain\Insights\CyclomaticComplexityIsHigh::class, - \NunoMaduro\PhpInsights\Domain\Insights\ForbiddenGlobals::class, - \NunoMaduro\PhpInsights\Domain\Insights\ForbiddenNormalClasses::class, - \NunoMaduro\PhpInsights\Domain\Insights\ForbiddenTraits::class, - \NunoMaduro\PhpInsights\Domain\Sniffs\ForbiddenSetterSniff::class, - \ObjectCalisthenics\Sniffs\Files\ClassTraitAndInterfaceLengthSniff::class, - \ObjectCalisthenics\Sniffs\Files\FunctionLengthSniff::class, - \ObjectCalisthenics\Sniffs\Metrics\MethodPerClassLimitSniff::class, - \ObjectCalisthenics\Sniffs\Metrics\MaxNestingLevelSniff::class, - \PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff::class, - \PHP_CodeSniffer\Standards\Generic\Sniffs\Commenting\TodoSniff::class, - \SlevomatCodingStandard\Sniffs\Classes\SuperfluousExceptionNamingSniff::class, - \SlevomatCodingStandard\Sniffs\Classes\SuperfluousInterfaceNamingSniff::class, - \SlevomatCodingStandard\Sniffs\Classes\UnusedPrivateElementsSniff::class, - \SlevomatCodingStandard\Sniffs\Functions\FunctionLengthSniff::class, - \SlevomatCodingStandard\Sniffs\TypeHints\DisallowMixedTypeHintSniff::class, - \SlevomatCodingStandard\Sniffs\TypeHints\ParameterTypeHintSniff::class, - \SlevomatCodingStandard\Sniffs\TypeHints\PropertyTypeHintSniff::class, - \SlevomatCodingStandard\Sniffs\TypeHints\ReturnTypeHintSniff::class, - \SlevomatCodingStandard\Sniffs\Commenting\UselessInheritDocCommentSniff::class, - ], - - 'config' => [ - \PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\DeprecatedFunctionsSniff::class => [ - 'exclude' => [ - ], - ], - \SlevomatCodingStandard\Sniffs\Functions\UnusedParameterSniff::class => [ - 'exclude' => [ - 'src/ServiceProvider.php', - ], - ], - \SlevomatCodingStandard\Sniffs\Classes\ModernClassNameReferenceSniff::class => [ - 'exclude' => [ - ], - ], - \SlevomatCodingStandard\Sniffs\Classes\RequireMultiLineMethodSignatureSniff::class => [ - 'minLineLength' => '0', - ], - ], - - 'requirements' => [ - 'min-quality' => 100, - 'min-complexity' => 50, - 'min-architecture' => 100, - 'min-style' => 100, - 'disable-security-check' => false, - ], -]; From 2d8fb3c87c3f7c71cd0fc7426d4cce4ef6e8a777 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 13:18:17 -0500 Subject: [PATCH 150/525] Update GitHub checks --- .github/workflows/checks.yml | 290 +++++++++++++++++- .../{repo-maintenance.yml => maintenance.yml} | 0 .github/workflows/tests.yml | 259 ---------------- composer.json | 19 +- 4 files changed, 304 insertions(+), 264 deletions(-) rename .github/workflows/{repo-maintenance.yml => maintenance.yml} (100%) delete mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 684766d6..4e215806 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -7,13 +7,295 @@ on: pull_request: jobs: - composer-normalize: - name: Composer Normalize + dependencies: + name: Dependencies runs-on: ubuntu-latest + strategy: + max-parallel: 10 + matrix: + php: ["8.0", "8.1", "8.2"] + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + extensions: mbstring + env: + update: true + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + + - name: Install dependencies with composer + run: composer update --no-ansi --no-interaction --no-progress --prefer-dist --prefer-stable + + phpstan: + name: Normalize + runs-on: ubuntu-latest + needs: ["dependencies"] + + strategy: + fail-fast: true + max-parallel: 10 + matrix: + php: ["8.0"] + steps: + - name: Set up PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + extensions: mbstring + env: + update: true + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Checkout code uses: actions/checkout@v3 - - name: Composer normalize - uses: docker://ergebnis/composer-normalize-action + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + + - name: Install dependencies + run: composer install --prefer-dist + + - name: Execute Normalize + run: composer normalize + + pest: + name: Pest + runs-on: ubuntu-latest + continue-on-error: true + needs: ["dependencies"] + + strategy: + max-parallel: 10 + matrix: + php: ["8.0", "8.1", "8.2"] + + steps: + - name: Set up PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: pcov + extensions: mbstring + env: + update: true + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + + - name: Install dependencies with composer + run: composer install --prefer-dist + + - name: Execute Pest + run: vendor/bin/pest --coverage-clover coverage/coverage.xml --no-interaction + + - if: (matrix.php == '8.1') + uses: codecov/codecov-action@v2 + with: + directory: coverage + + phpstan: + name: PHPStan + runs-on: ubuntu-latest + needs: ["dependencies"] + + strategy: + fail-fast: true + max-parallel: 10 + matrix: + php: ["8.0", "8.1", "8.2"] + + steps: + - name: Set up PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + extensions: mbstring + env: + update: true + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + + - name: Install dependencies + run: composer install --prefer-dist + + - name: Execute PHPStan + run: vendor/bin/phpstan analyze --no-progress + + psalm: + name: Psalm + runs-on: ubuntu-latest + needs: ["dependencies"] + + strategy: + fail-fast: true + max-parallel: 10 + matrix: + php: ["8.0", "8.1", "8.2"] + + steps: + - name: Set up PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + extensions: mbstring + env: + update: true + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + + - name: Install dependencies + run: composer install --prefer-dist + + - name: Execute Psalm + run: vendor/bin/psalm --no-progress + + pint: + name: Laravel Pint + runs-on: ubuntu-latest + needs: ["dependencies"] + + strategy: + fail-fast: true + max-parallel: 10 + matrix: + php: ["8.0", "8.1", "8.2"] + + steps: + - name: Set up PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + extensions: mbstring + env: + update: true + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + + - name: Install dependencies + run: composer install --prefer-dist + + - name: Execute Laravel Pint + run: vendor/bin/pint --test + + rector: + name: Rector + runs-on: ubuntu-latest + needs: ["dependencies"] + + strategy: + fail-fast: true + max-parallel: 10 + matrix: + php: ["8.0", "8.1", "8.2"] + + steps: + - name: Set up PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + extensions: mbstring + env: + update: true + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} + + - name: Install dependencies + run: composer install --prefer-dist + + - name: Execute Rector + run: vendor/bin/rector process src --dry-run diff --git a/.github/workflows/repo-maintenance.yml b/.github/workflows/maintenance.yml similarity index 100% rename from .github/workflows/repo-maintenance.yml rename to .github/workflows/maintenance.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml deleted file mode 100644 index ff0a89c3..00000000 --- a/.github/workflows/tests.yml +++ /dev/null @@ -1,259 +0,0 @@ -name: Analysis - -on: - push: - branches: - - main - pull_request: - -jobs: - dependencies: - name: Dependencies - runs-on: ubuntu-latest - - strategy: - max-parallel: 10 - matrix: - php: ["8.0", "8.1", "8.2"] - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: mbstring - env: - update: true - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - - name: Install dependencies with composer - run: composer update --no-ansi --no-interaction --no-progress --prefer-dist --prefer-stable - - pest: - name: Pest - runs-on: ubuntu-latest - continue-on-error: true - needs: ["dependencies"] - - strategy: - max-parallel: 10 - matrix: - php: ["8.0", "8.1", "8.2"] - - steps: - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: pcov - extensions: mbstring - env: - update: true - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - - name: Install dependencies with composer - run: composer install --prefer-dist - - - name: Execute Pest - run: vendor/bin/pest --coverage-clover coverage/coverage.xml --no-interaction - - - if: (matrix.php == '8.1') - uses: codecov/codecov-action@v2 - with: - directory: coverage - - phpstan: - name: PHPStan - runs-on: ubuntu-latest - needs: ["dependencies"] - - strategy: - fail-fast: true - max-parallel: 10 - matrix: - php: ["8.0", "8.1", "8.2"] - - steps: - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: mbstring - env: - update: true - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - - name: Install dependencies - run: composer install --prefer-dist - - - name: Execute PHPStan - run: vendor/bin/phpstan analyze --no-progress - - psalm: - name: Psalm - runs-on: ubuntu-latest - needs: ["dependencies"] - - strategy: - fail-fast: true - max-parallel: 10 - matrix: - php: ["8.0", "8.1", "8.2"] - - steps: - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: mbstring - env: - update: true - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - - name: Install dependencies - run: composer install --prefer-dist - - - name: Execute Psalm - run: vendor/bin/psalm --no-progress - - pint: - name: Laravel Pint - runs-on: ubuntu-latest - needs: ["dependencies"] - - strategy: - fail-fast: true - max-parallel: 10 - matrix: - php: ["8.0", "8.1", "8.2"] - - steps: - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: mbstring - env: - update: true - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - - name: Install dependencies - run: composer install --prefer-dist - - - name: Execute Laravel Pint - run: vendor/bin/pint --test - - rector: - name: Rector - runs-on: ubuntu-latest - needs: ["dependencies"] - - strategy: - fail-fast: true - max-parallel: 10 - matrix: - php: ["8.0", "8.1", "8.2"] - - steps: - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: mbstring - env: - update: true - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - - name: Install dependencies - run: composer install --prefer-dist - - - name: Execute Rector - run: vendor/bin/rector process src --dry-run diff --git a/composer.json b/composer.json index bb88fc43..f0d8d387 100644 --- a/composer.json +++ b/composer.json @@ -40,6 +40,7 @@ "illuminate/support": "^8.0 || ^9.0" }, "require-dev": { + "ergebnis/composer-normalize": "dev-main", "laravel/laravel": "^8.4.4 || ^9.0", "laravel/pint": "^1.2", "nunomaduro/larastan": "^1.0", @@ -55,6 +56,7 @@ "vimeo/psalm": "^4.28", "wikimedia/composer-merge-plugin": "^2.0" }, + "minimum-stability": "dev", "autoload": { "psr-4": { "Auth0\\Laravel\\": "src" @@ -68,12 +70,17 @@ "config": { "allow-plugins": { "pestphp/pest-plugin": true, - "wikimedia/composer-merge-plugin": true + "wikimedia/composer-merge-plugin": true, + "ergebnis/composer-normalize": true }, "optimize-autoloader": true, "sort-packages": true }, "extra": { + "composer-normalize": { + "indent-size": 4, + "indent-style": "space" + }, "laravel": { "aliases": { "Auth0": "Auth0\\Laravel\\Facade\\Auth0" @@ -94,5 +101,15 @@ "recurse": true, "replace": true } + }, + "scripts": { + "phpstan": "@php vendor/bin/phpstan analyse", + "phpstan:pro": "@php vendor/bin/phpstan analyse --pro", + "pint": "@php vendor/bin/pint --test", + "pint:fix": "@php vendor/bin/pint", + "psalm": "@php vendor/bin/psalm", + "rector": "@php vendor/bin/rector process src --dry-run", + "rector:fix": "@php vendor/bin/rector process src", + "test": "@php vendor/bin/pest --order-by random" } } From b7c497244d9ce1961074d45ad0b2728717db022b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 13:21:52 -0500 Subject: [PATCH 151/525] Update checks.yml --- .github/workflows/checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 4e215806..2d965938 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -43,7 +43,7 @@ jobs: - name: Install dependencies with composer run: composer update --no-ansi --no-interaction --no-progress --prefer-dist --prefer-stable - phpstan: + normalize: name: Normalize runs-on: ubuntu-latest needs: ["dependencies"] From 630d593ded119f0693e03fa83ba6e3650dfa03c5 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 14:06:38 -0500 Subject: [PATCH 152/525] Update composer.json --- composer.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/composer.json b/composer.json index f0d8d387..f3ab578b 100644 --- a/composer.json +++ b/composer.json @@ -28,6 +28,12 @@ } ], "homepage": "https://github.com/auth0/laravel-auth0", + "support": { + "email": "support@auth0.com", + "issues": "https://github.com/auth0/laravel-auth0/issues", + "forum": "https://community.auth0.com/", + "source": "https://github.com/auth0/laravel-auth0" + }, "require": { "php": "^8.0", "ext-filter": "*", @@ -57,6 +63,7 @@ "wikimedia/composer-merge-plugin": "^2.0" }, "minimum-stability": "dev", + "prefer-stable": true, "autoload": { "psr-4": { "Auth0\\Laravel\\": "src" @@ -108,6 +115,7 @@ "pint": "@php vendor/bin/pint --test", "pint:fix": "@php vendor/bin/pint", "psalm": "@php vendor/bin/psalm", + "psalm:fix": "@php vendor/bin/psalter --issues=all", "rector": "@php vendor/bin/rector process src --dry-run", "rector:fix": "@php vendor/bin/rector process src", "test": "@php vendor/bin/pest --order-by random" From 575615d75f434ff354823772ddee51bcff21e474 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 14:59:20 -0500 Subject: [PATCH 153/525] CacheItemInterface and CacheItemPoolInterface improvements --- composer.json | 2 - src/Cache/LaravelCacheItem.php | 93 ++++++++++++++++++---------------- src/Cache/LaravelCachePool.php | 16 +++--- 3 files changed, 57 insertions(+), 54 deletions(-) diff --git a/composer.json b/composer.json index f3ab578b..9202cff6 100644 --- a/composer.json +++ b/composer.json @@ -36,10 +36,8 @@ }, "require": { "php": "^8.0", - "ext-filter": "*", "ext-json": "*", "ext-mbstring": "*", - "ext-openssl": "*", "auth0/auth0-php": "^8.0", "illuminate/contracts": "^8.0 || ^9.0", "illuminate/http": "^8.0 || ^9.0", diff --git a/src/Cache/LaravelCacheItem.php b/src/Cache/LaravelCacheItem.php index 6dd930a0..8f79e15d 100644 --- a/src/Cache/LaravelCacheItem.php +++ b/src/Cache/LaravelCacheItem.php @@ -4,93 +4,100 @@ namespace Auth0\Laravel\Cache; -use DateInterval; -use DateTime; -use DateTimeInterface; use Psr\Cache\CacheItemInterface; final class LaravelCacheItem implements CacheItemInterface { - private ?int $expires = null; - private string $key; private mixed $value; - private bool $is_hit; + private bool $hit; + + private ?\DateTimeInterface $expiration; - public function __construct(string $key, mixed $value, bool $is_hit) + public function __construct(string $key, mixed $value, bool $hit) { $this->key = $key; $this->value = $value; - $this->is_hit = $is_hit; + $this->hit = $hit; } + /** + * {@inheritdoc} + */ public function getKey(): string { return $this->key; } + /** + * {@inheritdoc} + */ public function get(): mixed { - return $this->value; + return $this->isHit() ? $this->value : null; + } + + /** + * {@inheritdoc} + */ + public function set($value = null): static + { + $this->value = $value; + return $this; } + /** + * {@inheritdoc} + */ public function isHit(): bool { - return $this->is_hit; + return $this->hit; } - public function set(mixed $value): static + /** + * {@inheritdoc} + */ + public function expiresAt(?\DateTimeInterface $expiration): static { - $this->value = $value; - $this->is_hit = true; + $this->expiration = $expiration ?? new \DateTimeImmutable('now +1 year'); return $this; } - public function expiresAt(mixed $expiration): static + /** + * {@inheritdoc} + */ + public function expiresAfter(int|\DateInterval|null $time): static { - if ($expiration instanceof DateTimeInterface) { - $this->expires = $expiration->getTimestamp(); - - return $this; - } - - $this->expires = $expiration; - + $this->expiration = match (true) { + is_null($time) => new \DateTimeImmutable('now +1 year'), + is_int($time) => new \DateTimeImmutable('now +' . $time . ' seconds'), + $time instanceof \DateInterval => (new \DateTimeImmutable())->add($time), /** @phpstan-ignore-line */ + }; return $this; } /** - * @param DateInterval|int|null $time + * Returns the expiration timestamp. */ - public function expiresAfter(mixed $time): static + public function getExpiration(): \DateTimeInterface { - if (null === $time) { - $this->expires = null; - - return $this; - } - - if ($time instanceof DateInterval) { - $dateTime = new DateTime(); - $dateTime->add($time); - $this->expires = $dateTime->getTimestamp(); - - return $this; - } - - $this->expires = time() + $time; - - return $this; + return $this->expiration ?? new \DateTime('now +1 year'); } - public function expirationTimestamp(): ?int + /** + * Returns the raw value, regardless of hit status. + */ + public function getRawValue(): mixed { - return $this->expires; + return $this->value; } + /** + * Return a LaravelCacheItem instance flagged as missed. + */ public static function miss(string $key): self { return new self($key, null, false); diff --git a/src/Cache/LaravelCachePool.php b/src/Cache/LaravelCachePool.php index 1b3bf61a..5f56e0a6 100644 --- a/src/Cache/LaravelCachePool.php +++ b/src/Cache/LaravelCachePool.php @@ -14,7 +14,7 @@ final class LaravelCachePool implements CacheItemPoolInterface { /** - * @var array + * @var array */ private array $deferred = []; @@ -99,17 +99,15 @@ public function save(CacheItemInterface $item): bool $value = serialize($item->get()); $key = $item->getKey(); - $expires = $item->expirationTimestamp(); + $expires = $item->getExpiration(); $ttl = 0; - if (null !== $expires) { - if ($expires <= time()) { - return $this->deleteItem($key); - } - - $ttl = $expires - time(); + if ($expires->getTimestamp() <= time()) { + return $this->deleteItem($key); } + $ttl = $expires->getTimestamp() - time(); + return $this->getStore()-> put($key, $value, $ttl); } @@ -122,7 +120,7 @@ public function saveDeferred(CacheItemInterface $item): bool $this->deferred[$item->getKey()] = [ 'item' => $item, - 'expiration' => $item->expirationTimestamp(), + 'expiration' => $item->getExpiration(), ]; return true; From e1d498f4e2ad7779ff2f2a028ec24c5b31f35f1c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 15:08:57 -0500 Subject: [PATCH 154/525] Refactor DI and ServiceProvider for improved Octane compatibility --- .github/workflows/security.yml | 21 +++++++++--------- src/Cache/LaravelCacheItem.php | 22 +++++++++---------- src/Cache/LaravelCachePool.php | 4 +--- src/Contract/Model/User.php | 2 +- src/Event/Configuration/Built.php | 8 +------ src/Event/Stateful/AuthenticationFailed.php | 17 ++++---------- .../Stateful/AuthenticationSucceeded.php | 7 +----- src/Model/User.php | 7 +----- src/Store/LaravelSession.php | 22 ++++++------------- 9 files changed, 37 insertions(+), 73 deletions(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index b7f2badc..10fd3096 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -70,14 +70,15 @@ jobs: SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} SEMGREP_REPO_NAME: "auth0/laravel-auth0" SEMGREP_REPO_URL: "https://github.com/auth0/laravel-auth0" -# - name: Check to see if the SARIF a was generated -# id: sarif_file_exists -# uses: andstor/file-existence-action@v1 -# with: -# files: "semgrep.sarif" -# - name: Upload SARIF file for GitHub Advanced Security Dashboard -# uses: github/codeql-action/upload-sarif@v2 -# with: -# sarif_file: semgrep.sarif -# if: always() + - name: Check to see if the SARIF a was generated + id: sarif_file_exists + uses: andstor/file-existence-action@v1 + with: + files: "semgrep.sarif" + + - name: Upload SARIF file for GitHub Advanced Security Dashboard + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: semgrep.sarif + if: always() diff --git a/src/Cache/LaravelCacheItem.php b/src/Cache/LaravelCacheItem.php index 8f79e15d..9fc932d7 100644 --- a/src/Cache/LaravelCacheItem.php +++ b/src/Cache/LaravelCacheItem.php @@ -8,19 +8,13 @@ final class LaravelCacheItem implements CacheItemInterface { - private string $key; - private mixed $value; - - private bool $hit; - - private ?\DateTimeInterface $expiration; - - public function __construct(string $key, mixed $value, bool $hit) + public function __construct( + private string $key, + private mixed $value, + private bool $hit, + private ?\DateTimeInterface $expiration = null) { - $this->key = $key; - $this->value = $value; - $this->hit = $hit; } /** @@ -100,6 +94,10 @@ public function getRawValue(): mixed */ public static function miss(string $key): self { - return new self($key, null, false); + return new self( + key: $key, + value: null, + hit: false + ); } } diff --git a/src/Cache/LaravelCachePool.php b/src/Cache/LaravelCachePool.php index 5f56e0a6..335fcbca 100644 --- a/src/Cache/LaravelCachePool.php +++ b/src/Cache/LaravelCachePool.php @@ -100,7 +100,6 @@ public function save(CacheItemInterface $item): bool $value = serialize($item->get()); $key = $item->getKey(); $expires = $item->getExpiration(); - $ttl = 0; if ($expires->getTimestamp() <= time()) { return $this->deleteItem($key); @@ -108,8 +107,7 @@ public function save(CacheItemInterface $item): bool $ttl = $expires->getTimestamp() - time(); - return $this->getStore()-> - put($key, $value, $ttl); + return $this->getStore()->put($key, $value, $ttl); } public function saveDeferred(CacheItemInterface $item): bool diff --git a/src/Contract/Model/User.php b/src/Contract/Model/User.php index 65cdeb9a..e63d5ec0 100644 --- a/src/Contract/Model/User.php +++ b/src/Contract/Model/User.php @@ -11,7 +11,7 @@ interface User * * @param array $attributes attributes representing the user data */ - public function __construct(array $attributes = []); + public function __construct(private array $attributes = []); /** * Dynamically retrieve attributes on the model. diff --git a/src/Event/Configuration/Built.php b/src/Event/Configuration/Built.php index 31076df1..5e851c93 100644 --- a/src/Event/Configuration/Built.php +++ b/src/Event/Configuration/Built.php @@ -8,17 +8,11 @@ final class Built extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Configuration\Built { - /** - * Whether or not $exception will be thrown. - */ - private Configuration $configuration; - /** * {@inheritdoc} */ - public function __construct(Configuration $configuration) + public function __construct(private Configuration $configuration) { - $this->configuration = $configuration; } /** diff --git a/src/Event/Stateful/AuthenticationFailed.php b/src/Event/Stateful/AuthenticationFailed.php index cbb8434d..c9c32582 100644 --- a/src/Event/Stateful/AuthenticationFailed.php +++ b/src/Event/Stateful/AuthenticationFailed.php @@ -6,23 +6,14 @@ final class AuthenticationFailed extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Stateful\AuthenticationFailed { - /** - * An exception instance in which to throw for the authentication failure. - */ - private \Throwable $exception; - - /** - * Whether or not $exception will be thrown. - */ - private bool $throwException = true; - /** * {@inheritdoc} */ - public function __construct(\Throwable $exception, bool $throwException = true) + public function __construct( + private \Throwable $exception, + private bool $throwException = true + ) { - $this->exception = $exception; - $this->throwException = $throwException; } /** diff --git a/src/Event/Stateful/AuthenticationSucceeded.php b/src/Event/Stateful/AuthenticationSucceeded.php index 7c869776..8e7ebbc8 100644 --- a/src/Event/Stateful/AuthenticationSucceeded.php +++ b/src/Event/Stateful/AuthenticationSucceeded.php @@ -8,15 +8,10 @@ final class AuthenticationSucceeded extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Stateful\AuthenticationSucceeded { - /** - * An instance of \Illuminate\Contracts\Auth\Authenticatable representing the authenticated user. - */ - private Authenticatable $user; - /** * {@inheritdoc} */ - public function __construct(Authenticatable $user) + public function __construct(private Authenticatable $user) { $this->user = $user; } diff --git a/src/Model/User.php b/src/Model/User.php index 44f90b2f..f3881155 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -6,15 +6,10 @@ abstract class User implements \Illuminate\Contracts\Auth\Authenticatable, \Auth0\Laravel\Contract\Model\User { - /** - * The model's attributes. - */ - private array $attributes = []; - /** * {@inheritdoc} */ - public function __construct(array $attributes = []) + public function __construct(private array $attributes = []) { $this->fill($attributes); } diff --git a/src/Store/LaravelSession.php b/src/Store/LaravelSession.php index 3019d194..4cb8a2b0 100644 --- a/src/Store/LaravelSession.php +++ b/src/Store/LaravelSession.php @@ -13,24 +13,16 @@ */ final class LaravelSession implements StoreInterface { - /** - * Session base name, configurable on instantiation. - */ - private string $sessionPrefix; - - /** - * Track if a bootup event has been sent out yet. - */ - private bool $booted = false; - /** * Psr14Store constructor. * * @param string $sessionPrefix a string to prefix session keys with */ - public function __construct(string $sessionPrefix = 'auth0') + public function __construct( + private string $prefix = 'auth0', + private bool $booted = false + ) { - $this->sessionPrefix = $sessionPrefix; } /** @@ -82,7 +74,7 @@ public function purge(): void $pairs = $this->getStore()-> all(); - $prefix = $this->sessionPrefix . '_'; + $prefix = $this->prefix . '_'; foreach (array_keys($pairs) as $key) { if (mb_substr($key, 0, mb_strlen($prefix)) === $prefix) { @@ -133,8 +125,8 @@ private function getStore(): \Illuminate\Session\Store private function getPrefixedKey(string $key): string { - if ('' !== $this->sessionPrefix) { - return $this->sessionPrefix . '_' . $key; + if ('' !== $this->prefix) { + return $this->prefix . '_' . $key; } return $key; From ba2ee3f943723a191033463f8c2b264c938fbe45 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 15:13:59 -0500 Subject: [PATCH 155/525] Refactor DI and ServiceProvider for improved Octane compatibility --- src/Cache/LaravelCacheItem.php | 4 ++-- src/Contract/Model/User.php | 2 +- src/Event/Stateful/AuthenticationFailed.php | 3 +-- src/Store/LaravelSession.php | 3 +-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Cache/LaravelCacheItem.php b/src/Cache/LaravelCacheItem.php index 9fc932d7..f13b8770 100644 --- a/src/Cache/LaravelCacheItem.php +++ b/src/Cache/LaravelCacheItem.php @@ -8,12 +8,12 @@ final class LaravelCacheItem implements CacheItemInterface { - public function __construct( private string $key, private mixed $value, private bool $hit, - private ?\DateTimeInterface $expiration = null) + private ?\DateTimeInterface $expiration = null + ) { } diff --git a/src/Contract/Model/User.php b/src/Contract/Model/User.php index e63d5ec0..65cdeb9a 100644 --- a/src/Contract/Model/User.php +++ b/src/Contract/Model/User.php @@ -11,7 +11,7 @@ interface User * * @param array $attributes attributes representing the user data */ - public function __construct(private array $attributes = []); + public function __construct(array $attributes = []); /** * Dynamically retrieve attributes on the model. diff --git a/src/Event/Stateful/AuthenticationFailed.php b/src/Event/Stateful/AuthenticationFailed.php index c9c32582..e8b3f23a 100644 --- a/src/Event/Stateful/AuthenticationFailed.php +++ b/src/Event/Stateful/AuthenticationFailed.php @@ -12,8 +12,7 @@ final class AuthenticationFailed extends \Auth0\Laravel\Event\Auth0Event impleme public function __construct( private \Throwable $exception, private bool $throwException = true - ) - { + ) { } /** diff --git a/src/Store/LaravelSession.php b/src/Store/LaravelSession.php index 4cb8a2b0..497a931c 100644 --- a/src/Store/LaravelSession.php +++ b/src/Store/LaravelSession.php @@ -21,8 +21,7 @@ final class LaravelSession implements StoreInterface public function __construct( private string $prefix = 'auth0', private bool $booted = false - ) - { + ) { } /** From 074c335a87e026d4fea4c00ccd108bd5f17886ca Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 15:21:24 -0500 Subject: [PATCH 156/525] Refactor DI and ServiceProvider for improved Octane compatibility --- src/Store/LaravelSession.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Store/LaravelSession.php b/src/Store/LaravelSession.php index 497a931c..bae39131 100644 --- a/src/Store/LaravelSession.php +++ b/src/Store/LaravelSession.php @@ -13,11 +13,6 @@ */ final class LaravelSession implements StoreInterface { - /** - * Psr14Store constructor. - * - * @param string $sessionPrefix a string to prefix session keys with - */ public function __construct( private string $prefix = 'auth0', private bool $booted = false From 3a6bcffa1ecafe19575db47d4a025bc75702eef3 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 15:25:57 -0500 Subject: [PATCH 157/525] Update LaravelCacheItem.php --- src/Cache/LaravelCacheItem.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Cache/LaravelCacheItem.php b/src/Cache/LaravelCacheItem.php index f13b8770..e6b1a59e 100644 --- a/src/Cache/LaravelCacheItem.php +++ b/src/Cache/LaravelCacheItem.php @@ -13,8 +13,7 @@ public function __construct( private mixed $value, private bool $hit, private ?\DateTimeInterface $expiration = null - ) - { + ) { } /** From b1aa4e0f13d45b59f68fdeaa8208e86cfb9bb673 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 15:30:46 -0500 Subject: [PATCH 158/525] Refactor DI and ServiceProvider for improved Octane compatibility --- src/Cache/LaravelCacheItem.php | 10 +++++----- src/Event/Stateful/AuthenticationFailed.php | 2 +- src/Store/LaravelSession.php | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Cache/LaravelCacheItem.php b/src/Cache/LaravelCacheItem.php index e6b1a59e..5096fd3e 100644 --- a/src/Cache/LaravelCacheItem.php +++ b/src/Cache/LaravelCacheItem.php @@ -12,7 +12,7 @@ public function __construct( private string $key, private mixed $value, private bool $hit, - private ?\DateTimeInterface $expiration = null + private ?\DateTimeInterface $expiration = null, ) { } @@ -65,9 +65,9 @@ public function expiresAt(?\DateTimeInterface $expiration): static public function expiresAfter(int|\DateInterval|null $time): static { $this->expiration = match (true) { - is_null($time) => new \DateTimeImmutable('now +1 year'), - is_int($time) => new \DateTimeImmutable('now +' . $time . ' seconds'), - $time instanceof \DateInterval => (new \DateTimeImmutable())->add($time), /** @phpstan-ignore-line */ + null === $time => new \DateTimeImmutable('now +1 year'), + \is_int($time) => new \DateTimeImmutable('now +' . $time . ' seconds'), + $time instanceof \DateInterval => (new \DateTimeImmutable())->add($time), /* @phpstan-ignore-line */ }; return $this; } @@ -96,7 +96,7 @@ public static function miss(string $key): self return new self( key: $key, value: null, - hit: false + hit: false, ); } } diff --git a/src/Event/Stateful/AuthenticationFailed.php b/src/Event/Stateful/AuthenticationFailed.php index e8b3f23a..87c9064f 100644 --- a/src/Event/Stateful/AuthenticationFailed.php +++ b/src/Event/Stateful/AuthenticationFailed.php @@ -11,7 +11,7 @@ final class AuthenticationFailed extends \Auth0\Laravel\Event\Auth0Event impleme */ public function __construct( private \Throwable $exception, - private bool $throwException = true + private bool $throwException = true, ) { } diff --git a/src/Store/LaravelSession.php b/src/Store/LaravelSession.php index bae39131..793385f6 100644 --- a/src/Store/LaravelSession.php +++ b/src/Store/LaravelSession.php @@ -15,7 +15,7 @@ final class LaravelSession implements StoreInterface { public function __construct( private string $prefix = 'auth0', - private bool $booted = false + private bool $booted = false, ) { } From d209be8a9c489d67718afa4554fae96ef660a971 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 15:32:06 -0500 Subject: [PATCH 159/525] Refactor DI and ServiceProvider for improved Octane compatibility --- src/Cache/LaravelCacheItem.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Cache/LaravelCacheItem.php b/src/Cache/LaravelCacheItem.php index 5096fd3e..dd4158c2 100644 --- a/src/Cache/LaravelCacheItem.php +++ b/src/Cache/LaravelCacheItem.php @@ -38,6 +38,7 @@ public function get(): mixed public function set($value = null): static { $this->value = $value; + return $this; } @@ -69,6 +70,7 @@ public function expiresAfter(int|\DateInterval|null $time): static \is_int($time) => new \DateTimeImmutable('now +' . $time . ' seconds'), $time instanceof \DateInterval => (new \DateTimeImmutable())->add($time), /* @phpstan-ignore-line */ }; + return $this; } From 66be365483184752c046605f293d56901b05a8d2 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 23:16:46 -0500 Subject: [PATCH 160/525] Refactor DI and ServiceProvider for improved Octane compatibility --- src/Auth0.php | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/Auth0.php b/src/Auth0.php index 7ce785b4..298f4bc0 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -79,20 +79,18 @@ public function getConfiguration(): Configuration $configuration = new Configuration($config); - if (! \in_array($configuration->getStrategy(), [Configuration::STRATEGY_API, Configuration::STRATEGY_MANAGEMENT_API], true)) { - // If no sessionStorage is defined, use an LaravelSession store instance. - if (! isset($config['sessionStorage'])) { - $configuration->setSessionStorage( - new LaravelSession($configuration->getSessionStorageId()), - ); - } + // If no sessionStorage is defined, use an LaravelSession store instance. + if (! isset($config['sessionStorage'])) { + $configuration->setSessionStorage( + new LaravelSession($configuration->getSessionStorageId()), + ); + } - // If no transientStorage is defined, use an LaravelSession store instance. - if (! isset($config['transientStorage'])) { - $configuration->setTransientStorage( - new LaravelSession($configuration->getTransientStorageId()), - ); - } + // If no transientStorage is defined, use an LaravelSession store instance. + if (! isset($config['transientStorage'])) { + $configuration->setTransientStorage( + new LaravelSession($configuration->getTransientStorageId()), + ); } // Give apps an opportunity to mutate the configuration before applying it. From 2bdf37cfd98c0f4124650dc2dbbac726590906d2 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 23:36:10 -0500 Subject: [PATCH 161/525] [SDK-3716] Do not require session configuration for stateless strategies (#317) * Do not require session configurations for stateless/API-only strategies * Fix incorrect named argument call --- src/Auth0.php | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/Auth0.php b/src/Auth0.php index 298f4bc0..a41732da 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -79,18 +79,24 @@ public function getConfiguration(): Configuration $configuration = new Configuration($config); - // If no sessionStorage is defined, use an LaravelSession store instance. - if (! isset($config['sessionStorage'])) { - $configuration->setSessionStorage( - new LaravelSession($configuration->getSessionStorageId()), - ); - } + if (! \in_array($configuration->getStrategy(), [Configuration::STRATEGY_API, Configuration::STRATEGY_MANAGEMENT_API], true)) { + // If no sessionStorage is defined, use an LaravelSession store instance. + if (! isset($config['sessionStorage'])) { + $configuration->setSessionStorage( + sessionStorage: new LaravelSession( + prefix: $configuration->getSessionStorageId() + ) + ); + } - // If no transientStorage is defined, use an LaravelSession store instance. - if (! isset($config['transientStorage'])) { - $configuration->setTransientStorage( - new LaravelSession($configuration->getTransientStorageId()), - ); + // If no transientStorage is defined, use an LaravelSession store instance. + if (! isset($config['transientStorage'])) { + $configuration->setTransientStorage( + transientStorage: new LaravelSession( + prefix: $configuration->getTransientStorageId() + ) + ); + } } // Give apps an opportunity to mutate the configuration before applying it. From c279cddf4c253da8c9826c7c09af3a3458a61062 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 23:36:44 -0500 Subject: [PATCH 162/525] [SDK-3715] Pin `psr/cache` dependency version (#316) Update composer.json --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9202cff6..80c74912 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,8 @@ "auth0/auth0-php": "^8.0", "illuminate/contracts": "^8.0 || ^9.0", "illuminate/http": "^8.0 || ^9.0", - "illuminate/support": "^8.0 || ^9.0" + "illuminate/support": "^8.0 || ^9.0", + "psr/cache": "^3.0" }, "require-dev": { "ergebnis/composer-normalize": "dev-main", From 094fcc53c04a647e0bfea3cc6f9f067c83d4450d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 23:42:54 -0500 Subject: [PATCH 163/525] Refactor DI and ServiceProvider for improved Octane compatibility --- src/Auth0.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Auth0.php b/src/Auth0.php index a41732da..34166d3a 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -84,7 +84,7 @@ public function getConfiguration(): Configuration if (! isset($config['sessionStorage'])) { $configuration->setSessionStorage( sessionStorage: new LaravelSession( - prefix: $configuration->getSessionStorageId() + prefix: $configuration->getSessionStorageId(), ) ); } @@ -93,7 +93,7 @@ public function getConfiguration(): Configuration if (! isset($config['transientStorage'])) { $configuration->setTransientStorage( transientStorage: new LaravelSession( - prefix: $configuration->getTransientStorageId() + prefix: $configuration->getTransientStorageId(), ) ); } From e5beee5f0221a7032b1d5e5902a4b4ee43b4b458 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 13 Oct 2022 23:43:26 -0500 Subject: [PATCH 164/525] Refactor DI and ServiceProvider for improved Octane compatibility --- src/Auth0.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Auth0.php b/src/Auth0.php index 34166d3a..505d8555 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -85,7 +85,7 @@ public function getConfiguration(): Configuration $configuration->setSessionStorage( sessionStorage: new LaravelSession( prefix: $configuration->getSessionStorageId(), - ) + ), ); } @@ -94,7 +94,7 @@ public function getConfiguration(): Configuration $configuration->setTransientStorage( transientStorage: new LaravelSession( prefix: $configuration->getTransientStorageId(), - ) + ), ); } } From 09b32ad4165ee72f7b8354e8ed7eca20c3017ecc Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 14 Oct 2022 12:06:15 -0500 Subject: [PATCH 165/525] Release 7.2.1 (#318) --- CHANGELOG.md | 7 +++++++ src/Auth0.php | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 085a6fa9..6ee261f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## [7.2.1](https://github.com/auth0/laravel-auth0/tree/7.2.1) (2022-10-13) +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.2.0...7.2.1) + +**Fixed** +- `Auth0\Laravel\Auth0` no longer requires a session configuration for stateless strategies, restoring previous behavior. [\#317](https://github.com/auth0/laravel-auth0/pull/317) ([evansims](https://github.com/evansims)) +- The SDK now requires `^3.0` of the `psr/cache` dependency, to accomodate breaking changes made in the upstream interface (typed parameters and return types) for PHP 8.0+. [\#316](https://github.com/auth0/laravel-auth0/pull/316) ([evansims](https://github.com/evansims)) + ## [7.2.0](https://github.com/auth0/laravel-auth0/tree/7.2.0) (2022-10-10) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.1.0...7.2.0) diff --git a/src/Auth0.php b/src/Auth0.php index 505d8555..34f841ef 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -17,7 +17,7 @@ final class Auth0 implements \Auth0\Laravel\Contract\Auth0 /** * The Laravel-Auth0 SDK version:. */ - public const VERSION = '7.2.0'; + public const VERSION = '7.2.1'; /** * An instance of the Auth0-PHP SDK. From b45aaa84b2b1e951ffa9e4928d90c81da2bb7dc1 Mon Sep 17 00:00:00 2001 From: "sre-57-opslevel[bot]" <113727212+sre-57-opslevel[bot]@users.noreply.github.com> Date: Mon, 17 Oct 2022 13:12:50 +0000 Subject: [PATCH 166/525] Upload OpsLevel YAML --- opslevel.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 opslevel.yml diff --git a/opslevel.yml b/opslevel.yml new file mode 100644 index 00000000..009a5ec0 --- /dev/null +++ b/opslevel.yml @@ -0,0 +1,6 @@ +--- +version: 1 +repository: + owner: dx_sdks + tier: + tags: From e3b54179bc858f9c89b00b309afc553b8f8ed60a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 17 Oct 2022 16:51:36 -0500 Subject: [PATCH 167/525] Update Bug Report.yml --- .github/ISSUE_TEMPLATE/Bug Report.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index d8317f1c..32252601 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -11,6 +11,8 @@ body: label: SDK Version description: What version of our Laravel plugin are you running? (`composer show | grep auth0/login`) options: + - 7.2 + - 7.1 - 7.0 - 6.5 - 6.4 From add088c8535f308d6c774336dcc9b947461a510a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 19 Oct 2022 10:41:35 -0500 Subject: [PATCH 168/525] [SDK-3721] Bump minimum `auth0/auth0-php` version to `^8.3.2` (#322) [SDK-3721] Pin `auth0/auth0-php` to `^8.3.2` --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 80c74912..d5090feb 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "php": "^8.0", "ext-json": "*", "ext-mbstring": "*", - "auth0/auth0-php": "^8.0", + "auth0/auth0-php": "^8.3.2", "illuminate/contracts": "^8.0 || ^9.0", "illuminate/http": "^8.0 || ^9.0", "illuminate/support": "^8.0 || ^9.0", From 36e8c001c99c6c261687b893c6c1252b5436eb5a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 19 Oct 2022 20:27:34 -0500 Subject: [PATCH 169/525] [SDK-3720] Restore `php artisan vendor:publish` command (#321) [SDK-3720] Fix `php artisan vendor:publish` command --- src/ServiceProvider.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 5d28f801..ca9e8315 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -50,6 +50,8 @@ public function register(): self public function boot(\Illuminate\Routing\Router $router, \Illuminate\Auth\AuthManager $auth): self { + $this->publishes([implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'config', 'auth0.php']) => config_path('auth0.php')], 'auth0-config'); + $auth->extend('auth0', static fn (): Guard => new Guard()); $auth->provider('auth0', static fn (): Provider => new Provider()); From 71a02e0416fc4d4122e6755a3a19971724687375 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 19 Oct 2022 20:28:30 -0500 Subject: [PATCH 170/525] fix: Bump auth0/auth0-php dependency to ^8.3.3 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d5090feb..8753f361 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "php": "^8.0", "ext-json": "*", "ext-mbstring": "*", - "auth0/auth0-php": "^8.3.2", + "auth0/auth0-php": "^8.3.3", "illuminate/contracts": "^8.0 || ^9.0", "illuminate/http": "^8.0 || ^9.0", "illuminate/support": "^8.0 || ^9.0", From 71d518b5be977397565e50125122b3ecada66ee4 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 19 Oct 2022 20:29:02 -0500 Subject: [PATCH 171/525] fix: `cookiePath` configuration should default to `/` --- config/auth0.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/auth0.php b/config/auth0.php index 23ad6f4a..546f8077 100644 --- a/config/auth0.php +++ b/config/auth0.php @@ -46,7 +46,7 @@ 'cookieDomain' => env('AUTH0_COOKIE_DOMAIN'), // Specifies path on the domain where the cookies will work. Defaults to '/'. Use a single slash ('/') for all paths on the domain. - 'cookiePath' => env('AUTH0_COOKIE_PATH'), + 'cookiePath' => env('AUTH0_COOKIE_PATH', '/'), // Defaults to false. Specifies whether cookies should ONLY be sent over secure connections. 'cookieSecure' => \Auth0\Laravel\Configuration::stringToBoolOrNull(env('AUTH0_COOKIE_SECURE'), false), From 0f19c8b7f533f2381261235ba2dce65901f72a19 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 19 Oct 2022 23:03:28 -0500 Subject: [PATCH 172/525] fix: Bump auth0/auth0-php dependency to ^8.3.4 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8753f361..4382a241 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "php": "^8.0", "ext-json": "*", "ext-mbstring": "*", - "auth0/auth0-php": "^8.3.3", + "auth0/auth0-php": "^8.3.4", "illuminate/contracts": "^8.0 || ^9.0", "illuminate/http": "^8.0 || ^9.0", "illuminate/support": "^8.0 || ^9.0", From e132b28b9fb623339ba1f236f6430effa29f2c89 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 19 Oct 2022 23:04:02 -0500 Subject: [PATCH 173/525] fix: `scopes` should never be configured as `null` --- config/auth0.php | 4 ++-- src/Configuration.php | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/config/auth0.php b/config/auth0.php index 546f8077..9625822e 100644 --- a/config/auth0.php +++ b/config/auth0.php @@ -9,7 +9,7 @@ return [ // Should be assigned either 'api', 'management', or 'webapp' to indicate your application's use case for the SDK. // Determines what configuration options will be required. - 'strategy' => env('AUTH0_STRATEGY', 'webapp'), + 'strategy' => env('AUTH0_STRATEGY', \Auth0\SDK\Configuration\SdkConfiguration::STRATEGY_REGULAR), // Auth0 domain for your tenant, found in your Auth0 Application settings. 'domain' => env('AUTH0_DOMAIN'), @@ -30,7 +30,7 @@ 'audience' => \Auth0\Laravel\Configuration::stringToArrayOrNull(env('AUTH0_AUDIENCE')), // One or more scopes to request for Tokens. See https://auth0.com/docs/scopes - 'scope' => \Auth0\Laravel\Configuration::stringToArrayOrNull(env('AUTH0_SCOPE')), + 'scope' => \Auth0\Laravel\Configuration::stringToArray(env('AUTH0_SCOPE')), // One or more Organization IDs, found in your Auth0 Organization settings. The SDK uses the first value for building links. If provided, at least one of these values must match the 'org_id' claim to validate an ID Token successfully. 'organization' => \Auth0\Laravel\Configuration::stringToArrayOrNull(env('AUTH0_ORGANIZATION')), diff --git a/src/Configuration.php b/src/Configuration.php index 99da8956..ffb32b96 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -26,6 +26,23 @@ public static function stringToArrayOrNull(?string $config, string $delimiter = return null; } + /** + * {@inheritdoc} + */ + public static function stringToArray(?string $config, string $delimiter = ' '): array + { + if (\is_string($config) && '' !== $config && '' !== $delimiter) { + $response = explode($delimiter, $config); + + // @phpstan-ignore-next-line + if (\count($response) >= 1 && '' !== trim($response[0])) { + return $response; + } + } + + return []; + } + /** * {@inheritdoc} */ From ea45bfeeaf303efc6ada271d25c6e6c2d8cfc190 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 19 Oct 2022 23:04:16 -0500 Subject: [PATCH 174/525] change: Improvements to logout flow --- src/Auth/Guard.php | 6 ++++-- src/Http/Controller/Stateful/Logout.php | 7 ++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index cc3fd27e..0983afc3 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -11,6 +11,7 @@ use Auth0\SDK\Configuration\SdkConfiguration; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\UserProvider; +use Illuminate\Support\Facades\Session; use RuntimeException; final class Guard implements \Auth0\Laravel\Contract\Auth\Guard, \Illuminate\Contracts\Auth\Guard @@ -31,8 +32,9 @@ public function login(Authenticatable $user): self */ public function logout(): self { - $this->getState()-> - setUser(null); + app()->instance(StateInstance::class, null); + Session::flush(); + app(Auth0::class)->getSdk()->clear(); return $this; diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index 2098e627..0b1eccf2 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -24,12 +24,9 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re * @var Guard $guard */ if ($guard->check()) { - $guard->logout(); + $request->session()->invalidate(); - $request->session()-> - invalidate(); - $request->session()-> - regenerateToken(); + $guard->logout(); return redirect()->away( app(\Auth0\Laravel\Auth0::class)->getSdk()->authentication()->getLogoutLink(url(http://github.com/config('auth0.routes.home',%20'/'))), // @phpstan-ignore-line From d5ddb10565d19b3f8d5bc473396f1a67a6287a3b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 19 Oct 2022 23:08:35 -0500 Subject: [PATCH 175/525] Release 7.2.2 (#324) --- CHANGELOG.md | 7 +++++++ src/Auth0.php | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ee261f0..5a583966 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## [7.2.2](https://github.com/auth0/laravel-auth0/tree/7.2.2) (2022-10-19) +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.2.1...7.2.2) + +**Fixed** +- [SDK-3720] Restore `php artisan vendor:publish` command [\#321](https://github.com/auth0/laravel-auth0/pull/321) ([evansims](https://github.com/evansims)) +- [SDK-3721] Bump minimum `auth0/auth0-php` version to `^8.3.4` [\#322](https://github.com/auth0/laravel-auth0/pull/322) ([evansims](https://github.com/evansims)) + ## [7.2.1](https://github.com/auth0/laravel-auth0/tree/7.2.1) (2022-10-13) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.2.0...7.2.1) diff --git a/src/Auth0.php b/src/Auth0.php index 34f841ef..177b702f 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -17,7 +17,7 @@ final class Auth0 implements \Auth0\Laravel\Contract\Auth0 /** * The Laravel-Auth0 SDK version:. */ - public const VERSION = '7.2.1'; + public const VERSION = '7.2.2'; /** * An instance of the Auth0-PHP SDK. From ccb41b698361a8d90655fc321031d54daac382f0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 27 Oct 2022 10:12:17 -0500 Subject: [PATCH 176/525] [SDK-3700] Redesign README (#327) Co-authored-by: Ewan Harris --- EXAMPLES.md | 144 +++++++++++++++++++ README.md | 387 ++++++++++++++-------------------------------------- 2 files changed, 248 insertions(+), 283 deletions(-) create mode 100644 EXAMPLES.md diff --git a/EXAMPLES.md b/EXAMPLES.md new file mode 100644 index 00000000..0ffbc2f3 --- /dev/null +++ b/EXAMPLES.md @@ -0,0 +1,144 @@ +# Examples using laravel-auth0 + +- [Custom user models and repositories](#custom-user-models-and-repositories) +- [Authorizing HTTP tests](#authorizing-http-tests) + +## Custom user models and repositories + +In Laravel, a User Repository is an interface that sits between your authentication source (Auth0) and core Laravel authentication services. It allows you to shape and manipulate the user model and it's data as you need to. + +For example, Auth0's unique identifier is a `string` in the format `auth0|123456abcdef`. If you were to attempt to persist a user to many traditional databases you'd likely encounter an error as, by default, a unique identifier is often exected to be an `integer` rather than a `string` type. A custom user model and repository is a great way to address integration challenges like this. + +### Creating a custom user model + +Let's setup a custom user model for our application. To do this, let's create a file at `app/Auth/Models/User.php` within our Laravel project. This new class needs to implement the `Illuminate\Contracts\Auth\Authenticatable` interface to be compatible with Laravel's Guard API and this SDK. It must also implement either `Auth0\Laravel\Contract\Model\Stateful\User` or `Auth0\Laravel\Contract\Model\Stateless\User` depending on your application's needs. For example: + +```php + + */ + protected $fillable = [ + 'id', + 'name', + 'email', + ]; + + /** + * The attributes that should be hidden for serialization. + * + * @var array + */ + protected $hidden = []; + + /** + * The attributes that should be cast. + * + * @var array + */ + protected $casts = []; +} +``` + +### Creating a Custom User Repository + +Now let's create a custom user repository for your application which will return the new new custom model. To do this, create the file `app/Auth/CustomUserRepository.php`. This new class must implment the `Auth0\Laravel\Contract\Auth\User\Repository` interface. This new repository takes in user data returned from Auth0's API, applies it to the `App\Models\User` custom user model created in the previous step, and returns it for use throughout your application. + +```php + 'just_a_random_example|' . $user['sub'] ?? $user['user_id'] ?? null, + 'name' => $user['name'], + 'email' => $user['email'] + ]); + } + + public function fromAccessToken( + array $user + ): ?\Illuminate\Contracts\Auth\Authenticatable { + // Simliar to above. Used for stateless application types. + return null; + } +} +``` + +### Using a Custom User Repository + +Finally, update your application's `config/auth.php` file. Within the Auth0 provider, assign a custom `repository` value pointing to your new custom user provider class. For example: + +```php + 'providers' => [ + //... + + 'auth0' => [ + 'driver' => 'auth0', + 'repository' => App\Auth\CustomUserRepository::class + ], + ], +``` + +## Authorizing HTTP tests + +If your application does contain HTTP tests which access routes that are protected by the `auth0.authorize` middleware, you can use the trait `Auth0\Laravel\Traits\ActingAsAuth0User` in your tests, which will give you a helper method `actingAsAuth0User(array $attributes=[])` simmilar to Laravels `actingAs` method, that allows you to fake beeing authenticated as a Auth0 user. + +The argument `attributes` is optional and you can use it to set any auth0 specific user attributes like scope, sub, azp, iap and so on. If no attributes are set, some default values are used. + +### Example with a scope protected route + +Let's assume you have a route like the following, that is protected by the scope `read:messages`: +```php +Route::get('/api/private-scoped', function () { + return response()->json([ + 'message' => 'Hello from a private endpoint!', + 'authorized' => Auth::check(), + 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, + ], 200, [], JSON_PRETTY_PRINT); +})->middleware(['auth0.authorize:read:messages']); +``` + +To be able to test the route from above, the implementation of your test would have to look like this: +```php +use Auth0\Laravel\Traits\ActingAsAuth0User; + +public function test_readMessages(){ + $response = $this->actingAsAuth0User([ + "scope"=>"read:messages" + ])->getJson("/api/private-scoped"); + + $response->assertStatus(200); +} +``` diff --git a/README.md b/README.md index 933764c5..efbea3b1 100644 --- a/README.md +++ b/README.md @@ -1,137 +1,96 @@ -# Auth0 Laravel SDK - -[![Latest Stable Version](https://img.shields.io/packagist/v/auth0/login?label=stable)](https://packagist.org/packages/auth0/laravel-auth0) -[![Latest Version](https://img.shields.io/packagist/v/auth0/login?include_prereleases&label=latest)](https://packagist.org/packages/auth0/laravel-auth0) -[![Supported PHP Versions](https://img.shields.io/packagist/php-v/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) -[![License](https://img.shields.io/packagist/l/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) - -This SDK helps you integrate your [Laravel](https://laravel.com/) application with [Auth0](https://auth0.com/) to achieve single sign-on with a few simple steps. The SDK also provides an easy method of integration all the functionality of the underlying [Auth0-PHP](https://github.com/auth0/auth0-PHP) inside your Laravel application, including all types of authentication, authorization of API endpoints, and issuing Management API calls. - -- [Requirements](#requirements) -- [Usage](#usage) - - [Getting Started](#getting-started) - - [Installation](#installation) - - [Configuration the SDK](#configuration-the-sdk) - - [Regular Web Applications](#regular-web-applications) - - [Backend API Applications](#backend-api-applications) - - [Additional Options](#additional-options) - - [Configure your Application](#configure-your-application) - - [Authentication Routes](#authentication-routes) - - [Protecting Routes with Middleware](#protecting-routes-with-middleware) - - [Regular Web Applications](#regular-web-applications-1) - - [Backend API Applications](#backend-api-applications-1) - - [Custom User Models and Repositories](#custom-user-models-and-repositories) - - [Creating a Custom User Model](#creating-a-custom-user-model) - - [Creating a Custom User Repository](#creating-a-custom-user-repository) - - [Using a Custom User Repository](#using-a-custom-user-repository) - - [Authorizing HTTP Tests](#authorizing-http-tests) - - [Octane](#octane) -- [Documentation](#documentation) -- [Contributing](#contributing) -- [Support + Feedback](#support--feedback) -- [Vulnerability Reporting](#vulnerability-reporting) -- [What is Auth0?](#what-is-auth0) -- [License](#license) - -## Requirements +![laravel-auth0](https://cdn.auth0.com/website/sdks/banners/auth0-php-banner.png) -| SDK Version | Laravel Version¹ | PHP Version² | Support Ends³ | -|-------------|------------------|--------------|---------------| -| 7 | 9 | 8.1 | Feb 2024 | -| | | 8.0 | Nov 2023 | -| | 8 | 8.1 | Jan 2023 | -| | | 8.0 | Jan 2023 | -| 6⁴ | 8 | 8.1 | Jan 2023 | -| | | 8.0 | Jan 2023 | +Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. -¹ This library follows the [Laravel release support schedule](https://laravel.com/docs/releases#support-policy). We do not support framework versions after they stop receiving security fixes from Laravel. +[![Package](https://img.shields.io/packagist/dt/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) +[![Build](https://img.shields.io/github/workflow/status/auth0/laravel-auth0/Checks)](https://github.com/auth0/laravel-auth0/actions/workflows/checks.yml?query=branch%3Amain) +[![License](https://img.shields.io/packagist/l/auth0/login)](https://doge.mit-license.org/) -² This library follows the [PHP release support schedule](https://www.php.net/supported-versions.php). We do not support runtime versions after they stop receiving security fixes from the PHP Group. +:books: [Documentation](#documentation) - :rocket: [Getting Started](#getting-started) - :speech_balloon: [Feedback](#feedback) + +## Documentation -³ Our support windows are determined by the Laravel and PHP Group support schedules, and support ends when either the Laravel framework or PHP runtime outlined above stop receiving security fixes, whichever comes first. +- Stateful Applications + - [Quickstart](https://auth0.com/docs/quickstart/webapp/laravel) — add login, logout and user information to a Laravel application using Auth0. + - [Sample Application](https://github.com/auth0-samples/auth0-laravel-php-web-app) — a sample Laravel web application integrated with Auth0. +- Stateless Applications + - [Quickstart](https://auth0.com/docs/quickstart/backend/php) — add access token handling and route authorization to a backend Laravel application using Auth0. + - [Sample Application](https://github.com/auth0-samples/auth0-laravel-api-samples) — a sample Laravel backend application integrated with Auth0. +- [Examples](./EXAMPLES.md) — code samples for common scenarios. +- [Docs site](https://www.auth0.com/docs) — explore our docs site and learn more about Auth0. -⁴ With the release of Laravel SDK v7, v6 is now in bug-fix only mode. Please migrate to v7 to continue to receive feature enhancements. +## Getting Started -## Usage +### Requirements -### Getting Started +- PHP 8.0+ +- Laravel 8 / Laravel 9 -- Create a [free Auth0 account](https://auth0.com/signup) and register an [Application](https://auth0.com/docs/applications). -- If you do not already have one, [prepare a Laravel project](https://laravel.com/docs/master/installation). +> Please review our [support policy](#support-policy) to learn when language and framework versions will exit support in the future. + +> [Octane support](#octane-support) is experimental and not advisable for use in production at this time. ### Installation -The supported method of SDK installation is through [Composer](https://getcomposer.org/). From your terminal shell, `cd` into your project directory and issue the following command: +Add the dependency to your application with [Composer](https://getcomposer.org/): -```bash +``` composer require auth0/login ``` -### Configuration the SDK - -Use the Laravel `vendor:publish` command to import the configuration file into your application: - -```sh -php artisan vendor:publish --tag=auth0-config -``` +### Configure Auth0 -Now edit your `.env` file and add Auth0 tenants details for your project, depending on the type of application you're building: +Create a **Regular Web Application** in the [Auth0 Dashboard](https://manage.auth0.com/#/applications). Verify that the "Token Endpoint Authentication Method" is set to `POST`. -#### Regular Web Applications +Next, configure the callback and logout URLs for your application under the "Application URIs" section of the "Settings" page: -```sh -# The URL of your Auth0 tenant domain -# You'll find this in your Auth0 Application's settings page. -AUTH0_DOMAIN=... +- **Allowed Callback URLs**: The URL of your application where Auth0 will redirect to during authentication, e.g., `http://localhost:3000/callback`. +- **Allowed Logout URLs**: The URL of your application where Auth0 will redirect to after user logout, e.g., `http://localhost:3000/login`. -# Your Auth0 application's Client ID -# You'll find this in your Auth0 Application's settings page. -AUTH0_CLIENT_ID=... +Note the **Domain**, **Client ID**, and **Client Secret**. These values will be used during configuration later. -# Your Auth0 application's Client ID -# You'll find this in your Auth0 Application's settings page. -AUTH0_CLIENT_SECRET=... +### Publish SDK configuration -# Your Auth0 Custom API identifier/audience. -# You'll find this in your Custom API's settings page. -AUTH0_AUDIENCE=... +Use Laravel's CLI to generate an Auth0 configuration file within your project: -# Authentication callback URI, as defined in your Auth0 Application settings. -# (Update this as appropriate for your application's location.) -# (You must configure this in your Auth0 Application's settings page as well!) -AUTH0_REDIRECT_URI=http://localhost:3000/auth0/callback +``` +php artisan vendor:publish --tag auto0-config ``` -#### Backend API Applications - -These are applications that accept an Access Token through the 'Authorization' header of a request. +A new file will appear within your project, `app/config/auth0.php`. You should avoid making changes to this file directly. -```sh -# This tells the Auth0 Laravel SDK about your use case to customize its behavior. -# The 'api' strategy is used for backend API applications like we're building here. -# See: https://github.com/auth0/auth0-PHP/blob/main/README.md#configuration-strategies -AUTH0_STRATEGY=api +### Configure your `.env` file -# The URL of your Auth0 tenant domain -# You'll find this in your Auth0 Application's settings page. -AUTH0_DOMAIN=... +Open the `.env` file within your application's directory, and add the following lines appropriate for your application type: -# Your Auth0 application's Client ID -# You'll find this in your Auth0 Application's settings page. -AUTH0_CLIENT_ID=... +
+ For Stateful Web Applications -# Your Auth0 Custom API identifier/audience. -# You'll find this in your Custom API's settings page. -AUTH0_AUDIENCE=... ``` +AUTH0_DOMAIN="Your Auth0 domain" +AUTH0_CLIENT_ID="Your Auth0 application client ID" +AUTH0_CLIENT_SECRET="Your Auth0 application client secret" +AUTH0_COOKIE_SECRET="A randomly generated string" +``` + +Provide a sufficiently long, random string for your `AUTH0_COOKIE_SECRET` using `openssl rand -hex 32`. +
-#### Additional Options +
+ For Stateless Backend Applications -The default configuration provided by the Auth0 Laravel SDK is intentionally limited and designed to support only the most common types of applications. More complex applications may require more robust configuration customizations available in the underlying Auth0-PHP SDK. You can add support for more configuration options by modifying your `config/auth0.php` and `.env` files. A complete list of configuration options are available [from the Auth0-PHP SDK README](https://github.com/auth0/auth0-PHP/blob/main/README.md#configuration-options). +``` +AUTH0_STRATEGY="api" +AUTH0_DOMAIN="Your Auth0 domain" +AUTH0_CLIENT_ID="Your Auth0 application client ID" +AUTH0_CLIENT_SECRET="Your Auth0 application client secret" +AUTH0_AUDIENCE="Your Auth0 API identifier" +``` +
-### Configure your Application +### Setup your Laravel application -Integrating the SDK's Guard requires some small changes to your `config\auth.php` file. +Integrating the SDK's Guard requires changes to your `config\auth.php` file. To begin, find the `defaults` section. Set the default `guard` to `auth0`, like this: @@ -167,9 +126,9 @@ Finally, find the `providers` section, and add `auth0` there as well: ], ``` -### Authentication Routes +## Add login to stateful web applications -The SDK offers a number of convenience route controllers to ease supporting authentication in regular web application (that is, an application that handles end users logging in and out). +For regular web applications that provide login and logout, we provide prebuilt route controllers to add to your `app/routes/web.php` file that will automatically handle your application's authentication flow with Auth0 for you: ```php Route::get('/login', \Auth0\Laravel\Http\Controller\Stateful\Login::class)->name('login'); @@ -177,13 +136,12 @@ Route::get('/logout', \Auth0\Laravel\Http\Controller\Stateful\Logout::class)->na Route::get('/auth0/callback', \Auth0\Laravel\Http\Controller\Stateful\Callback::class)->name('auth0.callback'); ``` -These routes will automatically handle your regular web application's authentication flow for you. - -### Protecting Routes with Middleware +## Protect routes with middleware -The Auth0 Laravel SDK includes a number of middleware that simplify either authenticating (regular web applications) or authorizing (backend api applications) your Laravel routes, depending on the type of application you're building. +This SDK includes middleware to simplify either authenticating (regular web applications) or authorizing (backend api applications) your Laravel routes, depending on your application type. -#### Regular Web Applications +
+Stateful Web Applications These are for traditional applications that handle logging in and out. @@ -207,11 +165,13 @@ Route::get('/', function () { })->middleware(['auth0.authenticate.optional']); ``` -Note that the `example.user.template` and `example.guest.templates` views are just examples and are not part of the SDK; replace these as appropriate for your app. +> Note that the `example.user.template` and `example.guest.templates` views are just examples and are not part of the SDK; replace these as appropriate for your application. +
-#### Backend API Applications +
+Stateless Backend Applications -These are applications that accept an Access Token through the 'Authorization' header of a request. +These are applications that accept an a Access Token through the 'Authorization' header of a request. The `auth0.authorize` middleware will resolve a Access Token and reject any request with an invalid token. @@ -248,195 +208,56 @@ Route::get('/api/public', function () { ], 200, [], JSON_PRETTY_PRINT); })->middleware(['auth0.authorize.optional']); ``` +
-### Custom User Models and Repositories - -In Laravel, a User Repository is an interface that sits between your authentication source (Auth0) and core Laravel authentication services. It allows you to shape and manipulate the user model and it's data as you need to. - -For example, Auth0's unique identifier is a `string` in the format `auth0|123456abcdef`. If you were to attempt to persist a user to many traditional databases you'd likely encounter an error as, by default, a unique identifier is often exected to be an `integer` rather than a `string` type. A custom user model and repository is a great way to address integration challenges like this. - -#### Creating a Custom User Model - -Let's setup a custom user model for our application. To do this, let's create a file at `app/Auth/Models/User.php` within our Laravel project. This new class needs to implement the `Illuminate\Contracts\Auth\Authenticatable` interface to be compatible with Laravel's Guard API and this SDK. It must also implement either `Auth0\Laravel\Contract\Model\Stateful\User` or `Auth0\Laravel\Contract\Model\Stateless\User` depending on your application's needs. For example: - -```php - - */ - protected $fillable = [ - 'id', - 'name', - 'email', - ]; - - /** - * The attributes that should be hidden for serialization. - * - * @var array - */ - protected $hidden = []; - - /** - * The attributes that should be cast. - * - * @var array - */ - protected $casts = []; -} -``` - -#### Creating a Custom User Repository - -Now let's create a custom user repository for your application which will return the new new custom model. To do this, create the file `app/Auth/CustomUserRepository.php`. This new class must implment the `Auth0\Laravel\Contract\Auth\User\Repository` interface. This new repository takes in user data returned from Auth0's API, applies it to the `App\Models\User` custom user model created in the previous step, and returns it for use throughout your application. - -```php - 'just_a_random_example|' . $user['sub'] ?? $user['user_id'] ?? null, - 'name' => $user['name'], - 'email' => $user['email'] - ]); - } - - public function fromAccessToken( - array $user - ): ?\Illuminate\Contracts\Auth\Authenticatable { - // Simliar to above. Used for stateless application types. - return null; - } -} -``` - -#### Using a Custom User Repository +## Support Policy -Finally, update your application's `config/auth.php` file. Within the Auth0 provider, assign a custom `repository` value pointing to your new custom user provider class. For example: +Our support windows are determined by the [Laravel release support](https://laravel.com/docs/releases#support-policy) and [PHP release support](https://www.php.net/supported-versions.php) schedules, and support ends when either the Laravel framework or PHP runtime outlined below stop receiving security fixes, whichever may come first. -```php - 'providers' => [ - //... - - 'auth0' => [ - 'driver' => 'auth0', - 'repository' => App\Auth\CustomUserRepository::class - ], - ], -``` - -### Authorizing HTTP Tests - -If your application does contain HTTP tests which access routes that are protected by the `auth0.authorize` middleware, you can use the trait `Auth0\Laravel\Traits\ActingAsAuth0User` in your tests, which will give you a helper method `actingAsAuth0User(array $attributes=[])` simmilar to Laravels `actingAs` method, that allows you to fake beeing authenticated as a Auth0 user. - -The argument `attributes` is optional and you can use it to set any auth0 specific user attributes like scope, sub, azp, iap and so on. If no attributes are set, some default values are used. - -#### Example with a scope protected route -Let's assume you have a route like the following, that is protected by the scope `read:messages`: -```php -Route::get('/api/private-scoped', function () { - return response()->json([ - 'message' => 'Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.', - 'authorized' => Auth::check(), - 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, - ], 200, [], JSON_PRETTY_PRINT); -})->middleware(['auth0.authorize:read:messages']); -``` - -To be able to test the route from above, the implementation of your test would have to look like this: -```php -use Auth0\Laravel\Traits\ActingAsAuth0User; - -public function test_readMessages(){ - $response = $this->actingAsAuth0User([ - "scope"=>"read:messages" - ])->getJson("/api/private-scoped"); +| SDK Version | Laravel Version¹ | PHP Version² | Support Ends³ | +|-------------|------------------|--------------|---------------| +| 7 | 9 | 8.1 | Feb 2024 | +| | | 8.0 | Nov 2023 | +| | 8 | 8.1 | Jan 2023 | +| | | 8.0 | Jan 2023 | +| 6⁴ | 8 | 8.1 | Jan 2023 | +| | | 8.0 | Jan 2023 | - $response->assertStatus(200); -} -``` +Deprecations of EOL'd language or framework versions are not considered a breaking change, as Composer handles these scenarios elegantly. Legacy applications will stop receiving updates from us, but will continue to function on those unsupported SDK versions. -### Octane +## Octane Support Octane compatibility is currently considered experimental and unsupported. -Although we are working toward ensuring the SDK is fully compatible with this performance-enhancing technique backed by Open Swoole and RoadRunner, we do not recommend using this feature with our SDK in production until we have full confidence and greenlit support. Due to the aggressive changes Octane makes to Laravel's behavior, there is opportunity for problems we haven't fully identified or resolved yet. +Although we are working toward ensuring the SDK is fully compatible with this feature, we do not recommend using this with our SDK in production until we have full confidence and announced support. Due to the aggressive changes Octane makes to Laravel's core behavior, there is opportunity for problems we haven't fully identified or resolved yet. -Feedback and bug fix contributions are greatly appreciated as we work on Octane support. +Feedback and bug fix contributions are greatly appreciated as we work toward full. Octane support. -## Documentation - -We provide a number of sample apps that demonstrate common use cases, to help you get started using this SDK: - -- [Web Application Authentication](https://auth0.com/docs/quickstart/webapp/laravel/) ([GitHub repo](https://github.com/auth0-samples/auth0-laravel-php-web-app)) -- [Backend API Authorization](https://auth0.com/docs/quickstart/backend/laravel/) ([GitHub repo](https://github.com/auth0-samples/auth0-laravel-api-samples)) +## Feedback -## Contributing +### Contributing We appreciate feedback and contribution to this repo! Before you get started, please see the following: -- [Auth0's Contribution guidelines](https://github.com/auth0/.github/blob/master/CONTRIBUTING.md) -- [Auth0's Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) - -## Support + Feedback - -- The [Auth0 Community](https://community.auth0.com/) is a valuable resource for asking questions and finding answers, staffed by the Auth0 team and a community of enthusiastic developers -- For code-level support (such as feature requests and bug reports), we encourage you to [open issues](https://github.com/auth0/laravel-auth0/issues) here on our repo -- For customers on [paid plans](https://auth0.com/pricing/), our [support center](https://support.auth0.com/) is available for opening tickets with our knowledgeable support specialists - -Further details about our support solutions are [available on our website.](https://auth0.com/docs/support) - -## Vulnerability Reporting - -Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. - -## What is Auth0? +- [Auth0's general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) +- [Auth0's code of conduct guidelines](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) -Auth0 helps you to: +### Raise an issue +To provide feedback or report a bug, [please raise an issue on our issue tracker](https://github.com/auth0/laravel-auth0/issues). -- Add authentication with [multiple authentication sources](https://docs.auth0.com/identityproviders), either social like Google, Facebook, Microsoft, LinkedIn, GitHub, Twitter, Box, Salesforce (amongst others), or enterprise identity systems like Windows Azure AD, Google Apps, Active Directory, ADFS or any SAML Identity Provider. -- Add authentication through more traditional **[username/password databases](https://docs.auth0.com/mysql-connection-tutorial)**. -- Add support for [passwordless](https://auth0.com/passwordless) and [multi-factor authentication](https://auth0.com/docs/mfa). -- Add support for [linking different user accounts](https://docs.auth0.com/link-accounts) with the same user. -- Analytics of how, when, and where users are logging in. -- Pull data from other sources and add it to the user profile through [JavaScript rules](https://docs.auth0.com/rules). +### Vulnerability Reporting +Please do not report security vulnerabilities on the public Github issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. -[Why Auth0?](https://auth0.com/why-auth0) +--- -## License +

+ + + + Auth0 Logo + +

-The Auth0 Laravel SDK is open source software licensed under [the MIT license](https://opensource.org/licenses/MIT). See the [LICENSE](LICENSE.txt) file for more info. +

Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout Why Auth0?

-[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fauth0%2Flaravel-auth0?ref=badge_large) +

This project is licensed under the MIT license. See the LICENSE file for more info.

From 7af0beecaf2009b3fba3bc5b4ba93321144d5019 Mon Sep 17 00:00:00 2001 From: Patrick Kivits <64962739+pkivits-litebit@users.noreply.github.com> Date: Thu, 3 Nov 2022 22:33:54 +0100 Subject: [PATCH 177/525] fix: Auth0\Laravel\Cache\LaravelCachePool::createItem returning a cache miss (#329) Even when there is a value in the cache, it was still returning a miss, which made the caching practically unusable... --- src/Cache/LaravelCachePool.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cache/LaravelCachePool.php b/src/Cache/LaravelCachePool.php index 335fcbca..ce56e513 100644 --- a/src/Cache/LaravelCachePool.php +++ b/src/Cache/LaravelCachePool.php @@ -154,7 +154,7 @@ private function createItem(string $key, mixed $value): CacheItemInterface $value = unserialize($value); - if (false === $value || 'b:0;' !== $value) { + if (false === $value) { return LaravelCacheItem::miss($key); } From 30a724e64cbce0c9ac107a308664fdd3c78f23b6 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 7 Nov 2022 15:29:44 -0600 Subject: [PATCH 178/525] add: Raise additional Laravel Auth Events (#331) --- src/Auth/Guard.php | 16 +++++++-- .../Stateless/TokenVerificationAttempting.php | 27 ++++++++++++++ .../Stateless/TokenVerificationFailed.php | 31 ++++++++++++++++ .../Stateless/TokenVerificationSucceeded.php | 29 +++++++++++++++ .../Stateful/AuthenticationSucceeded.php | 1 - .../Stateless/TokenVerificationAttempting.php | 35 +++++++++++++++++++ .../Stateless/TokenVerificationFailed.php | 35 +++++++++++++++++++ .../Stateless/TokenVerificationSucceeded.php | 33 +++++++++++++++++ src/Http/Controller/Stateful/Callback.php | 25 ++++++++++++- 9 files changed, 228 insertions(+), 4 deletions(-) create mode 100644 src/Contract/Event/Stateless/TokenVerificationAttempting.php create mode 100644 src/Contract/Event/Stateless/TokenVerificationFailed.php create mode 100644 src/Contract/Event/Stateless/TokenVerificationSucceeded.php create mode 100644 src/Event/Stateless/TokenVerificationAttempting.php create mode 100644 src/Event/Stateless/TokenVerificationFailed.php create mode 100644 src/Event/Stateless/TokenVerificationSucceeded.php diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 0983afc3..0e034961 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -21,8 +21,7 @@ final class Guard implements \Auth0\Laravel\Contract\Auth\Guard, \Illuminate\Con */ public function login(Authenticatable $user): self { - $this->getState()-> - setUser($user); + $this->getState()->setUser($user); return $this; } @@ -32,6 +31,11 @@ public function login(Authenticatable $user): self */ public function logout(): self { + // Although user() should never return null in this instance, default to an empty dummy user in such an event to avoid throwing an exception. + $user = $this->user() ?? new \Auth0\Laravel\Model\Stateful\User([]); + + event(new \Illuminate\Auth\Events\Logout(Guard::class, $user)); + app()->instance(StateInstance::class, null); Session::flush(); @@ -168,6 +172,10 @@ private function getUserFromToken(): ?Authenticatable return null; } + $event = new \Auth0\Laravel\Event\Stateless\TokenVerificationAttempting($token); + event($event); + $token = $event->getToken(); + try { // Attempt to decode the bearer token. $decoded = app(Auth0::class)->getSdk()->decode( @@ -175,6 +183,8 @@ private function getUserFromToken(): ?Authenticatable tokenType: \Auth0\SDK\Token::TYPE_TOKEN, )->toArray(); } catch (\Auth0\SDK\Exception\InvalidTokenException $invalidToken) { + event(new \Auth0\Laravel\Event\Stateless\TokenVerificationFailed($token, $invalidToken)); + // Invalid bearer token. return null; } @@ -196,6 +206,8 @@ private function getUserFromToken(): ?Authenticatable exit('User model returned fromAccessToken must implement \Auth0\Laravel\Contract\Model\Stateless\User.'); } + event(new \Auth0\Laravel\Event\Stateless\TokenVerificationSucceeded($token, $decoded)); + $this->getState()-> clear()-> setDecoded($decoded)-> diff --git a/src/Contract/Event/Stateless/TokenVerificationAttempting.php b/src/Contract/Event/Stateless/TokenVerificationAttempting.php new file mode 100644 index 00000000..e74ab00a --- /dev/null +++ b/src/Contract/Event/Stateless/TokenVerificationAttempting.php @@ -0,0 +1,27 @@ +user = $user; } /** diff --git a/src/Event/Stateless/TokenVerificationAttempting.php b/src/Event/Stateless/TokenVerificationAttempting.php new file mode 100644 index 00000000..08c795d1 --- /dev/null +++ b/src/Event/Stateless/TokenVerificationAttempting.php @@ -0,0 +1,35 @@ +token = $token; + $this->mutated = true; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getToken(): string + { + return $this->token; + } +} diff --git a/src/Event/Stateless/TokenVerificationFailed.php b/src/Event/Stateless/TokenVerificationFailed.php new file mode 100644 index 00000000..5aa6fdac --- /dev/null +++ b/src/Event/Stateless/TokenVerificationFailed.php @@ -0,0 +1,35 @@ +token; + } + + /** + * {@inheritdoc} + */ + public function getException(): Throwable + { + return $this->exception; + } +} diff --git a/src/Event/Stateless/TokenVerificationSucceeded.php b/src/Event/Stateless/TokenVerificationSucceeded.php new file mode 100644 index 00000000..eb650742 --- /dev/null +++ b/src/Event/Stateless/TokenVerificationSucceeded.php @@ -0,0 +1,33 @@ +token; + } + + /** + * {@inheritdoc} + */ + public function getPayload(): array + { + return $this->payload; + } +} diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index 131c8ce4..98213778 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -47,12 +47,21 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re try { if (null !== $code && null !== $state) { + event(new \Illuminate\Auth\Events\Attempting($guard::class, ['code' => $code, 'state' => $state], true)); + app(\Auth0\Laravel\Auth0::class)->getSdk()->exchange( code: $code, state: $state, ); } } catch (\Throwable $exception) { + $credentials = app(\Auth0\Laravel\Auth0::class)->getSdk()->getUser() ?? []; + $credentials['code'] = $code; + $credentials['state'] = $state; + $credentials['error'] = ['description' => $exception->getMessage()]; + + event(new \Illuminate\Auth\Events\Failed($guard::class, $guard->user(), $credentials)); + app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); // Throw hookable $event to allow custom error handling scenarios. @@ -72,6 +81,14 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re $error = \is_string($error) ? $error : ''; $errorDescription = \is_string($errorDescription) ? $errorDescription : ''; + $credentials = [ + 'code' => $code, + 'state' => $state, + 'error' => ['error' => $error, 'description' => $errorDescription] + ]; + + event(new \Illuminate\Auth\Events\Failed($guard::class, $guard->user(), $credentials)); + // Clear the local session via the Auth0-PHP SDK: app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); @@ -92,14 +109,20 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re $user = $guard->user(); if (null !== $user) { + event(new \Illuminate\Auth\Events\Validated($guard::class, $user)); + $request->session()->regenerate(); // Throw hookable event to allow custom application logic for successful logins: $event = new \Auth0\Laravel\Event\Stateful\AuthenticationSucceeded($user); event($event); + $user = $event->getUser(); // Apply any mutations to the user object: - $guard->setUser($event->getUser()); + $guard->setUser($user); + + event(new \Illuminate\Auth\Events\Login($guard::class, $user, true)); + event(new \Illuminate\Auth\Events\Authenticated($guard::class, $user)); } return redirect()->intended(config('auth0.routes.home', '/')); // @phpstan-ignore-line From 2531eed6c3b99bbef1d44657ed700bfc62058f1b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 7 Nov 2022 15:30:00 -0600 Subject: [PATCH 179/525] fix: `env()` incorrectly assigns `cookieExpires` to a `string` value (#332) fix: env() incorrectly setting `cookieExpires` to a string value, typo in `.env` name --- config/auth0.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/auth0.php b/config/auth0.php index 9625822e..d9db2ffd 100644 --- a/config/auth0.php +++ b/config/auth0.php @@ -39,7 +39,7 @@ 'cookieSecret' => env('AUTH0_COOKIE_SECRET', env('APP_KEY')), // How long, in seconds, before cookies expire. If set to 0 the cookie will expire at the end of the session (when the browser closes). - 'cookieExpires' => env('COOKIE_EXPIRES', 0), + 'cookieExpires' => (int) env('AUTH0_COOKIE_EXPIRES', 0), // Cookie domain, for example 'www.example.com', for use with PHP sessions and SDK cookies. Defaults to value of HTTP_HOST server environment information. // Note: To make cookies visible on all subdomains then the domain must be prefixed with a dot like '.example.com'. From 69c0d60aff896397b796cc5c76f0d38e1abb61d0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 7 Nov 2022 17:36:26 -0600 Subject: [PATCH 180/525] Release 7.3.0 (#333) --- CHANGELOG.md | 10 ++++++++++ src/Auth0.php | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a583966..a249f218 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## [7.3.0](https://github.com/auth0/laravel-auth0/tree/7.3.0) (2022-11-07) +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.2.2...7.3.0) + +**Added** +- add: Raise additional Laravel Auth Events [\#331](https://github.com/auth0/laravel-auth0/pull/331) ([evansims](https://github.com/evansims)) + +**Fixed** +- fix: `env()` incorrectly assigns `cookieExpires` to a `string` value [\#332](https://github.com/auth0/laravel-auth0/pull/332) ([evansims](https://github.com/evansims)) +- fix: Auth0\Laravel\Cache\LaravelCachePool::createItem returning a cache miss [\#329](https://github.com/auth0/laravel-auth0/pull/329) ([pkivits-litebit](https://github.com/pkivits-litebit)) + ## [7.2.2](https://github.com/auth0/laravel-auth0/tree/7.2.2) (2022-10-19) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.2.1...7.2.2) diff --git a/src/Auth0.php b/src/Auth0.php index 177b702f..9aab84b7 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -17,7 +17,7 @@ final class Auth0 implements \Auth0\Laravel\Contract\Auth0 /** * The Laravel-Auth0 SDK version:. */ - public const VERSION = '7.2.2'; + public const VERSION = '7.3.0'; /** * An instance of the Auth0-PHP SDK. From 045a639b6ac75765b3de9dabc360eab8f6a4f2f7 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 8 Nov 2022 10:25:48 -0600 Subject: [PATCH 181/525] fix: Typo in README vendor:publish command (#335) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index efbea3b1..b0ea4ac6 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Note the **Domain**, **Client ID**, and **Client Secret**. These values will be Use Laravel's CLI to generate an Auth0 configuration file within your project: ``` -php artisan vendor:publish --tag auto0-config +php artisan vendor:publish --tag auth0-config ``` A new file will appear within your project, `app/config/auth0.php`. You should avoid making changes to this file directly. From 7c2862ce3616dbaae5469993fc5417337001ab39 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 9 Dec 2022 14:02:19 -0600 Subject: [PATCH 182/525] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b0ea4ac6..dd11e7bc 100644 --- a/README.md +++ b/README.md @@ -214,7 +214,7 @@ Route::get('/api/public', function () { Our support windows are determined by the [Laravel release support](https://laravel.com/docs/releases#support-policy) and [PHP release support](https://www.php.net/supported-versions.php) schedules, and support ends when either the Laravel framework or PHP runtime outlined below stop receiving security fixes, whichever may come first. -| SDK Version | Laravel Version¹ | PHP Version² | Support Ends³ | +| SDK Version | Laravel Version | PHP Version | Support Ends | |-------------|------------------|--------------|---------------| | 7 | 9 | 8.1 | Feb 2024 | | | | 8.0 | Nov 2023 | @@ -223,7 +223,7 @@ Our support windows are determined by the [Laravel release support](https://lara | 6⁴ | 8 | 8.1 | Jan 2023 | | | | 8.0 | Jan 2023 | -Deprecations of EOL'd language or framework versions are not considered a breaking change, as Composer handles these scenarios elegantly. Legacy applications will stop receiving updates from us, but will continue to function on those unsupported SDK versions. +Deprecations of EOL'd language or framework versions are not considered a breaking change, as Composer handles these scenarios elegantly. Legacy applications will stop receiving updates from us, but will continue to function on those unsupported SDK versions. Please ensure your PHP environment and Laravel framework dependencies always remain up to date. ## Octane Support From 2bb0442069d4e1e384d07f4aeb265c3c2d77608f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 9 Dec 2022 14:02:36 -0600 Subject: [PATCH 183/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dd11e7bc..b01f0409 100644 --- a/README.md +++ b/README.md @@ -220,7 +220,7 @@ Our support windows are determined by the [Laravel release support](https://lara | | | 8.0 | Nov 2023 | | | 8 | 8.1 | Jan 2023 | | | | 8.0 | Jan 2023 | -| 6⁴ | 8 | 8.1 | Jan 2023 | +| 6 | 8 | 8.1 | Jan 2023 | | | | 8.0 | Jan 2023 | Deprecations of EOL'd language or framework versions are not considered a breaking change, as Composer handles these scenarios elegantly. Legacy applications will stop receiving updates from us, but will continue to function on those unsupported SDK versions. Please ensure your PHP environment and Laravel framework dependencies always remain up to date. From 5adff9ddb7760861ff3b58eb6985eb566d8a3386 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 12 Dec 2022 18:15:38 -0600 Subject: [PATCH 184/525] Update composer.json --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index 4382a241..a07a5ad0 100644 --- a/composer.json +++ b/composer.json @@ -110,7 +110,6 @@ }, "scripts": { "phpstan": "@php vendor/bin/phpstan analyse", - "phpstan:pro": "@php vendor/bin/phpstan analyse --pro", "pint": "@php vendor/bin/pint --test", "pint:fix": "@php vendor/bin/pint", "psalm": "@php vendor/bin/psalm", From da42413f76ee46d9aff0005b747eb7dc06453584 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 12 Dec 2022 18:28:31 -0600 Subject: [PATCH 185/525] feat: Add `Auth0\Laravel\Event\Configuration\Building` event hook (#339) * feat: Add `Auth0\Laravel\Event\Configuration\Building` event hook * Update Auth0.php * Linter fixes * Linter fixes --- src/Auth0.php | 5 ++- src/Contract/Event/Configuration/Building.php | 27 +++++++++++++++ src/Event/Configuration/Building.php | 33 +++++++++++++++++++ src/Store/LaravelSession.php | 5 +++ 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/Contract/Event/Configuration/Building.php create mode 100644 src/Event/Configuration/Building.php diff --git a/src/Auth0.php b/src/Auth0.php index 9aab84b7..204282e0 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -77,7 +77,10 @@ public function getConfiguration(): Configuration } } - $configuration = new Configuration($config); + $event = new \Auth0\Laravel\Event\Configuration\Building($config); + event($event); + + $configuration = new Configuration($event->getConfiguration()); if (! \in_array($configuration->getStrategy(), [Configuration::STRATEGY_API, Configuration::STRATEGY_MANAGEMENT_API], true)) { // If no sessionStorage is defined, use an LaravelSession store instance. diff --git a/src/Contract/Event/Configuration/Building.php b/src/Contract/Event/Configuration/Building.php new file mode 100644 index 00000000..b459f109 --- /dev/null +++ b/src/Contract/Event/Configuration/Building.php @@ -0,0 +1,27 @@ +configuration = $configuration; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getConfiguration(): array + { + return $this->configuration; + } +} diff --git a/src/Store/LaravelSession.php b/src/Store/LaravelSession.php index 793385f6..0dca8976 100644 --- a/src/Store/LaravelSession.php +++ b/src/Store/LaravelSession.php @@ -104,6 +104,11 @@ private function boot(): void } } + /** + * {@inheritdoc} + * + * @psalm-suppress RedundantConditionGivenDocblockType + */ private function getStore(): \Illuminate\Session\Store { $request = request(); From 376a3f68b106c01a4acb1b44029004bd911f7065 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 12 Dec 2022 18:52:28 -0600 Subject: [PATCH 186/525] feat: Add `Auth0\Laravel\Event\Middleware\...` event hooks (#340) * feat: Add `Auth0\Laravel\Event\Middleware` event hooks * Typo fix * Linter fixes --- src/Contract/Event/Middleware/StatefulRequest.php | 9 +++++++++ src/Contract/Event/Middleware/StatelessRequest.php | 9 +++++++++ src/Event/Middleware/StatefulRequest.php | 12 ++++++++++++ src/Event/Middleware/StatelessRequest.php | 12 ++++++++++++ src/Http/Middleware/Stateful/Authenticate.php | 2 ++ .../Middleware/Stateful/AuthenticateOptional.php | 2 ++ src/Http/Middleware/Stateless/Authorize.php | 2 ++ src/Http/Middleware/Stateless/AuthorizeOptional.php | 2 ++ 8 files changed, 50 insertions(+) create mode 100644 src/Contract/Event/Middleware/StatefulRequest.php create mode 100644 src/Contract/Event/Middleware/StatelessRequest.php create mode 100644 src/Event/Middleware/StatefulRequest.php create mode 100644 src/Event/Middleware/StatelessRequest.php diff --git a/src/Contract/Event/Middleware/StatefulRequest.php b/src/Contract/Event/Middleware/StatefulRequest.php new file mode 100644 index 00000000..b97bd819 --- /dev/null +++ b/src/Contract/Event/Middleware/StatefulRequest.php @@ -0,0 +1,9 @@ +guard('auth0'); + event(new \Auth0\Laravel\Event\Middleware\StatefulRequest($request, $guard)); + /** * @var Guard $guard */ diff --git a/src/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Http/Middleware/Stateful/AuthenticateOptional.php index f34cd340..2e15dbbd 100644 --- a/src/Http/Middleware/Stateful/AuthenticateOptional.php +++ b/src/Http/Middleware/Stateful/AuthenticateOptional.php @@ -25,6 +25,8 @@ public function handle(\Illuminate\Http\Request $request, \Closure $next) */ $guard = $auth->guard('auth0'); + event(new \Auth0\Laravel\Event\Middleware\StatefulRequest($request, $guard)); + /** * @var Guard $guard */ diff --git a/src/Http/Middleware/Stateless/Authorize.php b/src/Http/Middleware/Stateless/Authorize.php index 5a0121a5..2479732b 100644 --- a/src/Http/Middleware/Stateless/Authorize.php +++ b/src/Http/Middleware/Stateless/Authorize.php @@ -24,6 +24,8 @@ public function handle(\Illuminate\Http\Request $request, \Closure $next, string */ $guard = $auth->guard('auth0'); + event(new \Auth0\Laravel\Event\Middleware\StatelessRequest($request, $guard)); + /** * @var Guard $guard */ diff --git a/src/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Http/Middleware/Stateless/AuthorizeOptional.php index 7ae90280..c97c2459 100644 --- a/src/Http/Middleware/Stateless/AuthorizeOptional.php +++ b/src/Http/Middleware/Stateless/AuthorizeOptional.php @@ -23,6 +23,8 @@ public function handle(\Illuminate\Http\Request $request, \Closure $next) */ $guard = $auth->guard('auth0'); + event(new \Auth0\Laravel\Event\Middleware\StatelessRequest($request, $guard)); + /** * @var Guard $guard */ From 7020d5ff05a6aa6039dfa5481e1b47947e701e2d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 12 Dec 2022 19:10:51 -0600 Subject: [PATCH 187/525] Release 7.4.0 (#341) --- CHANGELOG.md | 7 +++++++ src/Auth0.php | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a249f218..0ac453e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## [7.4.0](https://github.com/auth0/laravel-auth0/tree/7.4.0) (2022-12-12) +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.3.0...7.4.0) + +**Added** +- feat: Add `Auth0\Laravel\Event\Middleware\...` event hooks [\#340](https://github.com/auth0/laravel-auth0/pull/340) ([evansims](https://github.com/evansims)) +- feat: Add `Auth0\Laravel\Event\Configuration\Building` event hook [\#339](https://github.com/auth0/laravel-auth0/pull/339) ([evansims](https://github.com/evansims)) + ## [7.3.0](https://github.com/auth0/laravel-auth0/tree/7.3.0) (2022-11-07) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.2.2...7.3.0) diff --git a/src/Auth0.php b/src/Auth0.php index 204282e0..160ec6a0 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -17,7 +17,7 @@ final class Auth0 implements \Auth0\Laravel\Contract\Auth0 /** * The Laravel-Auth0 SDK version:. */ - public const VERSION = '7.3.0'; + public const VERSION = '7.4.0'; /** * An instance of the Auth0-PHP SDK. From 6760d9e17aa613b46ef5dd064c91beef82c2f2da Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 14 Dec 2022 14:20:02 -0600 Subject: [PATCH 188/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b01f0409..c7ab39ab 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![laravel-auth0](https://cdn.auth0.com/website/sdks/banners/auth0-php-banner.png) +![laravel-auth0](https://cdn.auth0.com/website/sdks/banners/laravel-auth0-banner.png) Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. From cacd280769c5fa62edf8b7255f96d7d9b392cfaf Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 19 Dec 2022 16:56:06 -0600 Subject: [PATCH 189/525] docs: Add note about `StartSession` middleware (#343) --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c7ab39ab..0c71e486 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,11 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. - PHP 8.0+ - Laravel 8 / Laravel 9 +- `Illuminate\Session\Middleware\StartSession` enabled in `app/Http/Kernel.php` > Please review our [support policy](#support-policy) to learn when language and framework versions will exit support in the future. -> [Octane support](#octane-support) is experimental and not advisable for use in production at this time. +> [Octane support](#octane-support) is experimental and not advisable for use in production at this time. ### Installation @@ -114,7 +115,7 @@ Next, find the `guards` section, and add `auth0` there: ], ``` -Finally, find the `providers` section, and add `auth0` there as well: +Next, find the `providers` section, and add `auth0` there as well: ```php // 👆 Continued from above, in config/auth.php 'providers' => [ @@ -126,6 +127,17 @@ Finally, find the `providers` section, and add `auth0` there as well: ], ``` +Although it is enabled by default, now is a good time to ensure the `StartSession` middleware is enabled in your `app/Http/Kernel.php` file: +```php +protected $middlewareGroups = [ + 'web' => [ + // ... + \Illuminate\Session\Middleware\StartSession::class, + // ... + ], +]; +``` + ## Add login to stateful web applications For regular web applications that provide login and logout, we provide prebuilt route controllers to add to your `app/routes/web.php` file that will automatically handle your application's authentication flow with Auth0 for you: From 5bc1157fb428f4c135218c5d5472377e65adef41 Mon Sep 17 00:00:00 2001 From: Weber Tsai Date: Mon, 27 Feb 2023 12:12:14 +0800 Subject: [PATCH 190/525] add Laravel v10 support (#349) --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index a07a5ad0..530111e7 100644 --- a/composer.json +++ b/composer.json @@ -39,14 +39,14 @@ "ext-json": "*", "ext-mbstring": "*", "auth0/auth0-php": "^8.3.4", - "illuminate/contracts": "^8.0 || ^9.0", - "illuminate/http": "^8.0 || ^9.0", - "illuminate/support": "^8.0 || ^9.0", + "illuminate/contracts": "^8.0 || ^9.0 || ^10.0", + "illuminate/http": "^8.0 || ^9.0 || ^10.0", + "illuminate/support": "^8.0 || ^9.0 || ^10.0", "psr/cache": "^3.0" }, "require-dev": { "ergebnis/composer-normalize": "dev-main", - "laravel/laravel": "^8.4.4 || ^9.0", + "laravel/laravel": "^8.4.4 || ^9.0 || ^10.0", "laravel/pint": "^1.2", "nunomaduro/larastan": "^1.0", "nyholm/psr7": "^1.4", From 4dace3bba6f18f6493c4ead2a90b85202bfe56f7 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:09:56 -0500 Subject: [PATCH 191/525] Update test suite --- .gitignore | 5 +- .php-cs-fixer.dist.php | 228 ++++++++++++++++ .styleci.yml | 258 ------------------ composer.json | 60 ++-- config/auth0.php | 33 ++- infection.json5.dist | 11 + phpstan.neon.dist | 6 +- phpunit.xml.dist | 39 +-- pint.json | 4 - psalm.xml.dist | 6 +- rector.php | 26 +- tests/Pest.php | 95 ++++--- tests/TestCase.php | 102 ++++++- tests/Unit/Auth/GuardStatefulTest.php | 258 ++++++++++++++++++ tests/Unit/Auth/GuardStatelessTest.php | 117 ++++++++ tests/Unit/Auth/GuardTest.php | 187 +++++++++++++ tests/Unit/Auth/User/ProviderTest.php | 88 ++++++ tests/Unit/Auth/User/RepositoryTest.php | 24 ++ tests/Unit/Auth0Test.php | 139 ++++++---- tests/Unit/Cache/LaravelCacheItemTest.php | 100 +++++++ tests/Unit/Cache/LaravelCachePoolTest.php | 257 +++++++++++++++++ tests/Unit/ConfigurationTest.php | 34 +++ tests/Unit/Entities/CredentialTest.php | 191 +++++++++++++ .../Http/Controller/Stateful/CallbackTest.php | 163 +++++++++++ .../Http/Controller/Stateful/LoginTest.php | 62 +++++ .../Http/Controller/Stateful/LogoutTest.php | 62 +++++ .../Stateful/AuthenticateOptionalTest.php | 117 ++++++++ .../Middleware/Stateful/AuthenticateTest.php | 119 ++++++++ .../Stateless/AuthorizeOptionalTest.php | 152 +++++++++++ .../Middleware/Stateless/AuthorizeTest.php | 150 ++++++++++ tests/Unit/Model/UserTest.php | 103 +++++++ tests/Unit/ServiceProviderTest.php | 192 +++++++++++++ tests/Unit/Store/LaravelSessionTest.php | 66 +++++ tests/Unit/Traits/ActingAsAuth0UserTest.php | 172 ++++++++++++ tests/Unit/Traits/ImpersonateTest.php | 168 ++++++++++++ tests/constants.php | 16 -- 36 files changed, 3364 insertions(+), 446 deletions(-) create mode 100644 .php-cs-fixer.dist.php delete mode 100644 .styleci.yml create mode 100644 infection.json5.dist delete mode 100644 pint.json create mode 100644 tests/Unit/Auth/GuardStatefulTest.php create mode 100644 tests/Unit/Auth/GuardStatelessTest.php create mode 100644 tests/Unit/Auth/User/ProviderTest.php create mode 100644 tests/Unit/Auth/User/RepositoryTest.php create mode 100644 tests/Unit/Cache/LaravelCacheItemTest.php create mode 100644 tests/Unit/Cache/LaravelCachePoolTest.php create mode 100644 tests/Unit/ConfigurationTest.php create mode 100644 tests/Unit/Entities/CredentialTest.php create mode 100644 tests/Unit/Http/Controller/Stateful/CallbackTest.php create mode 100644 tests/Unit/Http/Controller/Stateful/LoginTest.php create mode 100644 tests/Unit/Http/Controller/Stateful/LogoutTest.php create mode 100644 tests/Unit/Http/Middleware/Stateful/AuthenticateOptionalTest.php create mode 100644 tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php create mode 100644 tests/Unit/Http/Middleware/Stateless/AuthorizeOptionalTest.php create mode 100644 tests/Unit/Http/Middleware/Stateless/AuthorizeTest.php create mode 100644 tests/Unit/Model/UserTest.php create mode 100644 tests/Unit/ServiceProviderTest.php create mode 100644 tests/Unit/Store/LaravelSessionTest.php create mode 100644 tests/Unit/Traits/ActingAsAuth0UserTest.php create mode 100644 tests/Unit/Traits/ImpersonateTest.php diff --git a/.gitignore b/.gitignore index 397959dd..ca94a6ac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ build/ vendor/ +coverage/ +tmp/ .idea/ .env .DS_Store @@ -7,4 +9,5 @@ composer.lock composer.phar .phpunit.result.cache composer.local.json - +composer.local.json_ +.php-cs-fixer.cache diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 00000000..e0b641b3 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,228 @@ +setRiskyAllowed(true) + ->setRules([ + 'array_indentation' => true, + 'array_push' => true, + 'array_syntax' => ['syntax' => 'short'], + 'assign_null_coalescing_to_coalesce_equal' => true, + 'backtick_to_shell_exec' => true, + 'binary_operator_spaces' => ['operators' => ['=' => 'align', 'xor' => null, '+=' => 'align_single_space', '===' => 'align_single_space_minimal', '|' => 'single_space', '=>' => 'align_single_space_minimal_by_scope']], + 'blank_line_after_namespace' => true, + 'blank_line_after_opening_tag' => true, + 'blank_line_before_statement' => true, + 'braces' => true, + 'cast_spaces' => true, + 'class_attributes_separation' => ['elements' => ['const' => 'only_if_meta', 'method' => 'one', 'property' => 'only_if_meta', 'trait_import' => 'one', 'case' => 'one']], + 'class_definition' => true, + 'class_reference_name_casing' => true, + 'clean_namespace' => true, + 'combine_consecutive_issets' => true, + 'combine_consecutive_unsets' => true, + 'combine_nested_dirname' => true, + 'comment_to_phpdoc' => ['ignored_tags' => ['codeCoverageIgnoreStart', 'codeCoverageIgnoreEnd', 'phpstan-ignore-next-line']], + 'compact_nullable_typehint' => true, + 'concat_space' => ['spacing' => 'one'], + 'constant_case' => ['case' => 'lower'], + 'date_time_create_from_format_call' => true, + 'declare_equal_normalize' => ['space' => 'none'], + 'declare_parentheses' => true, + 'declare_strict_types' => true, + 'dir_constant' => true, + 'doctrine_annotation_array_assignment' => true, + 'doctrine_annotation_braces' => true, + 'doctrine_annotation_indentation' => true, + 'doctrine_annotation_spaces' => true, + 'echo_tag_syntax' => ['format' => 'long'], + 'elseif' => true, + 'empty_loop_body' => true, + 'empty_loop_condition' => true, + 'encoding' => true, + 'ereg_to_preg' => true, + 'error_suppression' => true, + 'escape_implicit_backslashes' => true, + 'explicit_indirect_variable' => true, + 'explicit_string_variable' => true, + 'final_class' => true, + 'final_internal_class' => true, + 'final_public_method_for_abstract_class' => true, + 'fopen_flag_order' => true, + 'fopen_flags' => true, + 'full_opening_tag' => true, + 'fully_qualified_strict_types' => true, + 'function_declaration' => true, + 'function_to_constant' => true, + 'function_typehint_space' => true, + 'general_phpdoc_annotation_remove' => true, + 'general_phpdoc_tag_rename' => true, + 'get_class_to_class_keyword' => true, + 'global_namespace_import' => ['import_classes' => true, 'import_constants' => true, 'import_functions' => true], + 'group_import' => true, + 'heredoc_indentation' => true, + 'heredoc_to_nowdoc' => true, + 'implode_call' => true, + 'include' => true, + 'increment_style' => ['style' => 'pre'], + 'indentation_type' => true, + 'integer_literal_case' => true, + 'is_null' => true, + 'lambda_not_used_import' => true, + 'line_ending' => true, + 'linebreak_after_opening_tag' => true, + 'list_syntax' => ['syntax' => 'short'], + 'logical_operators' => true, + 'lowercase_cast' => true, + 'lowercase_keywords' => true, + 'lowercase_static_reference' => true, + 'magic_constant_casing' => true, + 'magic_method_casing' => true, + 'mb_str_functions' => true, + 'method_argument_space' => true, + 'method_chaining_indentation' => true, + 'modernize_strpos' => true, + 'modernize_types_casting' => true, + 'multiline_comment_opening_closing' => true, + 'multiline_whitespace_before_semicolons' => true, + 'native_function_casing' => true, + 'native_function_invocation' => true, + 'native_function_type_declaration_casing' => true, + 'new_with_braces' => true, + 'no_alias_functions' => true, + 'no_alias_language_construct_call' => true, + 'no_alternative_syntax' => true, + 'no_binary_string' => true, + 'no_blank_lines_after_class_opening' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_break_comment' => true, + 'no_closing_tag' => true, + 'no_empty_comment' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_blank_lines' => true, + 'no_homoglyph_names' => true, + 'no_leading_import_slash' => true, + 'no_leading_namespace_whitespace' => true, + 'no_mixed_echo_print' => true, + 'no_multiline_whitespace_around_double_arrow' => true, + 'no_multiple_statements_per_line' => true, + 'no_php4_constructor' => true, + 'no_short_bool_cast' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'no_space_around_double_colon' => true, + 'no_spaces_after_function_name' => true, + 'no_spaces_around_offset' => true, + 'no_spaces_inside_parenthesis' => true, + 'no_superfluous_elseif' => true, + 'no_trailing_comma_in_singleline_array' => true, + 'no_trailing_comma_in_singleline_function_call' => true, + 'no_trailing_comma_in_singleline' => true, + 'no_trailing_whitespace_in_comment' => true, + 'no_trailing_whitespace_in_string' => true, + 'no_trailing_whitespace' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unneeded_curly_braces' => true, + 'no_unneeded_final_method' => true, + 'no_unneeded_import_alias' => true, + 'no_unreachable_default_argument_value' => true, + 'no_unset_cast' => true, + 'no_unused_imports' => true, + 'no_useless_concat_operator' => true, + 'no_useless_else' => true, + 'no_useless_nullsafe_operator' => true, + 'no_useless_return' => true, + 'no_useless_sprintf' => true, + 'no_whitespace_before_comma_in_array' => true, + 'no_whitespace_in_blank_line' => true, + 'non_printable_character' => true, + 'normalize_index_brace' => true, + 'not_operator_with_successor_space' => true, + 'nullable_type_declaration_for_default_null_value' => true, + 'object_operator_without_whitespace' => true, + 'octal_notation' => true, + 'operator_linebreak' => true, + 'ordered_class_elements' => ['sort_algorithm' => 'alpha', 'order' => ['case', 'constant', 'constant_private', 'constant_protected', 'constant_public', 'construct', 'destruct', 'magic', 'method', 'method_abstract', 'method_private', 'method_private_abstract', 'method_private_abstract_static', 'method_private_static', 'method_protected', 'method_protected_abstract', 'method_protected_abstract_static', 'method_protected_static', 'method_public', 'method_public_abstract', 'method_public_abstract_static', 'method_public_static', 'method_static', 'phpunit', 'private', 'property', 'property_private', 'property_private_readonly', 'property_private_static', 'property_protected', 'property_protected_readonly', 'property_protected_static', 'property_public', 'property_public_readonly', 'property_public_static', 'property_static', 'protected', 'public', 'use_trait']], + 'ordered_imports' => ['sort_algorithm' => 'alpha', 'imports_order' => ['const', 'class', 'function']], + 'ordered_interfaces' => true, + 'ordered_traits' => true, + 'php_unit_fqcn_annotation' => true, + 'phpdoc_add_missing_param_annotation' => ['only_untyped' => false], + 'phpdoc_align' => ['align' => 'vertical'], + 'phpdoc_indent' => true, + 'phpdoc_inline_tag_normalizer' => true, + 'phpdoc_line_span' => true, + 'phpdoc_no_access' => true, + 'phpdoc_no_empty_return' => true, + 'phpdoc_no_package' => true, + 'phpdoc_no_useless_inheritdoc' => true, + 'phpdoc_order_by_value' => true, + 'phpdoc_order' => true, + 'phpdoc_return_self_reference' => ['replacements' => ['this' => 'self']], + 'phpdoc_scalar' => true, + 'phpdoc_separation' => true, + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_summary' => true, + 'phpdoc_tag_type' => true, + 'phpdoc_to_comment' => ['ignored_tags' => ['var']], + 'phpdoc_trim_consecutive_blank_line_separation' => true, + 'phpdoc_trim' => true, + 'phpdoc_types_order' => true, + 'phpdoc_types' => true, + 'phpdoc_var_annotation_correct_order' => true, + 'phpdoc_var_without_name' => true, + 'pow_to_exponentiation' => true, + 'protected_to_private' => true, + 'psr_autoloading' => true, + 'random_api_migration' => true, + 'regular_callable_call' => true, + 'return_assignment' => true, + 'return_type_declaration' => ['space_before' => 'none'], + 'return_type_declaration' => true, + 'self_accessor' => true, + 'self_static_accessor' => true, + 'semicolon_after_instruction' => true, + 'set_type_to_cast' => true, + 'short_scalar_cast' => true, + 'simple_to_complex_string_variable' => true, + 'simplified_if_return' => true, + 'single_blank_line_at_eof' => true, + 'single_blank_line_before_namespace' => true, + 'single_class_element_per_statement' => true, + 'single_line_after_imports' => true, + 'single_line_comment_spacing' => true, + 'single_line_comment_style' => ['comment_types' => ['hash']], + 'single_line_throw' => true, + 'single_quote' => true, + 'single_space_after_construct' => true, + 'single_trait_insert_per_statement' => true, + 'space_after_semicolon' => true, + 'standardize_increment' => true, + 'standardize_not_equals' => true, + 'statement_indentation' => true, + 'static_lambda' => true, + 'strict_comparison' => true, + 'strict_param' => true, + 'string_length_to_empty' => true, + 'string_line_ending' => true, + 'switch_case_semicolon_to_colon' => true, + 'switch_case_space' => true, + 'switch_continue_to_break' => true, + 'ternary_operator_spaces' => true, + 'ternary_to_elvis_operator' => true, + 'ternary_to_null_coalescing' => true, + 'trailing_comma_in_multiline' => ['after_heredoc' => true, 'elements' => ['arguments', 'parameters']], + 'trim_array_spaces' => true, + 'types_spaces' => ['space' => 'single'], + 'unary_operator_spaces' => true, + 'use_arrow_functions' => true, + 'visibility_required' => true, + 'void_return' => true, + 'whitespace_after_comma_in_array' => true, + 'yoda_style' => true, + ]) + ->setFinder( + PhpCsFixer\Finder::create() + ->exclude('vendor') + ->in([__DIR__.'/src/']) + ) +; diff --git a/.styleci.yml b/.styleci.yml deleted file mode 100644 index 6f1da912..00000000 --- a/.styleci.yml +++ /dev/null @@ -1,258 +0,0 @@ -risky: true -version: 8.0 -preset: none -enabled: - - align_double_arrow - - align_phpdoc - - alpha_ordered_imports - - alpha_ordered_traits - - array_indentation - - array_push - - assign_null_coalescing_to_coalesce_equal - - backtick_to_shell_exec - - binary_operator_spaces - - blank_line_after_namespace - - blank_line_after_opening_tag - - blank_line_before_break - - blank_line_before_cases - - blank_line_before_continue - - blank_line_before_declare - - blank_line_before_do - - blank_line_before_exit - - blank_line_before_for - - blank_line_before_goto - - blank_line_before_if - - blank_line_before_include - - blank_line_before_return - - blank_line_before_switch - - blank_line_before_throw - - blank_line_before_try - - blank_line_before_while - - blank_line_before_yield - - cast_spaces - - class_reference_name_casing - - clean_namespace - - combine_consecutive_issets - - combine_consecutive_unsets - - combine_nested_dirname - - comment_to_phpdoc - - compact_nullable_typehint - - concat_with_spaces - - const_separation - - const_visibility_required - - declare_equal_normalize - - declare_strict_types - - deprecation_error_suppression - - die_to_exit - - dir_constant - - doctrine_annotation_array_assignment - - doctrine_annotation_braces - - doctrine_annotation_indentation - - doctrine_annotation_spaces - - elseif - - empty_loop_body_braces - - empty_loop_condition - - encoding - - ereg_to_preg - - escape_implicit_backslashes - - explicit_indirect_variable - - explicit_string_variable - - final_internal_class - - final_public_method_for_abstract_class - - fopen_flag_order - - fopen_flags - - full_opening_tag - - fully_qualified_strict_types - - function_declaration - - function_to_constant - - function_typehint_space - - get_class_to_class_keyword - - hash_to_slash_comment - - heredoc_indentation - - heredoc_to_nowdoc - - implode_call - - include - - indentation - - integer_literal_case - - is_null - - laravel_braces - - laravel_phpdoc_alignment - - laravel_phpdoc_order - - laravel_phpdoc_separation - - linebreak_after_opening_tag - - logical_operators - - lowercase_cast - - lowercase_constants - - lowercase_keywords - - lowercase_static_reference - - magic_constant_casing - - magic_method_casing - - mb_str_functions - - method_argument_space_strict - - method_chaining_indentation - - method_separation - - method_visibility_required - - modernize_strpos - - modernize_types_casting - - multiline_comment_opening_closing - - native_function_casing - - native_function_invocation_symfony - - native_function_type_declaration_casing - - new_with_braces - - no_alias_functions - - no_alternative_syntax - - no_binary_string - - no_blank_lines_after_class_opening - - no_blank_lines_after_phpdoc - - no_blank_lines_after_return - - no_blank_lines_after_throw - - no_blank_lines_around_break - - no_blank_lines_around_cases - - no_blank_lines_around_continue - - no_blank_lines_around_switch - - no_blank_lines_between_imports - - no_break_comment - - no_closing_tag - - no_empty_comment - - no_empty_phpdoc - - no_empty_statement - - no_extra_block_blank_lines - - no_extra_consecutive_blank_lines - - no_homoglyph_names - - no_leading_import_slash - - no_leading_namespace_whitespace - - no_multiline_whitespace_around_double_arrow - - no_multiline_whitespace_before_semicolons - - no_php4_constructor - - no_short_bool_cast - - no_short_echo_tag - - no_singleline_whitespace_before_semicolons - - no_space_around_double_colon - - no_spaces_after_function_name - - no_spaces_inside_offset - - no_spaces_inside_parenthesis - - no_spaces_outside_offset - - no_superfluous_elseif - - no_superfluous_phpdoc_tags_symfony - - no_trailing_comma_in_list_call - - no_trailing_comma_in_singleline_array - - no_trailing_comma_in_singleline_function_call - - no_trailing_whitespace - - no_trailing_whitespace_in_comment - - no_trailing_whitespace_in_string - - no_unneeded_control_parentheses - - no_unneeded_curly_braces - - no_unneeded_final_method - - no_unneeded_import_alias - - no_unreachable_default_argument_value - - no_unset_cast - - no_unused_imports - - no_unused_lambda_imports - - no_useless_else - - no_useless_return - - no_useless_sprintf - - no_whitespace_before_comma_in_array - - no_whitespace_in_blank_line - - non_printable_character - - normalize_index_brace - - not_operator_with_successor_space - - nullable_type_declarations - - object_operator_without_whitespace - - operator_linebreak_end - - ordered_class_elements - - php_unit_fqcn_annotation - - phpdoc_add_missing_param_annotation - - phpdoc_annotation_without_dot - - phpdoc_indent - - phpdoc_inline_inheritdoc - - phpdoc_inline_tag_normalizer - - phpdoc_link_to_see - - phpdoc_no_access - - phpdoc_no_empty_return - - phpdoc_no_package - - phpdoc_no_useless_inheritdoc - - phpdoc_property - - phpdoc_return_self_reference - - phpdoc_scalar - - phpdoc_single_line_var_spacing - - phpdoc_singular_inheritdoc - - phpdoc_summary - - phpdoc_to_comment - - phpdoc_trim - - phpdoc_trim_consecutive_blank_line_separation - - phpdoc_type_to_var - - phpdoc_types - - phpdoc_types_order - - phpdoc_var_order - - phpdoc_var_without_name - - pow_to_exponentiation - - pre_increment - - print_to_echo - - property_separation - - property_visibility_required - - protected_to_private - - psr4 - - random_api_migration - - regular_callable_call - - return_assignment - - return_type_declaration - - self_accessor - - self_static_accessor - - semicolon_after_instruction - - set_type_to_cast - - short_array_syntax - - short_list_syntax - - short_scalar_cast - - simple_to_complex_string_variable - - simplified_if_return - - single_blank_line_at_eof - - single_blank_line_before_namespace - - single_class_element_per_statement - - single_import_per_statement - - single_line_after_imports - - single_line_comment_spacing - - single_line_throw - - single_quote - - single_space_after_construct - - single_trait_insert_per_statement - - space_after_semicolon - - standardize_increment - - standardize_not_equals - - static_lambda - - strict_comparison - - strict_param - - string_length_to_empty - - string_line_ending - - switch_case_semicolon_to_colon - - switch_case_space - - switch_continue_to_break - - symfony_class_definition - - ternary_operator_spaces - - ternary_to_elvis_operator - - ternary_to_null_coalescing - - trailing_comma_in_multiline_array - - trailing_comma_in_multiline_call - - trailing_comma_in_multiline_definition - - trim_array_spaces - - unalign_equals - - unary_operator_spaces - - union_type_without_spaces - - unix_line_endings - - use_arrow_functions - - void_return - - whitespace_after_comma_in_array - - yoda_style -finder: - exclude: - - "modules" - - "node_modules" - - "nova" - - "nova-components" - - "storage" - - "spark" - - "vendor" - - "tests" - name: "*.php" - not-name: - - "*.blade.php" - - "_ide_helper.php" diff --git a/composer.json b/composer.json index a07a5ad0..a6a51864 100644 --- a/composer.json +++ b/composer.json @@ -39,26 +39,29 @@ "ext-json": "*", "ext-mbstring": "*", "auth0/auth0-php": "^8.3.4", - "illuminate/contracts": "^8.0 || ^9.0", - "illuminate/http": "^8.0 || ^9.0", - "illuminate/support": "^8.0 || ^9.0", - "psr/cache": "^3.0" + "illuminate/contracts": "^9.0 || ^10.0", + "illuminate/http": "^9.0 || ^10.0", + "illuminate/support": "^9.0 || ^10.0", + "psr/cache": "^2.0 || ^3.0" }, "require-dev": { - "ergebnis/composer-normalize": "dev-main", - "laravel/laravel": "^8.4.4 || ^9.0", - "laravel/pint": "^1.2", - "nunomaduro/larastan": "^1.0", - "nyholm/psr7": "^1.4", - "orchestra/testbench": "6.25.1", - "pestphp/pest": "^1.21", - "pestphp/pest-plugin-laravel": "^1.2", - "phpstan/phpstan": "^1.7", - "phpstan/phpstan-strict-rules": "1.4.3", - "phpunit/phpunit": "^9.5", - "psalm/plugin-laravel": "^2.0", - "rector/rector": "^0.13.6", - "vimeo/psalm": "^4.28", + "friendsofphp/php-cs-fixer": "^3.14", + "infection/infection": "^0.26", + "nunomaduro/collision": "^6.1", + "nunomaduro/larastan": "^2.5", + "orchestra/testbench": "^7.19 || ^8.0", + "pestphp/pest": "^1.22", + "pestphp/pest-plugin-laravel": "^1.4", + "pestphp/pest-plugin-mock": "^1.0", + "phpstan/phpstan": "^1.10", + "phpstan/phpstan-strict-rules": "^1.5", + "phpunit/phpunit": "^9.6", + "psalm/plugin-laravel": "^2.8", + "psr-mock/http-client-implementation": "1.x-dev", + "psr-mock/http-factory-implementation": "1.x-dev", + "psr-mock/http-message-implementation": "1.x-dev", + "rector/rector": "^0.15", + "vimeo/psalm": "^5.8", "wikimedia/composer-merge-plugin": "^2.0" }, "minimum-stability": "dev", @@ -77,16 +80,15 @@ "allow-plugins": { "pestphp/pest-plugin": true, "wikimedia/composer-merge-plugin": true, - "ergebnis/composer-normalize": true + "infection/extension-installer": true, + "php-http/discovery": false }, "optimize-autoloader": true, + "preferred-install": "dist", + "process-timeout": 0, "sort-packages": true }, "extra": { - "composer-normalize": { - "indent-size": 4, - "indent-style": "space" - }, "laravel": { "aliases": { "Auth0": "Auth0\\Laravel\\Facade\\Auth0" @@ -109,13 +111,17 @@ } }, "scripts": { - "phpstan": "@php vendor/bin/phpstan analyse", - "pint": "@php vendor/bin/pint --test", + "mutate": "@php ./vendor/bin/infection --test-framework=pest --show-mutations", + "phpcs:fix": "@php vendor/bin/php-cs-fixer fix src", + "phpcs": "@php vendor/bin/php-cs-fixer fix src --dry-run --diff", + "phpstan": "@php vendor/bin/phpstan analyse --debug", "pint:fix": "@php vendor/bin/pint", - "psalm": "@php vendor/bin/psalm", + "pint": "@php vendor/bin/pint --test", "psalm:fix": "@php vendor/bin/psalter --issues=all", - "rector": "@php vendor/bin/rector process src --dry-run", + "psalm": "@php vendor/bin/psalm --no-cache", "rector:fix": "@php vendor/bin/rector process src", + "rector": "@php vendor/bin/rector process src --dry-run", + "test:coverage": "@php vendor/bin/pest --order-by random --coverage", "test": "@php vendor/bin/pest --order-by random" } } diff --git a/config/auth0.php b/config/auth0.php index d9db2ffd..bc6cd129 100644 --- a/config/auth0.php +++ b/config/auth0.php @@ -2,57 +2,60 @@ declare(strict_types=1); -/** +use Auth0\Laravel\Configuration; +use Auth0\SDK\Configuration\SdkConfiguration; + +/* * Please review available configuration options here: * https://github.com/auth0/auth0-PHP#configuration-options. */ return [ // Should be assigned either 'api', 'management', or 'webapp' to indicate your application's use case for the SDK. // Determines what configuration options will be required. - 'strategy' => env('AUTH0_STRATEGY', \Auth0\SDK\Configuration\SdkConfiguration::STRATEGY_REGULAR), + 'strategy' => env('AUTH0_STRATEGY', SdkConfiguration::STRATEGY_REGULAR), // Auth0 domain for your tenant, found in your Auth0 Application settings. - 'domain' => env('AUTH0_DOMAIN'), + 'domain' => env('AUTH0_DOMAIN'), // If you have configured Auth0 to use a custom domain, configure it here. - 'customDomain' => env('AUTH0_CUSTOM_DOMAIN'), + 'customDomain' => env('AUTH0_CUSTOM_DOMAIN'), // Client ID, found in the Auth0 Application settings. - 'clientId' => env('AUTH0_CLIENT_ID'), + 'clientId' => env('AUTH0_CLIENT_ID'), // Authentication callback URI, as defined in your Auth0 Application settings. - 'redirectUri' => env('AUTH0_REDIRECT_URI', env('APP_URL') . '/callback'), + 'redirectUri' => env('AUTH0_REDIRECT_URI', env('APP_URL') . '/callback'), // Client Secret, found in the Auth0 Application settings. - 'clientSecret' => env('AUTH0_CLIENT_SECRET'), + 'clientSecret' => env('AUTH0_CLIENT_SECRET'), // One or more API identifiers, found in your Auth0 API settings. The SDK uses the first value for building links. If provided, at least one of these values must match the 'aud' claim to validate an ID Token successfully. - 'audience' => \Auth0\Laravel\Configuration::stringToArrayOrNull(env('AUTH0_AUDIENCE')), + 'audience' => Configuration::stringToArrayOrNull(env('AUTH0_AUDIENCE')), // One or more scopes to request for Tokens. See https://auth0.com/docs/scopes - 'scope' => \Auth0\Laravel\Configuration::stringToArray(env('AUTH0_SCOPE')), + 'scope' => Configuration::stringToArray(env('AUTH0_SCOPE')), // One or more Organization IDs, found in your Auth0 Organization settings. The SDK uses the first value for building links. If provided, at least one of these values must match the 'org_id' claim to validate an ID Token successfully. - 'organization' => \Auth0\Laravel\Configuration::stringToArrayOrNull(env('AUTH0_ORGANIZATION')), + 'organization' => Configuration::stringToArrayOrNull(env('AUTH0_ORGANIZATION')), // The secret used to derive an encryption key for the user identity in a session cookie and to sign the transient cookies used by the login callback. - 'cookieSecret' => env('AUTH0_COOKIE_SECRET', env('APP_KEY')), + 'cookieSecret' => env('AUTH0_COOKIE_SECRET', env('APP_KEY')), // How long, in seconds, before cookies expire. If set to 0 the cookie will expire at the end of the session (when the browser closes). 'cookieExpires' => (int) env('AUTH0_COOKIE_EXPIRES', 0), // Cookie domain, for example 'www.example.com', for use with PHP sessions and SDK cookies. Defaults to value of HTTP_HOST server environment information. // Note: To make cookies visible on all subdomains then the domain must be prefixed with a dot like '.example.com'. - 'cookieDomain' => env('AUTH0_COOKIE_DOMAIN'), + 'cookieDomain' => env('AUTH0_COOKIE_DOMAIN'), // Specifies path on the domain where the cookies will work. Defaults to '/'. Use a single slash ('/') for all paths on the domain. - 'cookiePath' => env('AUTH0_COOKIE_PATH', '/'), + 'cookiePath' => env('AUTH0_COOKIE_PATH', '/'), // Defaults to false. Specifies whether cookies should ONLY be sent over secure connections. - 'cookieSecure' => \Auth0\Laravel\Configuration::stringToBoolOrNull(env('AUTH0_COOKIE_SECURE'), false), + 'cookieSecure' => Configuration::stringToBoolOrNull(env('AUTH0_COOKIE_SECURE'), false), // Named routes within your Laravel application that the SDK may call during stateful requests for redirections. - 'routes' => [ + 'routes' => [ 'home' => env('AUTH0_ROUTE_HOME', '/'), 'login' => env('AUTH0_ROUTE_LOGIN', 'login'), ], diff --git a/infection.json5.dist b/infection.json5.dist new file mode 100644 index 00000000..ac2a7eeb --- /dev/null +++ b/infection.json5.dist @@ -0,0 +1,11 @@ +{ + source: { + directories: ["src"], + }, + logs: { + "text": "infection.log" + }, + mutators: { + "@default": true, + } +} diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 54b1acc7..cc6df64a 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,6 +1,6 @@ includes: - - vendor/phpstan/phpstan-strict-rules/rules.neon - - vendor/nunomaduro/larastan/extension.neon + - ./vendor/phpstan/phpstan-strict-rules/rules.neon + - ./vendor/nunomaduro/larastan/extension.neon parameters: level: max @@ -13,8 +13,6 @@ parameters: ignoreErrors: - '#Method (.*) has parameter (.*) with no value type specified in iterable type array.#' - - '#Cannot call method (.*) on mixed#' - '#no value type specified in iterable type array.#' - - '#Call to an undefined method Illuminate\\(.*).#' reportUnmatchedIgnoredErrors: false diff --git a/phpunit.xml.dist b/phpunit.xml.dist index ba93708e..85e566e1 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,18 +1,25 @@ - - - - ./src/ - - - - - tests/Unit - - - - - - - + + + + ./src/ + + + + ./src/Event/ + ./src/Contract/ + ./src/Exception/ + + + + + + + + + + + tests/Unit + + diff --git a/pint.json b/pint.json deleted file mode 100644 index 2bf69b74..00000000 --- a/pint.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "preset": "psr12", - "exclude": ["tests"] -} diff --git a/psalm.xml.dist b/psalm.xml.dist index e469154a..19efe4a1 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -5,6 +5,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config%20vendor/vimeo/psalm/config.xsd" + findUnusedBaselineEntry="true" + findUnusedCode="false" > @@ -13,14 +15,12 @@ - - - + diff --git a/rector.php b/rector.php index 4cbf85c5..3c49b81a 100644 --- a/rector.php +++ b/rector.php @@ -2,21 +2,29 @@ declare(strict_types=1); +use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector; use Rector\Config\RectorConfig; -use Rector\Core\ValueObject\PhpVersion; -use Rector\Php74\Rector\Property\TypedPropertyRector; use Rector\Set\ValueObject\SetList; return static function (RectorConfig $rectorConfig): void { - $rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/tests']); + $rectorConfig->paths([ + __DIR__ . '/config', + __DIR__ . '/src', + ]); + + // register a single rule + $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class); + // define sets of rules $rectorConfig->sets([ SetList::CODE_QUALITY, + SetList::PHP_80, + SetList::ACTION_INJECTION_TO_CONSTRUCTOR_INJECTION, + SetList::DEAD_CODE, + SetList::NAMING, + SetList::PRIVATIZATION, + SetList::PSR_4, + SetList::TYPE_DECLARATION, + SetList::EARLY_RETURN, ]); - - $rectorConfig->rule(TypedPropertyRector::class); - - $rectorConfig->phpVersion(PhpVersion::PHP_80); - - $rectorConfig->phpstanConfig(__DIR__ . '/phpstan.neon.dist'); }; diff --git a/tests/Pest.php b/tests/Pest.php index 06296a49..a9be220f 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,39 +1,68 @@ - beforeEach(function (): void { - $this->service = createService(); - }, )-> - in(__DIR__); - -function createServiceConfiguration( - array $configuration = [], -): Auth0\SDK\Configuration\SdkConfiguration { - $defaults = [ - 'strategy' => 'none', - ]; - - return new \Auth0\SDK\Configuration\SdkConfiguration(array_merge($defaults, $configuration)); -} - -function createService( - ?Auth0\SDK\Configuration\SdkConfiguration $configuration = null, -): Auth0\Laravel\Auth0 { - if (null === $configuration) { - $configuration = createServiceConfiguration(); - } +use Illuminate\Support\Facades\Event; +use Illuminate\Support\Facades\Artisan; + +// Flag to indicate that we are running tests. +define('AUTH0_LARAVEL_SDK_TESTS_RUNNING', true); + +/* +|-------------------------------------------------------------------------- +| Test Case +|-------------------------------------------------------------------------- +| +| The closure you provide to your test functions is always bound to a specific PHPUnit test +| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may +| need to change it using the "uses()" function to bind a different classes or traits. +| +*/ - return (new \Auth0\Laravel\Auth0())->setConfiguration($configuration); -} +uses(\Auth0\Laravel\Tests\TestCase::class)->in(__DIR__); -function createSdk( - ?Auth0\SDK\Configuration\SdkConfiguration $configuration = null, -): Auth0\SDK\Auth0 { - if (null === $configuration) { - $configuration = createServiceConfiguration(); +uses()->afterEach(function (): void { + $commands = ['optimize:clear']; + + foreach ($commands as $command) { + Artisan::call($command); } +})->in(__DIR__); + +uses()->beforeEach(function (): void { + $this->events = []; + + Event::listen('*', function ($event) { + $this->events[] = $event; + }); +})->in(__DIR__); + +/* +|-------------------------------------------------------------------------- +| Expectations +|-------------------------------------------------------------------------- +| +| When you're writing tests, you often need to check that values meet certain conditions. The +| "expect()" function gives you access to a set of "expectations" methods that you can use +| to assert different things. Of course, you may extend the Expectation API at any time. +| +*/ + +// expect()->extend('toBeOne', function () { +// return $this->toBe(1); +// }); + +/* +|-------------------------------------------------------------------------- +| Functions +|-------------------------------------------------------------------------- +| +| While Pest is very powerful out-of-the-box, you may have some testing code specific to your +| project that you don't want to repeat in every file. Here you can also expose helpers as +| global functions to help you to reduce the number of lines of code in your test files. +| +*/ + +// function something() +// { +// // .. +// } - return new \Auth0\SDK\Auth0($configuration); -} diff --git a/tests/TestCase.php b/tests/TestCase.php index 7df2ef4a..6fbae36d 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -4,24 +4,106 @@ namespace Auth0\Laravel\Tests; -use Orchestra\Testbench\TestCase as Orchestra; +use Orchestra\Testbench\TestCase as BaseTestCase; +use Auth0\Laravel\ServiceProvider; -class TestCase extends Orchestra +class TestCase extends BaseTestCase { - protected function setUp(): void + protected $enablesPackageDiscoveries = true; + protected $events = []; + + protected function getPackageProviders($app) { - parent::setUp(); + return [ + ServiceProvider::class, + ]; } - public function refreshServiceProvider(): void + protected function getEnvironmentSetUp($app): void { - (new \Auth0\Laravel\ServiceProvider($this->app))->packageBooted(); + $app['config']->set('auth', [ + 'defaults' => [ + 'guard' => 'testGuard', + 'passwords' => 'users', + ], + 'guards' => [ + 'web' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + 'testGuard' => [ + 'driver' => 'auth0.guard', + 'provider' => 'testProvider', + ], + ], + 'providers' => [ + 'users' => [ + 'driver' => 'eloquent', + 'model' => App\Models\User::class, + ], + 'testProvider' => [ + 'driver' => 'auth0.provider', + 'model' => 'auth0.repository', + ], + ], + ]); + + // Default to no strategy for testing + $app['config']->set('auth0.strategy', 'none'); + + // Set a random key for testing + $app['config']->set('app.key', 'base64:' . base64_encode(random_bytes(32))); + + // Setup database for testing (currently unused) + $app['config']->set('database.default', 'testbench'); + $app['config']->set('database.connections.testbench', [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '', + ]); } - protected function getPackageProviders($app) + /** + * Asserts that an event was dispatched. Optionally assert the number of times it was dispatched and/or that it was dispatched after another event. + * + * @param string $expectedEvent The event to assert was dispatched. + * @param int $times The number of times the event was expected to be dispatched. + * @param string|null $followingEvent The event that was expected to be dispatched before this event. + */ + protected function assertDispatched(string $expectedEvent, int $times = 0, ?string $followingEvent = null) { - return [ - \Auth0\Laravel\ServiceProvider::class, - ]; + $this->assertTrue(\in_array($expectedEvent, $this->events), 'Event ' . $expectedEvent . ' was not dispatched.'); + + if ($times > 0) { + $this->assertTrue(array_count_values($this->events)[$expectedEvent] === $times, 'Event ' . $expectedEvent . ' was not dispatched ' . $times . ' times.'); + } + + if (null !== $followingEvent) { + $this->assertTrue(\in_array($followingEvent, $this->events)); + + $indexExpected = array_search($expectedEvent, $this->events); + $indexFollowing = array_search($followingEvent, $this->events); + + if ($indexExpected !== false && $indexFollowing !== false) { + $this->assertTrue($indexExpected > $indexFollowing, 'Event ' . $expectedEvent . ' was not dispatched after ' . $followingEvent . '.'); + } + } + } + + /** + * Asserts that events were dispatched in the order provided. Events not in the array are ignored. + * + * @param array $events Array of events to assert were dispatched in order. + */ + protected function assertDispatchedOrdered(array $events) + { + $previousIndex = -1; + + foreach ($events as $event) { + $index = array_search($event, $this->events); + $this->assertTrue($index !== false); + $this->assertTrue($index > $previousIndex); + $previousIndex = $index; + } } } diff --git a/tests/Unit/Auth/GuardStatefulTest.php b/tests/Unit/Auth/GuardStatefulTest.php new file mode 100644 index 00000000..f65bfa59 --- /dev/null +++ b/tests/Unit/Auth/GuardStatefulTest.php @@ -0,0 +1,258 @@ +group('auth', 'auth.guard', 'auth.guard.stateful'); + +beforeEach(function (): void { + $this->laravel = app('auth0'); + $this->guard = $guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + $this->session = $this->config->getSessionStorage(); + $this->transient = $this->config->getTransientStorage(); + $this->user = new User(['sub' => uniqid('auth0|')]); + + $this->secret = uniqid(); + + $this->config->setDomain('my-domain.auth0.com'); + $this->config->setClientId('my_client_id'); + $this->config->setClientSecret($this->secret); + $this->config->setCookieSecret('my_cookie_secret'); + $this->config->setStrategy(SdkConfiguration::STRATEGY_REGULAR); + + $this->session->set('user', ['sub' => 'hello|world']); + $this->session->set('idToken', uniqid()); + $this->session->set('accessToken', uniqid()); + $this->session->set('accessTokenScope', [uniqid()]); + $this->session->set('accessTokenExpiration', time() + 60); + + $this->route = '/' . uniqid(); + + Route::get($this->route, function () use ($guard) { + $credential = $guard->find(Guard::SOURCE_SESSION); + + if (null !== $credential) { + $guard->login($credential, Guard::SOURCE_SESSION); + return response()->json(['status' => 'OK']); + } + + abort(Response::HTTP_UNAUTHORIZED, 'Unauthorized'); + }); +}); + +it('gets a user from a valid session', function (): void { + getJson($this->route) + ->assertStatus(Response::HTTP_OK); + + expect($this->guard) + ->user()->getAuthIdentifier()->toBe('hello|world'); +}); + +it('updates internal and session states as appropriate', function (): void { + // Session should be available and populated + expect($this->session) + ->getAll()->not()->toBe([]); + + // Guard should pick up on the session during the HTTP request + getJson($this->route) + ->assertStatus(Response::HTTP_OK); + + // Guard should have it's state populated + expect($this->guard) + ->user()->getAuthIdentifier()->toBe('hello|world'); + + // Empty guard state + $this->guard->logout(); + + // Guard should have had it's state emptied + expect($this->guard) + ->user()->toBeNull(); + + // Session should have been emptied + expect($this->session) + ->getAll()->toBe([]); + + // HTTP request should fail without a session. + getJson($this->route) + ->assertStatus(Response::HTTP_UNAUTHORIZED); + + // Inject a new session into the store + $this->session->set('user', ['sub' => 'hello|world|two']); + + // Session should be available and populated again + expect($this->session) + ->getAll()->not()->toBe([]); + + getJson($this->route) + ->assertStatus(Response::HTTP_OK); + + // Guard should pick up on the session + expect($this->guard) + ->user()->getAuthIdentifier()->toBe('hello|world|two'); + + // Directly wipe the Laravel session, circumventing the Guard APIs + $this->session->purge(); + + // Session should be empty + expect($this->session) + ->getAll()->toBe([]); + + getJson($this->route) + ->assertStatus(Response::HTTP_UNAUTHORIZED); + + // Guard should have it's state emptied + expect($this->guard) + ->user()->toBeNull(); + + $this->session->set('user', ['sub' => 'hello|world|4']); + + // Session should be available + expect($this->session) + ->getAll()->not()->toBe([]); + + getJson($this->route) + ->assertStatus(Response::HTTP_OK); + + // Guard should pick up on the session + expect($this->guard) + ->user()->getAuthIdentifier()->toBe('hello|world|4'); + + $identifier = uniqid('auth0|'); + $user = new User(['sub' => $identifier]); + + // Overwrite state using the Guard's login() + $this->guard->login(Credential::create( + user: $user + ), Guard::SOURCE_SESSION); + + getJson($this->route) + ->assertStatus(Response::HTTP_OK); + + // Guard should have it's state updated + expect($this->guard) + ->user()->getAuthIdentifier()->toBe($identifier); + + // Session should be updated + expect($this->session) + ->get('user')->toBe(['sub' => $identifier]); +}); + +it('creates a session from login()', function (): void { + $identifier = uniqid('auth0|'); + $idToken = uniqid('id-token-'); + $accessToken = uniqid('access-token-'); + $accessTokenScope = [uniqid('access-token-scope-')]; + $accessTokenExpiration = time() + 60; + + $this->session->set('user', ['sub' => $identifier]); + $this->session->set('idToken', $idToken); + $this->session->set('accessToken', $accessToken); + $this->session->set('accessTokenScope', $accessTokenScope); + $this->session->set('accessTokenExpiration', $accessTokenExpiration); + + $found = $this->guard->find(Guard::SOURCE_SESSION); + + expect($found) + ->toBeInstanceOf(Credential::class); + + $this->guard->login($found, Guard::SOURCE_SESSION); + + expect($this->session) + ->get('user')->toBe(['sub' => $identifier]) + ->get('idToken')->toBe($idToken) + ->get('accessToken')->toBe($accessToken) + ->get('accessTokenScope')->toBe($accessTokenScope) + ->get('accessTokenExpiration')->toBe($accessTokenExpiration) + ->get('refreshToken')->toBeNull(); + + $user = new User(['sub' => $identifier]); + + $changedIdToken = uniqid('CHANGED-id-token-'); + $changedRefreshToken = uniqid('CHANGED-refresh-token-'); + + // Overwrite state using the Guard's login() + $this->guard->login(Credential::create( + user: $user, + idToken: $changedIdToken, + refreshToken: $changedRefreshToken + ), Guard::SOURCE_SESSION); + + expect($this->guard) + ->user()->getAuthIdentifier()->toBe($identifier); + + expect($this->session) + ->get('user')->toBe(['sub' => $identifier]) + ->get('idToken')->toBe($changedIdToken) + ->get('accessToken')->toBe($accessToken) + ->get('accessTokenScope')->toBe($accessTokenScope) + ->get('accessTokenExpiration')->toBe($accessTokenExpiration) + ->get('refreshToken')->toBe($changedRefreshToken); +}); + +it('immediately invalidates an expired session when a refresh token is not available', function (): void { + $this->session->set('accessTokenExpiration', time() - 1000); + + $found = $this->guard->find(Guard::SOURCE_SESSION); + $this->guard->login($found, Guard::SOURCE_SESSION); + + expect($this->guard) + ->user()->toBeNull(); + + expect($this->session) + ->get('user')->toBeNull(); +}); + +it('invalidates an expired session when an access token fails to refresh', function (): void { + $this->session->set('accessTokenExpiration', time() - 1000); + $this->session->set('refreshToken', uniqid()); + + $found = $this->guard->find(Guard::SOURCE_SESSION); + $this->guard->login($found, Guard::SOURCE_SESSION); + + expect($this->guard) + ->user()->toBeNull(); + + expect($this->session) + ->get('user')->toBeNull(); +}); + +it('successfully continues a session when an access token succeeds is renewed', function (): void { + $this->session->set('accessTokenExpiration', time() - 1000); + $this->session->set('refreshToken', uniqid()); + + $http = $this->config->getHttpClient(); + $streamFactory = $this->config->getHttpStreamFactory(); + $responseFactory = $this->config->getHttpResponseFactory(); + + $http->queueResponse( + $responseFactory::create( + body: $streamFactory->createStream( + json_encode([ + 'access_token' => uniqid(), + 'expires_in' => 60, + 'scope' => 'openid profile', + 'token_type' => 'Bearer', + ], JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR) + ) + ) + ); + + $found = $this->guard->find(Guard::SOURCE_SESSION); + $this->guard->login($found, Guard::SOURCE_SESSION); + + expect($this->guard) + ->user()->not()->toBeNull(); + + expect($this->session) + ->get('user')->not()->toBeNull(); +}); diff --git a/tests/Unit/Auth/GuardStatelessTest.php b/tests/Unit/Auth/GuardStatelessTest.php new file mode 100644 index 00000000..bb17764f --- /dev/null +++ b/tests/Unit/Auth/GuardStatelessTest.php @@ -0,0 +1,117 @@ +group('auth', 'auth.guard', 'auth.guard.stateless'); + +beforeEach(function (): void { + $this->laravel = app('auth0'); + $this->guard = $guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + + $this->secret = uniqid(); + + $this->config->setDomain('my-domain.auth0.com'); + $this->config->setClientSecret($this->secret); + $this->config->setAudience(['https://example.com/health-api']); + $this->config->setTokenAlgorithm(Token::ALGO_HS256); + $this->config->setStrategy(SdkConfiguration::STRATEGY_API); + + $this->token = Generator::create($this->secret, Token::ALGO_HS256, [ + "iss" => "https://my-domain.auth0.com/", + "sub" => "auth0|123456", + "aud" => [ + "https://example.com/health-api", + "https://my-domain.auth0.com/userinfo" + ], + "azp" => "my_client_id", + "exp" => time() + 60, + "iat" => time(), + "scope" => "openid profile read:patients read:admin" + ]); + $this->bearerToken = ['Authorization' => 'Bearer ' . $this->token->toString()]; + + $this->route = '/' . uniqid(); + Route::get($this->route, function () use ($guard) { + $credential = $guard->find(Guard::SOURCE_TOKEN); + + if (null !== $credential) { + $guard->login($credential, Guard::SOURCE_TOKEN); + return response()->json(['status' => 'OK']); + } + + abort(Response::HTTP_UNAUTHORIZED, 'Unauthorized'); + }); +}); + +it('assigns a user from a good token', function (): void { + expect($this->guard) + ->user()->toBeNull(); + + getJson($this->route, $this->bearerToken) + ->assertStatus(Response::HTTP_OK); + + expect($this->guard) + ->user()->not()->toBeNull(); +}); + +it('does not assign a user from a empty token', function (): void { + getJson($this->route, ['Authorization' => 'Bearer ']) + ->assertStatus(Response::HTTP_UNAUTHORIZED); + + expect($this->guard) + ->user()->toBeNull(); +}); + +it('does not accept a user when a repository returns null from a token lookup', function (): void { + $repo = mock(Repository::class)->expect( + fromAccessToken: fn (array $user) => null + ); + + app()->singleton('auth0.repository', fn () => $repo); + + getJson($this->route, $this->bearerToken) + ->assertStatus(Response::HTTP_UNAUTHORIZED); + + expect($this->guard) + ->user()->toBeNull(); +}); + +it('does not accept a user when a repository returns an invalid user class from a token lookup', function (): void { + $repo = mock(Repository::class)->expect( + fromAccessToken: fn (array $user) => new User([]) + ); + + app()->singleton('auth0.repository', fn () => $repo); + + getJson($this->route, $this->bearerToken) + ->assertStatus(Response::HTTP_UNAUTHORIZED); + + expect($this->guard) + ->user()->toBeNull(); +}); + +it('does not get a user from a bad token', function (): void { + $this->config->setAudience(['BAD_AUDIENCE']); + + expect($this->guard) + ->user()->toBeNull(); + + getJson($this->route, $this->bearerToken) + ->assertStatus(Response::HTTP_UNAUTHORIZED); + + expect($this->guard) + ->user()->toBeNull(); +}); diff --git a/tests/Unit/Auth/GuardTest.php b/tests/Unit/Auth/GuardTest.php index 174d7fd7..7da631a4 100644 --- a/tests/Unit/Auth/GuardTest.php +++ b/tests/Unit/Auth/GuardTest.php @@ -1,3 +1,190 @@ group('auth', 'auth.guard', 'auth.guard.shared'); + +beforeEach(function (): void { + $this->guard = auth('testGuard'); + $this->user = new User(['sub' => uniqid('auth0|')]); + + Route::middleware('auth:auth0')->get('/test', function () { + return 'OK'; + }); +}); + +it('returns its configured name', function (): void { + expect($this->guard) + ->toBeInstanceOf(Guard::class) + ->getName()->toBe('testGuard'); +}); + +it('assigns a user at login', function (): void { + expect($this->guard) + ->toBeInstanceOf(Guard::class) + ->user()->toBeNull(); + + $this->guard->login(Credential::create( + user: $this->user + )); + + expect($this->guard) + ->user()->toBe($this->user); + + expect($this->guard) + ->id()->toBe($this->user->getAuthIdentifier()); +}); + +it('logs out a user', function (): void { + expect($this->guard) + ->toBeInstanceOf(Guard::class) + ->user()->toBeNull(); + + $this->guard->login(Credential::create( + user: $this->user + )); + + expect($this->guard) + ->user()->toBe($this->user); + + $this->guard->logout(); + + expect($this->guard) + ->user()->toBeNull(); + + expect($this->guard) + ->id()->toBeNull(); +}); + +it('checks if a user is logged in', function (): void { + expect($this->guard) + ->check()->toBeFalse(); + + $this->guard->login(Credential::create( + user: $this->user + )); + + expect($this->guard) + ->check()->toBeTrue(); +}); + +it('checks if a user is a guest', function (): void { + expect($this->guard) + ->guest()->toBeTrue(); + + $this->guard->login(Credential::create( + user: $this->user + )); + + expect($this->guard) + ->guest()->toBeFalse(); +}); + +it('gets the user identifier', function (): void { + $this->guard->login(Credential::create( + user: $this->user + )); + + expect($this->guard) + ->id()->toBe($this->user->getAuthIdentifier()); +}); + +it('validates a user', function (): void { + $this->guard->login(Credential::create( + user: $this->user + )); + + expect($this->guard) + ->validate(['id' => '123'])->toBeFalse() + ->validate(['id' => '456'])->toBeFalse(); +}); + +it('gets/sets a user', function (): void { + $this->guard->setUser($this->user); + + expect($this->guard) + ->user()->toBe($this->user); +}); + +it('has a user', function (): void { + $this->guard->setUser($this->user); + + expect($this->guard) + ->hasUser()->toBeTrue(); + + $this->guard->logout(); + + expect($this->guard) + ->hasUser()->toBeFalse(); +}); + +it('has a scope', function (): void { + $this->user = new User(['sub' => uniqid('auth0|'), 'scope' => 'read:users 456']); + + $credential = Credential::create( + user: $this->user, + accessTokenScope: ['read:users', '456'] + ); + + expect($this->guard) + ->hasScope('read:users', $credential)->toBeTrue() + ->hasScope('123', $credential)->toBeFalse() + ->hasScope('456', $credential)->toBeTrue() + ->hasScope('789', $credential)->toBeFalse() + ->hasScope('*', $credential)->toBeTrue(); + + $credential = Credential::create( + user: $this->user + ); + + expect($this->guard) + ->hasScope('read:users', $credential)->toBeFalse() + ->hasScope('*', $credential)->toBeTrue(); +}); + +it('checks if a user was authenticated via remember', function (): void { + $this->guard->login(Credential::create( + user: $this->user + )); + + expect($this->guard) + ->viaRemember()->toBeFalse(); +}); + +it('returns null if authenticate() is called without being authenticated', function (): void { + $response = $this->guard->authenticate(); + expect($response)->toBeNull(); +})->throws(AuthenticationException::class, AuthenticationExceptionContract::UNAUTHENTICATED); + +it('returns a user from authenticate() if called while authenticated', function (): void { + $this->guard->login(Credential::create( + user: $this->user + )); + + $response = $this->guard->authenticate(); + + expect($response) + ->toBe($this->user); +}); + +it('gets/sets a credentials', function (): void { + $credential = Credential::create( + user: $this->user, + idToken: uniqid(), + accessToken: uniqid(), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600 + ); + + $this->guard->setCredential($credential); + + expect($this->guard) + ->user()->toBe($this->user); +}); diff --git a/tests/Unit/Auth/User/ProviderTest.php b/tests/Unit/Auth/User/ProviderTest.php new file mode 100644 index 00000000..ee771e1e --- /dev/null +++ b/tests/Unit/Auth/User/ProviderTest.php @@ -0,0 +1,88 @@ +group('auth', 'auth.user', 'auth.user.provider'); + +test('retrieveByToken() returns null when an incompatible guard token is used', function (): void { + config([ + 'auth.defaults.guard' => 'web', + 'auth.guards.testGuard' => null, + 'auth0.routes.home' => '/testing' + ]); + + $route = '/' . uniqid(); + + Route::get($route, function () { + $provider = app('auth0.provider'); + $credential = $provider->retrieveByToken('token', ''); + + if (null === $credential) { + return response()->json(['status' => 'OK']); + } + + abort(Response::HTTP_UNAUTHORIZED, 'Unauthorized'); + }); + + $this->getJson($route) + ->assertOK(); +}); + +test('retrieveByToken() returns null when an invalid token is provided', function (): void { + $provider = app('auth0.provider'); + + expect($provider->retrieveByToken('token', '')) + ->toBeNull(); + + expect($provider->retrieveByToken('token', [])) + ->toBeNull(); +}); + +test('validateCredentials() always returns false', function (): void { + $provider = app('auth0.provider'); + $user = new User(); + + expect($provider->validateCredentials($user, [])) + ->toBeFalse(); +}); + +test('getRepository() throws an error when an non-existent repository provider is set', function (): void { + $provider = new Provider(['model' => 'MISSING']); + $provider->getRepository(); +})->throws(BindingResolutionException::class); + +test('getRepository() throws an error when an invalid repository provider is set', function (): void { + $provider = new Provider(['model' => ['ARRAY']]); + $provider->getRepository(); +})->throws(BindingResolutionException::class); + +test('setRepository() sets the repository model', function (): void { + $provider = new Provider(['model' => uniqid()]); + $repository = new Repository(); + $provider->setRepository($repository::class); + + expect($provider->getRepository()) + ->toBeInstanceOf($repository::class); +}); + +test('setRepository() with the same repository identifier uses the cached repository instance', function (): void { + $provider = new Provider(['model' => 'MISSING']); + $repository = new Repository(); + + $provider->setRepository($repository::class); + + expect($provider->getRepository()) + ->toBeInstanceOf($repository::class); + + $provider->setRepository($repository::class); + + expect($provider->getRepository()) + ->toBeInstanceOf($repository::class); +}); diff --git a/tests/Unit/Auth/User/RepositoryTest.php b/tests/Unit/Auth/User/RepositoryTest.php new file mode 100644 index 00000000..6c2911a8 --- /dev/null +++ b/tests/Unit/Auth/User/RepositoryTest.php @@ -0,0 +1,24 @@ +group('auth', 'auth.user', 'auth.user.repository'); + +it('returns a stateful user model from session queries', function (): void { + $repository = $this->app['auth0.repository']; + + expect($repository->fromSession(['name' => 'Stateful'])) + ->toBeInstanceOf(StatefulUser::class) + ->name->toBe('Stateful'); +}); + +it('returns a stateless user model from access token queries', function (): void { + $repository = $this->app['auth0.repository']; + + expect($repository->fromAccessToken(['name' => 'Stateless'])) + ->toBeInstanceOf(StatelessUser::class) + ->name->toBe('Stateless'); +}); diff --git a/tests/Unit/Auth0Test.php b/tests/Unit/Auth0Test.php index 68dd5cd4..07842f27 100644 --- a/tests/Unit/Auth0Test.php +++ b/tests/Unit/Auth0Test.php @@ -2,53 +2,92 @@ declare(strict_types=1); -test('the service is created successfully', function (): void { - expect($this->service)-> - toBeInstanceOf(\Auth0\Laravel\Auth0::class); -}, ); - -test('the service instantiates it\'s own configuration if none is assigned', function (): void { - $service = new \Auth0\Laravel\Auth0(); - - expect($service->getConfiguration())-> - toBeInstanceOf(\Auth0\SDK\Configuration\SdkConfiguration::class); -}, ); - -test('the service\'s getSdk() method returns an Auth0 SDK instance', function (): void { - expect($this->service->getSdk())-> - toBeInstanceOf(\Auth0\SDK\Auth0::class); -}, ); - -test('the service\'s getConfiguration method returns an SdkConfiguration instance', function (): void { - expect($this->service->getConfiguration())-> - toBeInstanceOf(\Auth0\SDK\Configuration\SdkConfiguration::class); -}, ); - -test('the service\'s getState method returns a StateInstance instance', function (): void { - expect($this->service->getState())-> - toBeInstanceOf(\Auth0\Laravel\Contract\StateInstance::class); -}, ); - -test('the service\'s setSdk() method allows overwriting the Auth0 instance', function (): void { - $oldSdk = $this->service->getSdk(); - $newSdk = createSdk(); - - $this->service->setSdk($newSdk); - - expect($this->service->getSdk())-> - toBe($newSdk)-> - not()-> - toBe($oldSdk); -}, ); - -test('the service\'s setConfiguration() method allows overwriting the SdkConfiguration instance', function (): void { - $oldConfiguration = $this->service->getConfiguration(); - $newConfiguration = createServiceConfiguration(); - - $this->service->setConfiguration($newConfiguration); - - expect($this->service->getConfiguration())-> - toBe($newConfiguration)-> - not()-> - toBe($oldConfiguration); -}, ); +use Auth0\SDK\Contract\Auth0Interface as SdkContract; +use Auth0\Laravel\Auth0; +use Auth0\SDK\Auth0 as SDKAuth0; +use Auth0\SDK\Configuration\SdkConfiguration; + +uses()->group('auth0'); + +it('can get/set the configuration', function (): void { + $laravel = app('auth0'); + expect($laravel->getConfiguration())->toBeInstanceOf(SdkConfiguration::class); + + $configuration = new SdkConfiguration(['strategy' => 'none', 'domain' => uniqid() . '.auth0.test']); + $laravel->setConfiguration($configuration); + expect($laravel->getConfiguration())->toBe($configuration); + + $domain = uniqid() . '.auth0.test'; + $configuration->setDomain($domain); + expect($laravel->getConfiguration()->getDomain())->toBe($domain); + + $configuration = new SdkConfiguration(['strategy' => 'none', 'domain' => uniqid() . '.auth0.test']); + $laravel->setConfiguration($configuration); + expect($laravel->getConfiguration())->toBe($configuration); + + $sdk = $laravel->getSdk(); + $configuration = new SdkConfiguration(['strategy' => 'none', 'domain' => uniqid() . '.auth0.test']); + $laravel->setConfiguration($configuration); + expect($laravel->getConfiguration())->toBe($configuration); + expect($sdk->configuration())->toBe($configuration); +}); + +it('can get the sdk credentials', function (): void { + $laravel = app('auth0'); + + expect($laravel->getCredentials()) + ->toBeNull(); + + $sdk = $laravel->getSdk(); + $config = $sdk->configuration(); + $session = $config->getSessionStorage(); + + $config->setDomain('my-domain.auth0.com'); + $config->setClientId('my_client_id'); + $config->setClientSecret('my_client_secret'); + $config->setCookieSecret('my_cookie_secret'); + $config->setStrategy(SdkConfiguration::STRATEGY_REGULAR); + + $session->set('user', ['sub' => 'hello|world']); + $session->set('idToken', uniqid()); + $session->set('accessToken', uniqid()); + $session->set('accessTokenScope', [uniqid()]); + $session->set('accessTokenExpiration', time() - 1000); + + // As we manually set the session values, we need to refresh the SDK state to ensure it's in sync. + $sdk->refreshState(); + + expect($laravel->getCredentials()) + ->toBeObject() + ->toHaveProperty('accessToken', $session->get('accessToken')) + ->toHaveProperty('accessTokenScope', $session->get('accessTokenScope')) + ->toHaveProperty('accessTokenExpiration', $session->get('accessTokenExpiration')) + ->toHaveProperty('idToken', $session->get('idToken')) + ->toHaveProperty('user', $session->get('user')); +}); + +it('can get/set the SDK', function (): void { + $laravel = app('auth0'); + expect($laravel->getSdk())->toBeInstanceOf(SdkContract::class); + + $sdk = new SDKAuth0(['strategy' => 'none']); + $laravel->setSdk($sdk); + expect($laravel->getSdk())->toBeInstanceOf(SdkContract::class); +}); + +it('can reset the internal static state', function (): void { + $laravel = app('auth0'); + $cache = spl_object_id($laravel->getSdk()); + + unset($laravel); // Force the object to be destroyed. Static state will remain. + + $laravel = app('auth0'); + $updated = spl_object_id($laravel->getSdk()); + expect($cache)->toBe($updated); + + $laravel->reset(); // Reset the static state. + + $laravel = app('auth0'); + $updated = spl_object_id($laravel->getSdk()); + expect($cache)->not->toBe($updated); +}); diff --git a/tests/Unit/Cache/LaravelCacheItemTest.php b/tests/Unit/Cache/LaravelCacheItemTest.php new file mode 100644 index 00000000..7466d86b --- /dev/null +++ b/tests/Unit/Cache/LaravelCacheItemTest.php @@ -0,0 +1,100 @@ +group('cache', 'cache.laravel', 'cache.laravel.item'); + +test('getKey() returns an expected value', function (): void { + $cacheItem = new LaravelCacheItem('testing', 42, true); + + expect($cacheItem->getKey()) + ->toBe('testing'); +}); + +test('get() returns an expected value when hit', function (): void { + $cacheItem = new LaravelCacheItem('testing', 42, true); + + expect($cacheItem->get()) + ->toBe(42); +}); + +test('get() returns null when no hit', function (): void { + $cacheItem = new LaravelCacheItem('testing', 42, false); + + expect($cacheItem->get()) + ->toBeNull(); +}); + +test('getRawValue() returns an expected value', function (): void { + $cacheItem = new LaravelCacheItem('testing', 42, false); + + expect($cacheItem->getRawValue()) + ->toBe(42); +}); + +test('isHit() returns an expected value when hit', function (): void { + $cacheItem = new LaravelCacheItem('testing', 42, true); + + expect($cacheItem->isHit()) + ->toBeTrue(); + + $cacheItem = new LaravelCacheItem('testing', 42, false); + + expect($cacheItem->isHit()) + ->toBeFalse(); +}); + +test('set() alters the stored value as expected', function (): void { + $cacheItem = new LaravelCacheItem('testing', 42, true); + + expect($cacheItem->get()) + ->toBe(42); + + expect($cacheItem->set(43)) + ->toBe($cacheItem) + ->get()->toBe(43); +}); + +test('expiresAt() defaults to +1 year and accepts changes to its value', function (): void { + $cacheItem = new LaravelCacheItem('testing', 42, true); + + expect($cacheItem->getExpiration()) + ->toBeGreaterThan(new DateTime('now +1 year -1 minute')) + ->toBeLessThan(new DateTime('now +1 year +1 minute')); + + $cacheItem->expiresAt(new DateTime('now +1 day')); + + expect($cacheItem->getExpiration()) + ->toBeGreaterThan(new DateTime('now +1 day -1 minute')) + ->toBeLessThan(new DateTime('now +1 day +1 minute')); +}); + +test('expiresAfter() defaults to +1 year and accepts changes to its value', function (): void { + $cacheItem = new LaravelCacheItem('testing', 42, true); + + expect($cacheItem->getExpiration()) + ->toBeGreaterThan(new DateTime('now +1 year -1 minute')) + ->toBeLessThan(new DateTime('now +1 year +1 minute')); + + $cacheItem->expiresAfter(300); + + expect($cacheItem->getExpiration()) + ->toBeGreaterThan(new DateTime('now +250 seconds')) + ->toBeLessThan(new DateTime('now +350 seconds')); +}); + +test('miss() returns a configured instance', function (): void { + $cacheItem = new LaravelCacheItem('testing', 42, true); + $newCacheItem = $cacheItem->miss('testing123'); + + expect($cacheItem->getKey()) + ->toBe('testing'); + + expect($newCacheItem->getKey()) + ->toBe('testing123'); + + expect($newCacheItem->get()) + ->not()->toBe($cacheItem->get()); +}); diff --git a/tests/Unit/Cache/LaravelCachePoolTest.php b/tests/Unit/Cache/LaravelCachePoolTest.php new file mode 100644 index 00000000..07a49838 --- /dev/null +++ b/tests/Unit/Cache/LaravelCachePoolTest.php @@ -0,0 +1,257 @@ +group('cache', 'cache.laravel', 'cache.laravel.pool'); + +test('getItem(), hasItem() and save() behave as expected', function (): void { + $pool = new LaravelCachePool(); + $cache = $pool->getItem('testing'); + + expect($pool) + ->hasItem('testing')->toBeFalse(); + + expect($cache) + ->toBeInstanceOf(LaravelCacheItem::class) + ->get()->toBeNull() + ->isHit()->toBeFalse(); + + $cache->set(42); + + expect($cache) + ->get()->toBeNull(); + + expect($pool) + ->save($cache)->toBeTrue(); + + expect($pool) + ->hasItem('testing')->toBeTrue(); + + $cache = $pool->getItem('testing'); + + expect($cache) + ->toBeInstanceOf(LaravelCacheItem::class) + ->isHit()->toBeTrue() + ->get()->toBeNull() + ->set(42) + ->get()->toBe(42); + + $results = $pool->getItems(); + + expect($results) + ->toBeArray() + ->toHaveCount(0); + + $results = $pool->getItems(['testing' => uniqid()]); + + expect($results['testing']) + ->toBeInstanceOf(LaravelCacheItem::class) + ->isHit()->toBeTrue() + ->get()->not()->toBe(42); + + $this->app[\Illuminate\Cache\CacheManager::class] + ->getStore() + ->put('testing', false, 60); + + $cache = $pool->getItem('testing'); + + expect($pool) + ->hasItem('testing')->toBeFalse(); + + expect($cache) + ->toBeInstanceOf(LaravelCacheItem::class) + ->get()->toBeNull() + ->isHit()->toBeFalse(); + + $cacheMock = $this->mock(CacheItemInterface::class); + + expect($pool) + ->save($cacheMock)->toBeFalse(); +}); + +test('save() with a negative expiration value is deleted', function (): void { + $pool = new LaravelCachePool(); + $cache = new LaravelCacheItem('testing', 42, true, new DateTime('now - 1 year')); + + expect($pool)->hasItem('testing')->toBeFalse(); + + $pool->save($cache); + + expect($pool)->hasItem('testing')->toBeFalse(); +}); + +test('saveDeferred() behaves as expected', function (): void { + $pool = new LaravelCachePool(); + $cache = new LaravelCacheItem('testing', 42, true, new DateTime('now + 1 hour')); + + expect($pool) + ->hasItem('testing')->toBeFalse() + ->saveDeferred($cache)->toBeTrue() + ->hasItem('testing')->toBeFalse() + ->commit()->toBeTrue() + ->hasItem('testing')->toBeTrue(); +}); + +test('save() with a false value is discarded', function (): void { + $pool = new LaravelCachePool(); + $cache = new LaravelCacheItem('testing', false, true, new DateTime('now + 1 hour')); + + expect($pool) + ->hasItem('testing')->toBeFalse() + ->save($cache)->toBeTrue() + ->hasItem('testing')->toBeFalse(); +}); + +test('saveDeferred() returns false when the wrong type of interface is saved', function (): void { + $pool = new LaravelCachePool(); + $cache = new LaravelCacheItem('testing', 42, true, new DateTime('now + 1 hour')); + + $cache = new class implements CacheItemInterface { + public function getKey(): string + { + return 'testing'; + } + + public function get(): mixed + { + return 42; + } + + public function isHit(): bool + { + return true; + } + + public function set(mixed $value): static + { + return $this; + } + + public function expiresAt($expiration): static + { + return $this; + } + + public function expiresAfter($time): static + { + return $this; + } + }; + + expect($pool) + ->hasItem('testing')->toBeFalse() + ->saveDeferred($cache)->toBeFalse() + ->hasItem('testing')->toBeFalse(); +}); + +test('deleteItem() behaves as expected', function (): void { + $pool = new LaravelCachePool(); + $cache = new LaravelCacheItem('testing', 42, true, new DateTime('now + 1 minute')); + + expect($pool)->hasItem('testing')->toBeFalse(); + + $pool->save($cache); + + expect($pool)->hasItem('testing')->toBeTrue(); + + $cache = $pool->getItem('testing'); + + expect($cache) + ->isHit()->toBeTrue() + ->get()->toBe(42); + + $pool->deleteItem('testing'); + + expect($pool) + ->hasItem('testing')->toBeFalse(); + + $cache = $pool->getItem('testing'); + + expect($cache) + ->isHit()->toBeFalse() + ->get()->toBeNull(); +}); + +test('deleteItems() behaves as expected', function (): void { + $pool = new LaravelCachePool(); + + expect($pool) + ->hasItem('testing1')->toBeFalse() + ->hasItem('testing2')->toBeFalse() + ->hasItem('testing3')->toBeFalse(); + + $cache = new LaravelCacheItem('testing1', uniqid(), true, new DateTime('now + 1 minute')); + $pool->save($cache); + + $cache = new LaravelCacheItem('testing2', uniqid(), true, new DateTime('now + 1 minute')); + $pool->save($cache); + + $cache = new LaravelCacheItem('testing3', uniqid(), true, new DateTime('now + 1 minute')); + $pool->save($cache); + + expect($pool) + ->hasItem('testing1')->toBeTrue() + ->hasItem('testing2')->toBeTrue() + ->hasItem('testing3')->toBeTrue(); + + $results = $pool->getItems(['testing1' => 1, 'testing2' => 2, 'testing3' => 3]); + + expect($results) + ->toHaveKey('testing1') + ->toHaveKey('testing2') + ->toHaveKey('testing3') + ->testing1->isHit()->toBeTrue() + ->testing2->isHit()->toBeTrue() + ->testing3->isHit()->toBeTrue(); + + expect($pool) + ->deleteItems(['testing1', 'testing2', 'testing3'])->toBeTrue() + ->hasItem('testing1')->toBeFalse() + ->hasItem('testing2')->toBeFalse() + ->hasItem('testing3')->toBeFalse() + ->deleteItems(['testing4', 'testing5', 'testing6'])->toBeFalse(); +}); + +test('clear() behaves as expected', function (): void { + $pool = new LaravelCachePool(); + + expect($pool) + ->hasItem('testing1')->toBeFalse() + ->hasItem('testing2')->toBeFalse() + ->hasItem('testing3')->toBeFalse(); + + $cache = new LaravelCacheItem('testing1', uniqid(), true, new DateTime('now + 1 minute')); + $pool->save($cache); + + $cache = new LaravelCacheItem('testing2', uniqid(), true, new DateTime('now + 1 minute')); + $pool->save($cache); + + $cache = new LaravelCacheItem('testing3', uniqid(), true, new DateTime('now + 1 minute')); + $pool->save($cache); + + expect($pool) + ->hasItem('testing1')->toBeTrue() + ->hasItem('testing2')->toBeTrue() + ->hasItem('testing3')->toBeTrue(); + + $results = $pool->getItems(['testing1' => 1, 'testing2' => 2, 'testing3' => 3]); + + expect($results) + ->toHaveKey('testing1') + ->toHaveKey('testing2') + ->toHaveKey('testing3') + ->testing1->isHit()->toBeTrue() + ->testing2->isHit()->toBeTrue() + ->testing3->isHit()->toBeTrue(); + + $pool->clear(); + + expect($pool) + ->hasItem('testing1')->toBeFalse() + ->hasItem('testing2')->toBeFalse() + ->hasItem('testing3')->toBeFalse(); +}); diff --git a/tests/Unit/ConfigurationTest.php b/tests/Unit/ConfigurationTest.php new file mode 100644 index 00000000..72499215 --- /dev/null +++ b/tests/Unit/ConfigurationTest.php @@ -0,0 +1,34 @@ +group('configuration'); + +test('stringToArrayOrNull() behaves as expected', function (): void { + expect(Configuration::stringToArrayOrNull('foo bar baz')) + ->toBe(['foo', 'bar', 'baz']); +}); + +test('stringToArray() behaves as expected', function (): void { + expect(Configuration::stringToArray('foo bar baz')) + ->toBe(['foo', 'bar', 'baz']); +}); + +test('stringToBoolOrNull() behaves as expected', function (): void { + expect(Configuration::stringToBoolOrNull('true')) + ->toBeTrue(); + + expect(Configuration::stringToBoolOrNull('false')) + ->toBeFalse(); + + expect(Configuration::stringToBoolOrNull('foo')) + ->toBeNull(); + + expect(Configuration::stringToBoolOrNull('foo', true)) + ->toBeTrue(); + + expect(Configuration::stringToBoolOrNull('foo', false)) + ->toBeFalse(); +}); diff --git a/tests/Unit/Entities/CredentialTest.php b/tests/Unit/Entities/CredentialTest.php new file mode 100644 index 00000000..bc5c3399 --- /dev/null +++ b/tests/Unit/Entities/CredentialTest.php @@ -0,0 +1,191 @@ +group('stateful', 'model', 'model.credential'); + +beforeEach(function (): void { + $this->laravel = app('auth0'); + $this->guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + $this->session = $this->config->getSessionStorage(); + $this->transient = $this->config->getTransientStorage(); + $this->secret = uniqid(); + + $this->config->setDomain('my-domain.auth0.com'); + $this->config->setClientId('my_client_id'); + $this->config->setClientSecret($this->secret); + $this->config->setCookieSecret('my_cookie_secret'); + $this->config->setTokenAlgorithm(Token::ALGO_HS256); + $this->config->setStrategy(SdkConfiguration::STRATEGY_API); + + $this->user = new User(['sub' => uniqid('auth0|')]); + $this->idToken = uniqid(); + $this->accessToken = uniqid(); + $this->accessTokenScope = ['openid', 'profile', 'email', uniqid()]; + $this->accessTokenExpiration = time() + 3600; + $this->refreshToken = uniqid(); +}); + +test('create() returns a properly configured instance', function (): void { + $credential = Credential::create( + user: $this->user, + idToken: $this->idToken, + accessToken: $this->accessToken, + accessTokenScope: $this->accessTokenScope, + accessTokenExpiration: $this->accessTokenExpiration, + refreshToken: $this->refreshToken + ); + + expect($credential) + ->toBeInstanceOf(Credential::class) + ->getUser()->toBe($this->user) + ->getIdToken()->toBe($this->idToken) + ->getAccessToken()->toBe($this->accessToken) + ->getAccessTokenScope()->toBe($this->accessTokenScope) + ->getAccessTokenExpiration()->toBe($this->accessTokenExpiration) + ->getRefreshToken()->toBe($this->refreshToken); +}); + +it('clear() nullifies all properties', function (): void { + $credential = Credential::create( + user: $this->user, + idToken: $this->idToken, + accessToken: $this->accessToken, + accessTokenScope: $this->accessTokenScope, + accessTokenExpiration: $this->accessTokenExpiration, + refreshToken: $this->refreshToken, + ); + + expect($credential) + ->toBeInstanceOf(Credential::class) + ->getUser()->toBe($this->user) + ->getIdToken()->toBe($this->idToken) + ->getAccessToken()->toBe($this->accessToken) + ->getAccessTokenScope()->toBe($this->accessTokenScope) + ->getAccessTokenExpiration()->toBe($this->accessTokenExpiration) + ->getRefreshToken()->toBe($this->refreshToken); + + expect($credential->clear()) + ->toBeInstanceOf(Credential::class) + ->getUser()->toBeNull() + ->getIdToken()->toBeNull() + ->getAccessToken()->toBeNull() + ->getAccessTokenScope()->toBeNull() + ->getAccessTokenExpiration()->toBeNull() + ->getRefreshToken()->toBeNull(); +}); + +it('setUser() assigns a correct value', function (): void { + $credential = Credential::create(); + + expect($credential) + ->toBeInstanceOf(Credential::class) + ->getUser()->toBeNull(); + + expect($credential->setUser($this->user)) + ->toBeInstanceOf(Credential::class) + ->getUser()->toBe($this->user); +}); + +it('setIdToken() assigns a correct value', function (): void { + $credential = Credential::create(); + + expect($credential) + ->toBeInstanceOf(Credential::class) + ->getIdToken()->toBeNull(); + + expect($credential->setIdToken($this->idToken)) + ->toBeInstanceOf(Credential::class) + ->getIdToken()->toBe($this->idToken); +}); + +it('setAccessToken() assigns a correct value', function (): void { + $credential = Credential::create(); + + expect($credential) + ->toBeInstanceOf(Credential::class) + ->getAccessToken()->toBeNull(); + + expect($credential->setAccessToken($this->accessToken)) + ->toBeInstanceOf(Credential::class) + ->getAccessToken()->toBe($this->accessToken); +}); + +it('setAccessTokenScope() assigns a correct value', function (): void { + $credential = Credential::create(); + + expect($credential) + ->toBeInstanceOf(Credential::class) + ->getAccessTokenScope()->toBeNull(); + + expect($credential->setAccessTokenScope($this->accessTokenScope)) + ->toBeInstanceOf(Credential::class) + ->getAccessTokenScope()->toBe($this->accessTokenScope); +}); + +it('setAccessTokenExpiration() assigns a correct value', function (): void { + $credential = Credential::create(); + + expect($credential) + ->toBeInstanceOf(Credential::class) + ->getAccessTokenExpiration()->toBeNull(); + + expect($credential->setAccessTokenExpiration($this->accessTokenExpiration)) + ->toBeInstanceOf(Credential::class) + ->getAccessTokenExpiration()->toBe($this->accessTokenExpiration); +}); + +it('setRefreshToken() assigns a correct value', function (): void { + $credential = Credential::create(); + + expect($credential) + ->toBeInstanceOf(Credential::class) + ->getRefreshToken()->toBeNull(); + + expect($credential->setRefreshToken($this->refreshToken)) + ->toBeInstanceOf(Credential::class) + ->getRefreshToken()->toBe($this->refreshToken); +}); + +it('getAccessTokenExpired() returns a correct value', function (): void { + $credential = Credential::create(); + + expect($credential) + ->toBeInstanceOf(Credential::class) + ->getAccessTokenExpired()->toBeNull(); + + expect($credential->setAccessTokenExpiration($this->accessTokenExpiration)) + ->toBeInstanceOf(Credential::class) + ->getAccessTokenExpired()->toBeFalse(); + + expect($credential->setAccessTokenExpiration($this->accessTokenExpiration - 3600 * 2)) + ->toBeInstanceOf(Credential::class) + ->getAccessTokenExpired()->toBeTrue(); +}); + +it('jsonSerialize() returns a correct structure', function (): void { + $credential = Credential::create( + user: $this->user, + idToken: $this->idToken, + accessToken: $this->accessToken, + accessTokenScope: $this->accessTokenScope, + accessTokenExpiration: $this->accessTokenExpiration, + refreshToken: $this->refreshToken, + ); + + expect(json_encode($credential)) + ->json() + ->user->toBe(json_encode($this->user)) + ->idToken->toBe($this->idToken) + ->accessToken->toBe($this->accessToken) + ->accessTokenScope->toBe($this->accessTokenScope) + ->accessTokenExpiration->toBe($this->accessTokenExpiration) + ->refreshToken->toBe($this->refreshToken); +}); diff --git a/tests/Unit/Http/Controller/Stateful/CallbackTest.php b/tests/Unit/Http/Controller/Stateful/CallbackTest.php new file mode 100644 index 00000000..b1bed41c --- /dev/null +++ b/tests/Unit/Http/Controller/Stateful/CallbackTest.php @@ -0,0 +1,163 @@ +group('stateful', 'controller', 'controller.stateful', 'controller.stateful.callback'); + +beforeEach(function (): void { + $this->laravel = app('auth0'); + $this->guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + $this->session = $this->config->getSessionStorage(); + $this->transient = $this->config->getTransientStorage(); + $this->user = new User(['sub' => uniqid('auth0|')]); + + $this->secret = uniqid(); + + $this->config->setDomain('my-domain.auth0.com'); + $this->config->setClientId('my_client_id'); + $this->config->setClientSecret($this->secret); + $this->config->setCookieSecret('my_cookie_secret'); + $this->config->setStrategy(SdkConfiguration::STRATEGY_REGULAR); + + Route::get('/auth0/callback', Callback::class)->name('callback'); +}); + +it('redirects home if an incompatible guard is active', function (): void { + config([ + 'auth.defaults.guard' => 'web', + 'auth.guards.testGuard' => null, + 'auth0.routes.home' => '/testing' + ]); + + getJson('/auth0/callback') + ->assertFound() + ->assertLocation('/testing'); +}); + +it('accepts code and state parameters', function (): void { + expect(function () { + $this->withoutExceptionHandling() + ->getJson('/auth0/callback?code=code&state=state'); + })->toThrow(StateException::class); + + $this->assertDispatched(Attempting::class, 1); + $this->assertDispatched(Failed::class, 1); + $this->assertDispatched(AuthenticationFailed::class, 1); + + $this->assertDispatchedOrdered([ + Attempting::class, + Failed::class, + AuthenticationFailed::class, + ]); +}); + +it('accepts error and error_description parameters', function (): void { + expect(function () { + $this->withoutExceptionHandling() + ->getJson('/auth0/callback?error=123&error_description=456'); + })->toThrow(CallbackException::class); + + $this->assertDispatched(Attempting::class, 1); + $this->assertDispatched(Failed::class, 1); + $this->assertDispatched(AuthenticationFailed::class, 1); + + $this->assertDispatchedOrdered([ + Attempting::class, + Failed::class, + AuthenticationFailed::class, + ]); +}); + +it('returns a user and sets up a session', function (): void { + config([ + 'auth0.routes.home' => '/testing' + ]); + + $this->config->setTokenAlgorithm(Token::ALGO_HS256); + + $state = uniqid(); + $pkce = uniqid(); + $nonce = uniqid(); + $verifier = uniqid(); + + $accessToken = Generator::create($this->secret, Token::ALGO_HS256, [ + 'iss' => 'https://my-domain.auth0.com/', + 'sub' => 'hello|world', + 'aud' => 'my_client_id', + 'exp' => time() + 60, + 'iat' => time(), + 'email' => 'john.doe@somewhere.teset' + ], []); + + $idToken = Generator::create($this->secret, Token::ALGO_HS256, [ + 'iss' => 'https://my-domain.auth0.com/', + 'sub' => 'hello|world', + 'aud' => 'my_client_id', + 'iat' => time(), + 'exp' => time() + 60, + 'azp' => 'my_client_id', + 'scope' => 'openid profile email', + 'nonce' => $nonce, + ], []); + + $factory = $this->config->getHttpResponseFactory(); + $response = $factory->createResponse(); + $response->getBody()->write(json_encode([ + 'access_token' => $accessToken->toString(), + 'id_token' => $idToken->toString(), + 'scope' => 'openid profile email', + 'expires_in' => 60, + ])); + + $client = $this->config->getHttpClient(); + $client->addResponse('POST', 'https://my-domain.auth0.com/oauth/token', $response); + + $this->withSession([ + 'auth0_transient_state' => $state, + 'auth0_transient_pkce' => $pkce, + 'auth0_transient_nonce' => $nonce, + 'auth0_transient_code_verifier' => $verifier + ])->getJson('/auth0/callback?code=code&state=' . $state) + ->assertFound() + ->assertLocation('/testing'); + + $this->assertDispatched(Attempting::class, 1); + $this->assertDispatched(Validated::class, 1); + $this->assertDispatched(Login::class, 1); + $this->assertDispatched(AuthenticationSucceeded::class, 1); + $this->assertDispatched(Authenticated::class, 1); + + $this->assertDispatchedOrdered([ + Attempting::class, + Validated::class, + Login::class, + AuthenticationSucceeded::class, + Authenticated::class, + ]); +}); + +it('redirects visitors if an expected parameter is not provided', function (): void { + $this->getJson('/auth0/callback?code=code') + ->assertFound() + ->assertLocation('/login'); +}); diff --git a/tests/Unit/Http/Controller/Stateful/LoginTest.php b/tests/Unit/Http/Controller/Stateful/LoginTest.php new file mode 100644 index 00000000..0a8820ae --- /dev/null +++ b/tests/Unit/Http/Controller/Stateful/LoginTest.php @@ -0,0 +1,62 @@ +group('stateful', 'controller', 'controller.stateful', 'controller.stateful.login'); + +beforeEach(function (): void { + $this->laravel = app('auth0'); + $this->guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + $this->session = $this->config->getSessionStorage(); + $this->transient = $this->config->getTransientStorage(); + + $this->secret = uniqid(); + + $this->config->setDomain('my-domain.auth0.com'); + $this->config->setClientId('my_client_id'); + $this->config->setClientSecret($this->secret); + $this->config->setCookieSecret('my_cookie_secret'); + $this->config->setStrategy(SdkConfiguration::STRATEGY_REGULAR); + + $this->templates['validSession'] = [ + 'auth0_session_user' => ['sub' => 'hello|world'], + 'auth0_session_idToken' => uniqid(), + 'auth0_session_accessToken' => uniqid(), + 'auth0_session_accessTokenScope' => [uniqid()], + 'auth0_session_accessTokenExpiration' => time() + 60, + ]; + + Route::get('/login', Login::class); +}); + +it('redirects to the home route if an incompatible guard is active', function (): void { + config($config = [ + 'auth.defaults.guard' => 'web', + 'auth.guards.testGuard' => null, + 'auth0.routes.home' => '/' . uniqid(), + ]); + + $this->get('/login') + ->assertRedirect($config['auth0.routes.home']); +}); + +it('redirects to the home route when a user is already logged in', function (): void { + config($config = [ + 'auth0.routes.home' => '/' . uniqid(), + ]); + + $this->withSession($this->templates['validSession']) + ->get('/login') + ->assertRedirect($config['auth0.routes.home']); +}); + +it('redirects to the Universal Login Page', function (): void { + $this->get('/login') + ->assertRedirectContains('/authorize'); +}); diff --git a/tests/Unit/Http/Controller/Stateful/LogoutTest.php b/tests/Unit/Http/Controller/Stateful/LogoutTest.php new file mode 100644 index 00000000..eed805b2 --- /dev/null +++ b/tests/Unit/Http/Controller/Stateful/LogoutTest.php @@ -0,0 +1,62 @@ +group('stateful', 'controller', 'controller.stateful', 'controller.stateful.logout'); + +beforeEach(function (): void { + $this->laravel = app('auth0'); + $this->guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + $this->session = $this->config->getSessionStorage(); + $this->transient = $this->config->getTransientStorage(); + + $this->secret = uniqid(); + + $this->config->setDomain('my-domain.auth0.com'); + $this->config->setClientId('my_client_id'); + $this->config->setClientSecret($this->secret); + $this->config->setCookieSecret('my_cookie_secret'); + $this->config->setStrategy(SdkConfiguration::STRATEGY_REGULAR); + + $this->templates['validSession'] = [ + 'auth0_session_user' => ['sub' => 'hello|world'], + 'auth0_session_idToken' => uniqid(), + 'auth0_session_accessToken' => uniqid(), + 'auth0_session_accessTokenScope' => [uniqid()], + 'auth0_session_accessTokenExpiration' => time() + 60, + ]; + + Route::get('/logout', Logout::class); +}); + +it('redirects to the home route if an incompatible guard is active', function (): void { + config($config = [ + 'auth.defaults.guard' => 'web', + 'auth.guards.testGuard' => null, + 'auth0.routes.home' => '/' . uniqid(), + ]); + + $this->get('/logout') + ->assertRedirect($config['auth0.routes.home']); +}); + +it('redirects to the home route when a user is not already logged in', function (): void { + config($config = [ + 'auth0.routes.home' => '/' . uniqid(), + ]); + + $this->get('/logout') + ->assertRedirect($config['auth0.routes.home']); +}); + +it('redirects to the Auth0 logout endpoint', function (): void { + $this->withSession($this->templates['validSession']) + ->get('/logout') + ->assertRedirectContains('/v2/logout'); +}); diff --git a/tests/Unit/Http/Middleware/Stateful/AuthenticateOptionalTest.php b/tests/Unit/Http/Middleware/Stateful/AuthenticateOptionalTest.php new file mode 100644 index 00000000..c91772bf --- /dev/null +++ b/tests/Unit/Http/Middleware/Stateful/AuthenticateOptionalTest.php @@ -0,0 +1,117 @@ +group('stateful', 'middleware', 'middleware.stateful', 'middleware.stateful.authenticate_optional'); + +beforeEach(function (): void { + $this->laravel = app('auth0'); + $this->guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + $this->session = $this->config->getSessionStorage(); + $this->transient = $this->config->getTransientStorage(); + + $this->secret = uniqid(); + + $this->config->setDomain('my-domain.auth0.com'); + $this->config->setClientId('my_client_id'); + $this->config->setClientSecret($this->secret); + $this->config->setCookieSecret('my_cookie_secret'); + $this->config->setStrategy(SdkConfiguration::STRATEGY_REGULAR); + + $this->templates['validSession'] = [ + 'auth0_session_user' => ['sub' => 'hello|world'], + 'auth0_session_idToken' => uniqid(), + 'auth0_session_accessToken' => uniqid(), + 'auth0_session_accessTokenScope' => [uniqid(), 'read:admin'], + 'auth0_session_accessTokenExpiration' => time() + 60, + ]; +}); + +it('does not assign a user when an incompatible guard is used', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate.optional')->get($route, function () use ($route): string { + return $route; + }); + + config($config = [ + 'auth.defaults.guard' => 'web', + 'auth.guards.testGuard' => null + ]); + + $this->get($route) + ->assertStatus(Response::HTTP_INTERNAL_SERVER_ERROR); + + expect($this->guard) + ->user()->toBeNull(); +}); + +it('continues if a visitor does not have a session', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate.optional')->get($route, function () use ($route): string { + return $route; + }); + + $this->get($route) + ->assertStatus(Response::HTTP_OK) + ->assertSee($route); + + expect($this->guard) + ->user()->toBeNull(); +}); + +it('assigns a user', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate.optional')->get($route, function () use ($route): string { + return $route; + }); + + $this->withSession($this->templates['validSession']) + ->get($route) + ->assertStatus(Response::HTTP_OK) + ->assertSee($route); + + expect($this->guard) + ->user()->toBeInstanceOf(User::class); +}); + +it('assigns a user when using a configured scope matches', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate.optional:read:admin')->get($route, function () use ($route): string { + return $route; + }); + + $this->withSession($this->templates['validSession']) + ->get($route) + ->assertStatus(Response::HTTP_OK) + ->assertSee($route); + + expect($this->guard) + ->user()->toBeInstanceOf(User::class); +}); + +it('does not assign a user when a configured scope is not matched', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate.optional:something:else')->get($route, function () use ($route): string { + return $route; + }); + + $this->withSession($this->templates['validSession']) + ->get($route) + ->assertStatus(Response::HTTP_OK) + ->assertSee($route); + + expect($this->guard) + ->user()->toBeNull(); +}); diff --git a/tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php b/tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php new file mode 100644 index 00000000..51f04516 --- /dev/null +++ b/tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php @@ -0,0 +1,119 @@ +group('stateful', 'middleware', 'middleware.stateful', 'middleware.stateful.authenticate'); + +beforeEach(function (): void { + $this->laravel = app('auth0'); + $this->guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + $this->session = $this->config->getSessionStorage(); + $this->transient = $this->config->getTransientStorage(); + + $this->secret = uniqid(); + + $this->config->setDomain('my-domain.auth0.com'); + $this->config->setClientId('my_client_id'); + $this->config->setClientSecret($this->secret); + $this->config->setCookieSecret('my_cookie_secret'); + $this->config->setStrategy(SdkConfiguration::STRATEGY_REGULAR); + + $this->templates['validSession'] = [ + 'auth0_session_user' => ['sub' => 'hello|world'], + 'auth0_session_idToken' => uniqid(), + 'auth0_session_accessToken' => uniqid(), + 'auth0_session_accessTokenScope' => [uniqid(), 'read:admin'], + 'auth0_session_accessTokenExpiration' => time() + 60, + ]; +}); + +it('does not assign a user when an incompatible guard is used', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate')->get($route, function () use ($route): string { + return $route; + }); + + config($config = [ + 'auth.defaults.guard' => 'web', + 'auth.guards.testGuard' => null + ]); + + $this->get($route) + ->assertStatus(Response::HTTP_INTERNAL_SERVER_ERROR); + + expect($this->guard) + ->user()->toBeNull(); +}); + +it('redirects to login route if a visitor does not have a session', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate')->get($route, function () use ($route): string { + return $route; + }); + + config($config = [ + 'auth0.routes.login' => '/' . uniqid() + ]); + + $this->get($route) + ->assertRedirect($config['auth0.routes.login']); + + expect($this->guard) + ->user()->toBeNull(); +}); + +it('assigns a user', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate')->get($route, function () use ($route): string { + return $route; + }); + + $this->withSession($this->templates['validSession']) + ->get($route) + ->assertStatus(Response::HTTP_OK) + ->assertSee($route); + + expect($this->guard) + ->user()->toBeInstanceOf(User::class); +}); + +it('assigns a user when using a configured scope matches', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate:read:admin')->get($route, function () use ($route): string { + return $route; + }); + + $this->withSession($this->templates['validSession']) + ->get($route) + ->assertStatus(Response::HTTP_OK) + ->assertSee($route); + + expect($this->guard) + ->user()->toBeInstanceOf(User::class); +}); + +it('does not assign a user when a configured scope is not matched', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate:something:else')->get($route, function () use ($route): string { + return $route; + }); + + $this->withSession($this->templates['validSession']) + ->get($route) + ->assertStatus(Response::HTTP_FORBIDDEN); + + expect($this->guard) + ->user()->toBeNull(); +}); diff --git a/tests/Unit/Http/Middleware/Stateless/AuthorizeOptionalTest.php b/tests/Unit/Http/Middleware/Stateless/AuthorizeOptionalTest.php new file mode 100644 index 00000000..90f1eeaf --- /dev/null +++ b/tests/Unit/Http/Middleware/Stateless/AuthorizeOptionalTest.php @@ -0,0 +1,152 @@ +group('stateful', 'middleware', 'middleware.stateless', 'middleware.stateless.authorize'); + +beforeEach(function (): void { + $this->laravel = app('auth0'); + $this->guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + $this->session = $this->config->getSessionStorage(); + $this->transient = $this->config->getTransientStorage(); + + $this->secret = uniqid(); + + $this->config->setDomain('my-domain.auth0.com'); + $this->config->setClientId('my_client_id'); + $this->config->setClientSecret($this->secret); + $this->config->setCookieSecret('my_cookie_secret'); + $this->config->setTokenAlgorithm(Token::ALGO_HS256); + $this->config->setStrategy(SdkConfiguration::STRATEGY_API); +}); + +it('does not assign a user when an incompatible guard is used', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize.optional')->get($route, function () use ($route): string { + return json_encode(['status' => $route]); + }); + + config([ + 'auth.defaults.guard' => 'web', + 'auth.guards.testGuard' => null + ]); + + $this->getJson($route, ['Authorization' => 'Bearer ' . uniqid()]) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]); + + expect($this->guard) + ->user()->toBeNull(); +}); + +it('does not assign a user when an invalid bearer token is provided', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize.optional')->get($route, function () use ($route): string { + return json_encode(['status' => $route]); + }); + + $this->getJson($route, ['Authorization' => 'Bearer ' . uniqid()]) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]); + + expect($this->guard) + ->user()->toBeNull(); +}); + +it('assigns a user', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize.optional')->get($route, function () use ($route): string { + return json_encode(['status' => $route]); + }); + + $token = Generator::create($this->secret, Token::ALGO_HS256, [ + "iss" => "https://my-domain.auth0.com/", + "sub" => "auth0|123456", + "aud" => [ + "https://example.com/health-api", + "https://my-domain.auth0.com/userinfo", + "my_client_id" + ], + "azp" => "my_client_id", + "exp" => time() + 60, + "iat" => time(), + "scope" => "openid profile read:patients read:admin" + ]); + + $this->getJson($route, ['Authorization' => 'Bearer ' . $token->toString()]) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]); + + expect($this->guard) + ->user()->toBeInstanceOf(User::class); +}); + +it('assigns a user when using a configured scope matches', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize.optional:read:admin')->get($route, function () use ($route): string { + return json_encode(['status' => $route]); + }); + + $token = Generator::create($this->secret, Token::ALGO_HS256, [ + "iss" => "https://my-domain.auth0.com/", + "sub" => "auth0|123456", + "aud" => [ + "https://example.com/health-api", + "https://my-domain.auth0.com/userinfo", + "my_client_id" + ], + "azp" => "my_client_id", + "exp" => time() + 60, + "iat" => time(), + "scope" => "openid profile read:patients read:admin" + ]); + + $this->getJson($route, ['Authorization' => 'Bearer ' . $token->toString()]) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]); + + expect($this->guard) + ->user()->toBeInstanceOf(User::class); +}); + +it('does not assign a user when a configured scope is not matched', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize.optional:something:else')->get($route, function () use ($route): string { + return json_encode(['status' => $route]); + }); + + $token = Generator::create($this->secret, Token::ALGO_HS256, [ + "iss" => "https://my-domain.auth0.com/", + "sub" => "auth0|123456", + "aud" => [ + "https://example.com/health-api", + "https://my-domain.auth0.com/userinfo", + "my_client_id" + ], + "azp" => "my_client_id", + "exp" => time() + 60, + "iat" => time(), + "scope" => "openid profile read:patients read:admin" + ]); + + $this->getJson($route, ['Authorization' => 'Bearer ' . $token->toString()]) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]); + + expect($this->guard) + ->user()->toBeNull(); +}); diff --git a/tests/Unit/Http/Middleware/Stateless/AuthorizeTest.php b/tests/Unit/Http/Middleware/Stateless/AuthorizeTest.php new file mode 100644 index 00000000..2a0b2963 --- /dev/null +++ b/tests/Unit/Http/Middleware/Stateless/AuthorizeTest.php @@ -0,0 +1,150 @@ +group('stateful', 'middleware', 'middleware.stateless', 'middleware.stateless.authorize'); + +beforeEach(function (): void { + $this->laravel = app('auth0'); + $this->guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + $this->session = $this->config->getSessionStorage(); + $this->transient = $this->config->getTransientStorage(); + + $this->secret = uniqid(); + + $this->config->setDomain('my-domain.auth0.com'); + $this->config->setClientId('my_client_id'); + $this->config->setClientSecret($this->secret); + $this->config->setCookieSecret('my_cookie_secret'); + $this->config->setTokenAlgorithm(Token::ALGO_HS256); + $this->config->setStrategy(SdkConfiguration::STRATEGY_API); +}); + +it('does not assign a user when an incompatible guard is used', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize')->get($route, function () use ($route): string { + return json_encode(['status' => $route]); + }); + + config([ + 'auth.defaults.guard' => 'web', + 'auth.guards.testGuard' => null + ]); + + $this->getJson($route, ['Authorization' => 'Bearer ' . uniqid()]) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]); + + expect($this->guard) + ->user()->toBeNull(); +}); + +it('returns a 401 and does not assign a user when an invalid bearer token is provided', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize')->get($route, function () use ($route): string { + return json_encode(['status' => $route]); + }); + + $this->getJson($route, ['Authorization' => 'Bearer ' . uniqid()]) + ->assertStatus(Response::HTTP_UNAUTHORIZED); + + expect($this->guard) + ->user()->toBeNull(); +}); + +it('assigns a user', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize')->get($route, function () use ($route): string { + return json_encode(['status' => $route]); + }); + + $token = Generator::create($this->secret, Token::ALGO_HS256, [ + "iss" => "https://my-domain.auth0.com/", + "sub" => "auth0|123456", + "aud" => [ + "https://example.com/health-api", + "https://my-domain.auth0.com/userinfo", + "my_client_id" + ], + "azp" => "my_client_id", + "exp" => time() + 60, + "iat" => time(), + "scope" => "openid profile read:patients read:admin" + ]); + + $this->getJson($route, ['Authorization' => 'Bearer ' . $token->toString()]) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]); + + expect($this->guard) + ->user()->toBeInstanceOf(User::class); +}); + +it('assigns a user when using a configured scope matches', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize:read:admin')->get($route, function () use ($route): string { + return json_encode(['status' => $route]); + }); + + $token = Generator::create($this->secret, Token::ALGO_HS256, [ + "iss" => "https://my-domain.auth0.com/", + "sub" => "auth0|123456", + "aud" => [ + "https://example.com/health-api", + "https://my-domain.auth0.com/userinfo", + "my_client_id" + ], + "azp" => "my_client_id", + "exp" => time() + 60, + "iat" => time(), + "scope" => "openid profile read:patients read:admin" + ]); + + $this->getJson($route, ['Authorization' => 'Bearer ' . $token->toString()]) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]); + + expect($this->guard) + ->user()->toBeInstanceOf(User::class); +}); + +it('returns a 403 and does not assign a user when a configured scope is not matched', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize:something:else')->get($route, function () use ($route): string { + return json_encode(['status' => $route]); + }); + + $token = Generator::create($this->secret, Token::ALGO_HS256, [ + "iss" => "https://my-domain.auth0.com/", + "sub" => "auth0|123456", + "aud" => [ + "https://example.com/health-api", + "https://my-domain.auth0.com/userinfo", + "my_client_id" + ], + "azp" => "my_client_id", + "exp" => time() + 60, + "iat" => time(), + "scope" => "openid profile read:patients read:admin" + ]); + + $this->getJson($route, ['Authorization' => 'Bearer ' . $token->toString()]) + ->assertStatus(Response::HTTP_FORBIDDEN); + + expect($this->guard) + ->user()->toBeNull(); +}); diff --git a/tests/Unit/Model/UserTest.php b/tests/Unit/Model/UserTest.php new file mode 100644 index 00000000..77f6a353 --- /dev/null +++ b/tests/Unit/Model/UserTest.php @@ -0,0 +1,103 @@ +group('stateful', 'model', 'model.user'); + +it('fills attributes provided to the constructor', function (): void { + $user = new User(['testing' => 'testing']); + + expect($user->testing) + ->toBe('testing'); +}); + +it('fills attributes', function (): void { + $user = new User(); + $user->fill(['testing' => 'testing']); + + expect($user->testing) + ->toBe('testing'); +}); + +it('sets attributes with magic', function (): void { + $user = new User(); + $user->testing = 'testing'; + + expect($user->testing) + ->toBe('testing'); +}); + +it('sets attributes', function (): void { + $user = new User(); + $user->setAttribute('testing', 'testing'); + + expect($user->getAttribute('testing')) + ->toBe('testing'); +}); + +it('gets attributes array', function (): void { + $user = new User([ + 'testing' => 'testing', + 'testing2' => 'testing2', + ]); + + expect($user->getAttributes()) + ->toBeArray() + ->toContain('testing') + ->toContain('testing2'); +}); + +it('supports getting the identifier', function (): void { + $user = new User(['sub' => 'testing']); + + expect($user->getAuthIdentifier()) + ->toBe('testing'); +}); + +it('supports getting the identifier name', function (): void { + $user = new User(['sub' => 'testing']); + + expect($user->getAuthIdentifierName()) + ->toBe('id'); +}); + +it('supports getting the password', function (): void { + $user = new User(); + + expect($user->getAuthPassword()) + ->toBe(''); +}); + +it('supports getting the remember token', function (): void { + $user = new User(); + + expect($user->getRememberToken()) + ->toBe(''); +}); + +it('supports getting the remember token name', function (): void { + $user = new User(); + + expect($user->getRememberTokenName()) + ->toBe(''); +}); + +it('supports setting the remember token', function (): void { + $user = new User(); + + expect($user->setRememberToken('testing')) + ->toBeNull(); +}); + +it('supports JSON serialization', function (): void { + $user = new User(['testing' => 'testing']); + + expect($user->jsonSerialize()) + ->toBeArray() + ->toContain('testing'); + + expect(json_encode($user)) + ->toBeJson('{"testing":"testing"}'); +}); diff --git a/tests/Unit/ServiceProviderTest.php b/tests/Unit/ServiceProviderTest.php new file mode 100644 index 00000000..5e564ff9 --- /dev/null +++ b/tests/Unit/ServiceProviderTest.php @@ -0,0 +1,192 @@ +group('service-provider'); + +it('provides the expected classes', function (): void { + $service = app(\Auth0\Laravel\ServiceProvider::class, ['app' => $this->app]); + + expect($service->provides()) + ->toBe([ + Auth0::class, + Authenticate::class, + AuthenticateOptional::class, + Authorize::class, + AuthorizeOptional::class, + Callback::class, + Guard::class, + LaravelSession::class, + Login::class, + Logout::class, + Provider::class, + Repository::class + ]); +}); + +it('creates a Auth0 singleton', function (): void { + $singleton1 = $this->app->make('auth0'); + $singleton2 = $this->app->make(Auth0::class); + + expect($singleton1) + ->toBeInstanceOf(Auth0::class); + + expect($singleton2) + ->toBeInstanceOf(Auth0::class); + + expect($singleton1) + ->toBe($singleton2); +}); + +it('does NOT create a Guard singleton', function (): void { + $singleton1 = $this->app->make('auth0.guard'); + $singleton2 = $this->app->make(Guard::class); + + expect($singleton1) + ->toBeInstanceOf(Guard::class); + + expect($singleton2) + ->toBeInstanceOf(Guard::class); + + expect($singleton1) + ->not()->toBe($singleton2); +}); + +it('creates a Repository singleton', function (): void { + $singleton1 = $this->app->make('auth0.repository'); + $singleton2 = $this->app->make(Repository::class); + + expect($singleton1) + ->toBeInstanceOf(Repository::class); + + expect($singleton2) + ->toBeInstanceOf(Repository::class); + + expect($singleton1) + ->toBe($singleton2); +}); + +it('creates a Provider singleton', function (): void { + $singleton1 = $this->app->make('auth0.provider'); + $singleton2 = $this->app->make(Provider::class); + + expect($singleton1) + ->toBeInstanceOf(Provider::class); + + expect($singleton2) + ->toBeInstanceOf(Provider::class); + + expect($singleton1) + ->toBe($singleton2); +}); + +it('creates a Authenticate singleton', function (): void { + $singleton1 = $this->app->make(Authenticate::class); + $singleton2 = $this->app->make(Authenticate::class); + + expect($singleton1) + ->toBeInstanceOf(Authenticate::class); + + expect($singleton2) + ->toBeInstanceOf(Authenticate::class); + + expect($singleton1) + ->toBe($singleton2); +}); + +it('creates a AuthenticateOptional singleton', function (): void { + $singleton1 = $this->app->make(AuthenticateOptional::class); + $singleton2 = $this->app->make(AuthenticateOptional::class); + + expect($singleton1) + ->toBeInstanceOf(AuthenticateOptional::class); + + expect($singleton2) + ->toBeInstanceOf(AuthenticateOptional::class); + + expect($singleton1) + ->toBe($singleton2); +}); + +it('creates a Authorize singleton', function (): void { + $singleton1 = $this->app->make(Authorize::class); + $singleton2 = $this->app->make(Authorize::class); + + expect($singleton1) + ->toBeInstanceOf(Authorize::class); + + expect($singleton2) + ->toBeInstanceOf(Authorize::class); + + expect($singleton1) + ->toBe($singleton2); +}); + +it('creates a AuthorizeOptional singleton', function (): void { + $singleton1 = $this->app->make(AuthorizeOptional::class); + $singleton2 = $this->app->make(AuthorizeOptional::class); + + expect($singleton1) + ->toBeInstanceOf(AuthorizeOptional::class); + + expect($singleton2) + ->toBeInstanceOf(AuthorizeOptional::class); + + expect($singleton1) + ->toBe($singleton2); +}); + +it('creates a Login singleton', function (): void { + $singleton1 = $this->app->make(Login::class); + $singleton2 = $this->app->make(Login::class); + + expect($singleton1) + ->toBeInstanceOf(Login::class); + + expect($singleton2) + ->toBeInstanceOf(Login::class); + + expect($singleton1) + ->toBe($singleton2); +}); + +it('creates a Logout singleton', function (): void { + $singleton1 = $this->app->make(Logout::class); + $singleton2 = $this->app->make(Logout::class); + + expect($singleton1) + ->toBeInstanceOf(Logout::class); + + expect($singleton2) + ->toBeInstanceOf(Logout::class); + + expect($singleton1) + ->toBe($singleton2); +}); + +it('creates a Callback singleton', function (): void { + $singleton1 = $this->app->make(Callback::class); + $singleton2 = $this->app->make(Callback::class); + + expect($singleton1) + ->toBeInstanceOf(Callback::class); + + expect($singleton2) + ->toBeInstanceOf(Callback::class); + + expect($singleton1) + ->toBe($singleton2); +}); diff --git a/tests/Unit/Store/LaravelSessionTest.php b/tests/Unit/Store/LaravelSessionTest.php new file mode 100644 index 00000000..a629f81e --- /dev/null +++ b/tests/Unit/Store/LaravelSessionTest.php @@ -0,0 +1,66 @@ +group('session-store'); + +it('throws an exception when an empty prefix is provided', function (): void { + expect(function () { + new LaravelSession( + prefix: '', + ); + })->toThrow(InvalidArgumentException::class); +}); + +it('accepts and uses a specified prefix', function (): void { + $prefix = uniqid(); + + $store = new LaravelSession( + prefix: $prefix, + ); + + expect($store) + ->toBeInstanceOf(StoreInterface::class) + ->getPrefix()->toBe($prefix); +}); + +it('allows updating the prefix', function (): void { + $store = new LaravelSession(); + + expect($store) + ->toBeInstanceOf(StoreInterface::class) + ->getPrefix()->toBe('auth0'); + + $prefix = uniqid(); + $store->setPrefix($prefix); + + expect($store) + ->toBeInstanceOf(StoreInterface::class) + ->getPrefix()->toBe($prefix); +}); + +it('supports CRUD operations', function (): void { + $prefix = uniqid(); + + $store = new LaravelSession( + prefix: $prefix, + ); + + expect($store) + ->toBeInstanceOf(StoreInterface::class) + ->get('test')->toBeNull() + ->set('test', 'value')->toBeNull() + ->get('test')->toBe('value') + ->getAll()->toBe([$prefix . '_test' => 'value']) + ->set('test2', 'value2')->toBeNull() + ->getAll()->toBe([$prefix . '_test' => 'value', $prefix . '_test2' => 'value2']) + ->delete('test')->toBeNull() + ->getAll()->toBe([$prefix . '_test2' => 'value2']) + ->set('test3', 'value3')->toBeNull() + ->getAll()->toBe([$prefix . '_test2' => 'value2', $prefix . '_test3' => 'value3']) + ->purge()->toBeNull() + ->getAll()->toBe([]); +}); diff --git a/tests/Unit/Traits/ActingAsAuth0UserTest.php b/tests/Unit/Traits/ActingAsAuth0UserTest.php new file mode 100644 index 00000000..35b4243f --- /dev/null +++ b/tests/Unit/Traits/ActingAsAuth0UserTest.php @@ -0,0 +1,172 @@ +group('trait', 'impersonation'); + +uses(ActingAsAuth0User::class); + +beforeEach(function (): void { + $this->laravel = app('auth0'); + $this->guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + $this->session = $this->config->getSessionStorage(); + $this->transient = $this->config->getTransientStorage(); + $this->secret = uniqid(); + $this->config->setDomain('my-domain.auth0.com'); + $this->config->setClientId('my_client_id'); + $this->config->setClientSecret($this->secret); + $this->config->setCookieSecret('my_cookie_secret'); + $this->config->setTokenAlgorithm(Token::ALGO_HS256); + $this->config->setStrategy(SdkConfiguration::STRATEGY_API); + + $this->user = ['sub' => uniqid(), 'scope' => 'openid profile email read:messages']; +}); + +it('impersonates with other guards', function (): void { + config([ + 'auth.defaults.guard' => 'web', + 'auth.guards.testGuard' => null + ]); + + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize')->get($route, function () use ($route): string { + return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); + }); + + $this->actingAsAuth0User($this->user, null) + ->getJson($route) + ->assertStatus(Response::HTTP_OK); + + expect($this->guard) + ->user()->toBeNull(); +}); + +it('impersonates a user against auth0.authenticate', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate')->get($route, function () use ($route) { + return response()->json([ + 'user' => auth()->user(), + 'status' => $route + ]); + }); + + $this->actingAsAuth0User($this->user, null) + ->getJson($route) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]) + ->assertJsonFragment(['sub' => $this->user['sub']]); + + expect($this->guard) + ->user()->toBeInstanceOf(Imposter::class); +}); + +it('impersonates a user against auth0.authenticate.optional', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate.optional')->get($route, function () use ($route) { + return response()->json([ + 'user' => auth()->user(), + 'status' => $route + ]); + }); + + $this->actingAsAuth0User($this->user, null) + ->getJson($route) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]) + ->assertJsonFragment(['sub' => $this->user['sub']]); + + expect($this->guard) + ->user()->toBeInstanceOf(Imposter::class); +}); + +it('impersonates a user against auth0.authenticate using a scope', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate:read:messages')->get($route, function () use ($route) { + return response()->json([ + 'user' => auth()->user(), + 'status' => $route + ]); + }); + + $this->actingAsAuth0User($this->user, null) + ->getJson($route) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]) + ->assertJsonFragment(['sub' => $this->user['sub']]); + + expect($this->guard) + ->user()->toBeInstanceOf(Imposter::class); +}); + +it('impersonates a user against auth0.authorize', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize')->get($route, function () use ($route) { + return response()->json([ + 'user' => auth()->user(), + 'status' => $route + ]); + }); + + $this->actingAsAuth0User($this->user, null) + ->getJson($route) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]) + ->assertJsonFragment(['sub' => $this->user['sub']]); + + expect($this->guard) + ->user()->toBeInstanceOf(Imposter::class); +}); + +it('impersonates a user against auth0.authorize.optional', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize.optional')->get($route, function () use ($route) { + return response()->json([ + 'user' => auth()->user(), + 'status' => $route + ]); + }); + + $this->actingAsAuth0User($this->user, null) + ->getJson($route) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]) + ->assertJsonFragment(['sub' => $this->user['sub']]); + + expect($this->guard) + ->user()->toBeInstanceOf(Imposter::class); +}); + +it('impersonates a user against auth0.authorize using a scope', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize:read:messages')->get($route, function () use ($route) { + return response()->json([ + 'user' => auth()->user(), + 'status' => $route + ]); + }); + + $this->actingAsAuth0User($this->user, null) + ->getJson($route) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]) + ->assertJsonFragment(['sub' => $this->user['sub']]); + + expect($this->guard) + ->user()->toBeInstanceOf(Imposter::class); +}); diff --git a/tests/Unit/Traits/ImpersonateTest.php b/tests/Unit/Traits/ImpersonateTest.php new file mode 100644 index 00000000..94194874 --- /dev/null +++ b/tests/Unit/Traits/ImpersonateTest.php @@ -0,0 +1,168 @@ +group('trait', 'impersonate'); + +uses(Impersonate::class); + +beforeEach(function (): void { + $this->laravel = app('auth0'); + $this->guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + $this->session = $this->config->getSessionStorage(); + $this->transient = $this->config->getTransientStorage(); + $this->secret = uniqid(); + $this->config->setDomain('my-domain.auth0.com'); + $this->config->setClientId('my_client_id'); + $this->config->setClientSecret($this->secret); + $this->config->setCookieSecret('my_cookie_secret'); + $this->config->setTokenAlgorithm(Token::ALGO_HS256); + $this->config->setStrategy(SdkConfiguration::STRATEGY_API); + + $this->impersonating = Credential::create( + user: new User(['sub' => uniqid()]), + idToken: uniqid(), + accessToken: uniqid(), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600 + ); +}); + +it('impersonates with other guards', function (): void { + config([ + 'auth.defaults.guard' => 'web', + 'auth.guards.testGuard' => null + ]); + + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize')->get($route, function () use ($route): string { + return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); + }); + + $this->impersonate($this->impersonating) + ->getJson($route) + ->assertStatus(Response::HTTP_OK); + + expect($this->guard) + ->user()->toBeNull(); +}); + +it('impersonates a user against auth0.authenticate', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate')->get($route, function () use ($route): string { + return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); + }); + + $this->impersonate($this->impersonating, Guard::SOURCE_SESSION) + ->getJson($route) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]) + ->assertJson(['user' => json_encode($this->impersonating->getUser())]); + + expect($this->guard) + ->user()->toBeInstanceOf(User::class) + ->toBe($this->impersonating->getUser()); +}); + +it('impersonates a user against auth0.authenticate.optional', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate.optional')->get($route, function () use ($route): string { + return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); + }); + + $this->impersonate($this->impersonating, Guard::SOURCE_SESSION) + ->getJson($route) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]) + ->assertJson(['user' => json_encode($this->impersonating->getUser())]); + + expect($this->guard) + ->user()->toBeInstanceOf(User::class) + ->toBe($this->impersonating->getUser()); +}); + +it('impersonates a user against auth0.authenticate using a scope', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate:read:messages')->get($route, function () use ($route): string { + return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); + }); + + $this->impersonate($this->impersonating, Guard::SOURCE_SESSION) + ->getJson($route) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]) + ->assertJson(['user' => json_encode($this->impersonating->getUser())]); + + expect($this->guard) + ->user()->toBeInstanceOf(User::class) + ->toBe($this->impersonating->getUser()); +}); + +it('impersonates a user against auth0.authorize', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize')->get($route, function () use ($route): string { + return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); + }); + + $this->impersonate($this->impersonating, Guard::SOURCE_TOKEN) + ->getJson($route) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]) + ->assertJson(['user' => json_encode($this->impersonating->getUser())]); + + expect($this->guard) + ->user()->toBeInstanceOf(User::class) + ->toBe($this->impersonating->getUser()); +}); + +it('impersonates a user against auth0.authorize.optional', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize.optional')->get($route, function () use ($route): string { + return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); + }); + + $this->impersonate($this->impersonating, Guard::SOURCE_TOKEN) + ->getJson($route) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]) + ->assertJson(['user' => json_encode($this->impersonating->getUser())]); + + expect($this->guard) + ->user()->toBeInstanceOf(User::class) + ->toBe($this->impersonating->getUser()); +}); + +it('impersonates a user against auth0.authorize using a scope', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize:read:messages')->get($route, function () use ($route): string { + return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); + }); + + $this->impersonate($this->impersonating, Guard::SOURCE_TOKEN) + ->getJson($route) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]) + ->assertJson(['user' => json_encode($this->impersonating->getUser())]); + + expect($this->guard) + ->user()->toBeInstanceOf(User::class) + ->toBe($this->impersonating->getUser()); +}); diff --git a/tests/constants.php b/tests/constants.php index bf70fd4e..174d7fd7 100644 --- a/tests/constants.php +++ b/tests/constants.php @@ -1,19 +1,3 @@ Date: Tue, 14 Mar 2023 15:12:12 -0500 Subject: [PATCH 192/525] Update EXAMPLES.md --- EXAMPLES.md | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index 0ffbc2f3..8bcb44bf 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -1,13 +1,13 @@ # Examples using laravel-auth0 -- [Custom user models and repositories](#custom-user-models-and-repositories) -- [Authorizing HTTP tests](#authorizing-http-tests) +- [Custom user models and repositories](#custom-user-models-and-repositories) +- [Authorizing HTTP tests](#authorizing-http-tests) ## Custom user models and repositories In Laravel, a User Repository is an interface that sits between your authentication source (Auth0) and core Laravel authentication services. It allows you to shape and manipulate the user model and it's data as you need to. -For example, Auth0's unique identifier is a `string` in the format `auth0|123456abcdef`. If you were to attempt to persist a user to many traditional databases you'd likely encounter an error as, by default, a unique identifier is often exected to be an `integer` rather than a `string` type. A custom user model and repository is a great way to address integration challenges like this. +For example, Auth0's unique identifier is a `string` in the format `auth0|123456abcdef`. If you were to attempt to persist a user to many traditional databases you'd likely encounter an error as, by default, a unique identifier is often expected to be an `integer` rather than a `string` type. A custom user model and repository is a great way to address integration challenges like this. ### Creating a custom user model @@ -66,7 +66,7 @@ class User extends \Illuminate\Database\Eloquent\Model implements StatefulUser, ### Creating a Custom User Repository -Now let's create a custom user repository for your application which will return the new new custom model. To do this, create the file `app/Auth/CustomUserRepository.php`. This new class must implment the `Auth0\Laravel\Contract\Auth\User\Repository` interface. This new repository takes in user data returned from Auth0's API, applies it to the `App\Models\User` custom user model created in the previous step, and returns it for use throughout your application. +Now let's create a custom user repository for your application which will return the new new custom model. To do this, create the file `app/Auth/CustomUserRepository.php`. This new class must implement the `Auth0\Laravel\Contract\Auth\User\Repository` interface. This new repository takes in user data returned from Auth0's API, applies it to the `App\Models\User` custom user model created in the previous step, and returns it for use throughout your application. ```php json([ @@ -131,14 +132,24 @@ Route::get('/api/private-scoped', function () { ``` To be able to test the route from above, the implementation of your test would have to look like this: -```php -use Auth0\Laravel\Traits\ActingAsAuth0User; - -public function test_readMessages(){ - $response = $this->actingAsAuth0User([ - "scope"=>"read:messages" - ])->getJson("/api/private-scoped"); - $response->assertStatus(200); -} +```php +use Auth0\Laravel\Contract\StateInstance; +use Auth0\Laravel\Model\Credential; +use Auth0\Laravel\Model\Stateless\User; +use Auth0\Laravel\Trait\Impersonate; +use Illuminate\Http\Response; + +it('can access a private scoped endpoint', function () { + $impersonating = Credential::create( + user: new User(['sub' => 'auth0|123456abcdef']), + accessTokenScope: ['read:messages'], + source: StateInstance::CONST_SOURCE_TOKEN, + ); + + $this->impersonate($impersonating) + ->getJson('/api/private-scoped') + ->assertStatus(Response::HTTP_OK) + ->assertJson(['message' => 'Hello from a private endpoint!']); +}); ``` From f8e14398665127bd48794ae38e2ca7cc93ea19c9 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:13:06 -0500 Subject: [PATCH 193/525] Update README.md --- README.md | 56 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 0c71e486..f5a2b572 100644 --- a/README.md +++ b/README.md @@ -3,29 +3,28 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. [![Package](https://img.shields.io/packagist/dt/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) -[![Build](https://img.shields.io/github/workflow/status/auth0/laravel-auth0/Checks)](https://github.com/auth0/laravel-auth0/actions/workflows/checks.yml?query=branch%3Amain) [![License](https://img.shields.io/packagist/l/auth0/login)](https://doge.mit-license.org/) :books: [Documentation](#documentation) - :rocket: [Getting Started](#getting-started) - :speech_balloon: [Feedback](#feedback) ## Documentation -- Stateful Applications - - [Quickstart](https://auth0.com/docs/quickstart/webapp/laravel) — add login, logout and user information to a Laravel application using Auth0. - - [Sample Application](https://github.com/auth0-samples/auth0-laravel-php-web-app) — a sample Laravel web application integrated with Auth0. -- Stateless Applications - - [Quickstart](https://auth0.com/docs/quickstart/backend/php) — add access token handling and route authorization to a backend Laravel application using Auth0. - - [Sample Application](https://github.com/auth0-samples/auth0-laravel-api-samples) — a sample Laravel backend application integrated with Auth0. -- [Examples](./EXAMPLES.md) — code samples for common scenarios. -- [Docs site](https://www.auth0.com/docs) — explore our docs site and learn more about Auth0. +- Stateful Applications + - [Quickstart](https://auth0.com/docs/quickstart/webapp/laravel) — add login, logout and user information to a Laravel application using Auth0. + - [Sample Application](https://github.com/auth0-samples/auth0-laravel-php-web-app) — a sample Laravel web application integrated with Auth0. +- Stateless Applications + - [Quickstart](https://auth0.com/docs/quickstart/backend/php) — add access token handling and route authorization to a backend Laravel application using Auth0. + - [Sample Application](https://github.com/auth0-samples/auth0-laravel-api-samples) — a sample Laravel backend application integrated with Auth0. +- [Examples](./EXAMPLES.md) — code samples for common scenarios. +- [Docs site](https://www.auth0.com/docs) — explore our docs site and learn more about Auth0. ## Getting Started ### Requirements -- PHP 8.0+ -- Laravel 8 / Laravel 9 -- `Illuminate\Session\Middleware\StartSession` enabled in `app/Http/Kernel.php` +- PHP 8.0+ +- Laravel 8 / Laravel 9 +- `Illuminate\Session\Middleware\StartSession` enabled in `app/Http/Kernel.php` > Please review our [support policy](#support-policy) to learn when language and framework versions will exit support in the future. @@ -45,8 +44,8 @@ Create a **Regular Web Application** in the [Auth0 Dashboard](https://manage.aut Next, configure the callback and logout URLs for your application under the "Application URIs" section of the "Settings" page: -- **Allowed Callback URLs**: The URL of your application where Auth0 will redirect to during authentication, e.g., `http://localhost:3000/callback`. -- **Allowed Logout URLs**: The URL of your application where Auth0 will redirect to after user logout, e.g., `http://localhost:3000/login`. +- **Allowed Callback URLs**: The URL of your application where Auth0 will redirect to during authentication, e.g., `http://localhost:3000/callback`. +- **Allowed Logout URLs**: The URL of your application where Auth0 will redirect to after user logout, e.g., `http://localhost:3000/login`. Note the **Domain**, **Client ID**, and **Client Secret**. These values will be used during configuration later. @@ -75,6 +74,7 @@ AUTH0_COOKIE_SECRET="A randomly generated string" ``` Provide a sufficiently long, random string for your `AUTH0_COOKIE_SECRET` using `openssl rand -hex 32`. +
@@ -87,6 +87,7 @@ AUTH0_CLIENT_ID="Your Auth0 application client ID" AUTH0_CLIENT_SECRET="Your Auth0 application client secret" AUTH0_AUDIENCE="Your Auth0 API identifier" ``` +
### Setup your Laravel application @@ -104,6 +105,7 @@ To begin, find the `defaults` section. Set the default `guard` to `auth0`, like ``` Next, find the `guards` section, and add `auth0` there: + ```php // 👆 Continued from above, in config/auth.php 'guards' => [ @@ -116,6 +118,7 @@ Next, find the `guards` section, and add `auth0` there: ``` Next, find the `providers` section, and add `auth0` there as well: + ```php // 👆 Continued from above, in config/auth.php 'providers' => [ @@ -128,6 +131,7 @@ Next, find the `providers` section, and add `auth0` there as well: ``` Although it is enabled by default, now is a good time to ensure the `StartSession` middleware is enabled in your `app/Http/Kernel.php` file: + ```php protected $middlewareGroups = [ 'web' => [ @@ -178,6 +182,7 @@ Route::get('/', function () { ``` > Note that the `example.user.template` and `example.guest.templates` views are just examples and are not part of the SDK; replace these as appropriate for your application. +
@@ -220,20 +225,21 @@ Route::get('/api/public', function () { ], 200, [], JSON_PRETTY_PRINT); })->middleware(['auth0.authorize.optional']); ``` +
## Support Policy Our support windows are determined by the [Laravel release support](https://laravel.com/docs/releases#support-policy) and [PHP release support](https://www.php.net/supported-versions.php) schedules, and support ends when either the Laravel framework or PHP runtime outlined below stop receiving security fixes, whichever may come first. -| SDK Version | Laravel Version | PHP Version | Support Ends | -|-------------|------------------|--------------|---------------| -| 7 | 9 | 8.1 | Feb 2024 | -| | | 8.0 | Nov 2023 | -| | 8 | 8.1 | Jan 2023 | -| | | 8.0 | Jan 2023 | -| 6 | 8 | 8.1 | Jan 2023 | -| | | 8.0 | Jan 2023 | +| SDK Version | Laravel Version | PHP Version | Support Ends | +| ----------- | --------------- | ----------- | ------------ | +| 7 | 9 | 8.1 | Feb 2024 | +| | | 8.0 | Nov 2023 | +| | 8 | 8.1 | Jan 2023 | +| | | 8.0 | Jan 2023 | +| 6 | 8 | 8.1 | Jan 2023 | +| | | 8.0 | Jan 2023 | Deprecations of EOL'd language or framework versions are not considered a breaking change, as Composer handles these scenarios elegantly. Legacy applications will stop receiving updates from us, but will continue to function on those unsupported SDK versions. Please ensure your PHP environment and Laravel framework dependencies always remain up to date. @@ -251,13 +257,15 @@ Feedback and bug fix contributions are greatly appreciated as we work toward ful We appreciate feedback and contribution to this repo! Before you get started, please see the following: -- [Auth0's general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) -- [Auth0's code of conduct guidelines](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) +- [Auth0's general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) +- [Auth0's code of conduct guidelines](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) ### Raise an issue + To provide feedback or report a bug, [please raise an issue on our issue tracker](https://github.com/auth0/laravel-auth0/issues). ### Vulnerability Reporting + Please do not report security vulnerabilities on the public Github issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. --- From 4473a5241dd5287a61ec267a4a1ab5bc3266eed5 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:14:49 -0500 Subject: [PATCH 194/525] Update README.md --- README.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f5a2b572..a3508702 100644 --- a/README.md +++ b/README.md @@ -23,16 +23,23 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. ### Requirements - PHP 8.0+ -- Laravel 8 / Laravel 9 -- `Illuminate\Session\Middleware\StartSession` enabled in `app/Http/Kernel.php` - -> Please review our [support policy](#support-policy) to learn when language and framework versions will exit support in the future. +- [Composer](https://getcomposer.org/) +- Laravel 9.x/10.x + - `Illuminate\Session\Middleware\StartSession` enabled in `app/Http/Kernel.php` +- PHP Extensions: + - [mbstring](https://www.php.net/manual/en/book.mbstring.php) +- Dependencies: + - [PSR-18 HTTP Client implementation](./FAQ.md#what-is-psr-18) + - [PSR-17 HTTP Factory implementation](./FAQ.md#what-is-psr-17) + - [PSR-7 HTTP Messages implementation](./FAQ.md#what-is-psr-7) + +> Please review our [support policy](#support-policy) for details on our PHP and Laravel version support. > [Octane support](#octane-support) is experimental and not advisable for use in production at this time. ### Installation -Add the dependency to your application with [Composer](https://getcomposer.org/): +Ensure you have [the necessary dependencies](#requirements) installed, then add the SDK to your application using [Composer](https://getcomposer.org/): ``` composer require auth0/login From a6837d2f30bbc71d4d4ef3236537f1adabfaea2d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:15:29 -0500 Subject: [PATCH 195/525] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a3508702..babcb9fd 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,9 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. - PHP Extensions: - [mbstring](https://www.php.net/manual/en/book.mbstring.php) - Dependencies: - - [PSR-18 HTTP Client implementation](./FAQ.md#what-is-psr-18) - - [PSR-17 HTTP Factory implementation](./FAQ.md#what-is-psr-17) - - [PSR-7 HTTP Messages implementation](./FAQ.md#what-is-psr-7) + - [PSR-18 HTTP Client implementation](https://github.com/auth0/laravel-auth0/FAQ.md#what-is-psr-18) + - [PSR-17 HTTP Factory implementation](https://github.com/auth0/laravel-auth0/FAQ.md#what-is-psr-17) + - [PSR-7 HTTP Messages implementation](https://github.com/auth0/laravel-auth0/FAQ.md#what-is-psr-7) > Please review our [support policy](#support-policy) for details on our PHP and Laravel version support. From 54debfe622ebdc32f3cb84264801c105d6af1272 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:16:08 -0500 Subject: [PATCH 196/525] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index babcb9fd..a8b4fbb1 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,9 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. - PHP Extensions: - [mbstring](https://www.php.net/manual/en/book.mbstring.php) - Dependencies: - - [PSR-18 HTTP Client implementation](https://github.com/auth0/laravel-auth0/FAQ.md#what-is-psr-18) - - [PSR-17 HTTP Factory implementation](https://github.com/auth0/laravel-auth0/FAQ.md#what-is-psr-17) - - [PSR-7 HTTP Messages implementation](https://github.com/auth0/laravel-auth0/FAQ.md#what-is-psr-7) + - [PSR-18 HTTP Client implementation](https://github.com/auth0/auth0-PHP/FAQ.md#what-is-psr-18) + - [PSR-17 HTTP Factory implementation](https://github.com/auth0/auth0-PHP/FAQ.md#what-is-psr-17) + - [PSR-7 HTTP Messages implementation](https://github.com/auth0/auth0-PHP/FAQ.md#what-is-psr-7) > Please review our [support policy](#support-policy) for details on our PHP and Laravel version support. From 80cddb639a62f7b3399a9901c51e5d875943e5df Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:19:06 -0500 Subject: [PATCH 197/525] Update README.md --- README.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a8b4fbb1..3a81e6fd 100644 --- a/README.md +++ b/README.md @@ -241,12 +241,10 @@ Our support windows are determined by the [Laravel release support](https://lara | SDK Version | Laravel Version | PHP Version | Support Ends | | ----------- | --------------- | ----------- | ------------ | -| 7 | 9 | 8.1 | Feb 2024 | +| 7.5+ | 10 | 8.2 | Feb 2024 | +| 7.0+ | 9 | 8.2 | Feb 2024 | +| | | 8.1 | Feb 2024 | | | | 8.0 | Nov 2023 | -| | 8 | 8.1 | Jan 2023 | -| | | 8.0 | Jan 2023 | -| 6 | 8 | 8.1 | Jan 2023 | -| | | 8.0 | Jan 2023 | Deprecations of EOL'd language or framework versions are not considered a breaking change, as Composer handles these scenarios elegantly. Legacy applications will stop receiving updates from us, but will continue to function on those unsupported SDK versions. Please ensure your PHP environment and Laravel framework dependencies always remain up to date. @@ -254,7 +252,7 @@ Deprecations of EOL'd language or framework versions are not considered a breaki Octane compatibility is currently considered experimental and unsupported. -Although we are working toward ensuring the SDK is fully compatible with this feature, we do not recommend using this with our SDK in production until we have full confidence and announced support. Due to the aggressive changes Octane makes to Laravel's core behavior, there is opportunity for problems we haven't fully identified or resolved yet. +Although we are working toward ensuring the SDK is fully compatible with this feature, we do not recommend using this with our SDK in production until we have full confidence and announced support. Due to the aggressive changes Octane makes to Laravel's core behavior, there is an opportunity for problems we haven't fully identified or resolved yet. Feedback and bug fix contributions are greatly appreciated as we work toward full. Octane support. @@ -273,7 +271,7 @@ To provide feedback or report a bug, [please raise an issue on our issue tracker ### Vulnerability Reporting -Please do not report security vulnerabilities on the public Github issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. +Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. --- @@ -285,6 +283,6 @@ Please do not report security vulnerabilities on the public Github issue tracker

-

Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout Why Auth0?

+

Auth0 is an easy-to-implement, adaptable authentication and authorization platform.
To learn more, check out "Why Auth0?"

This project is licensed under the MIT license. See the LICENSE file for more info.

From adfa3c79a3241ae6d495263194b5a6a8edd24aa9 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:20:48 -0500 Subject: [PATCH 198/525] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3a81e6fd..7dbc127d 100644 --- a/README.md +++ b/README.md @@ -237,7 +237,7 @@ Route::get('/api/public', function () { ## Support Policy -Our support windows are determined by the [Laravel release support](https://laravel.com/docs/releases#support-policy) and [PHP release support](https://www.php.net/supported-versions.php) schedules, and support ends when either the Laravel framework or PHP runtime outlined below stop receiving security fixes, whichever may come first. +Our support lifecycle mirrors the [Laravel release support](https://laravel.com/docs/releases#support-policy) and [PHP release support schedule](https://www.php.net/supported-versions.php). | SDK Version | Laravel Version | PHP Version | Support Ends | | ----------- | --------------- | ----------- | ------------ | @@ -246,7 +246,7 @@ Our support windows are determined by the [Laravel release support](https://lara | | | 8.1 | Feb 2024 | | | | 8.0 | Nov 2023 | -Deprecations of EOL'd language or framework versions are not considered a breaking change, as Composer handles these scenarios elegantly. Legacy applications will stop receiving updates from us, but will continue to function on those unsupported SDK versions. Please ensure your PHP environment and Laravel framework dependencies always remain up to date. +We drop support for Laravel and PHP versions when they reach end-of-life and cease receiving security fixes from Laravel and the PHP Foundation, whichever comes first. Please ensure your environment remains up to date so you can continue receiving updates for PHP and this SDK. ## Octane Support From 79e074d04933d24d304e03d95856b48af7f32327 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:21:24 -0500 Subject: [PATCH 199/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7dbc127d..5186b498 100644 --- a/README.md +++ b/README.md @@ -246,7 +246,7 @@ Our support lifecycle mirrors the [Laravel release support](https://laravel.com/ | | | 8.1 | Feb 2024 | | | | 8.0 | Nov 2023 | -We drop support for Laravel and PHP versions when they reach end-of-life and cease receiving security fixes from Laravel and the PHP Foundation, whichever comes first. Please ensure your environment remains up to date so you can continue receiving updates for PHP and this SDK. +We drop support for Laravel and PHP versions when they reach end-of-life and cease receiving security fixes from Laravel and the PHP Foundation, whichever comes first. Please ensure your environment remains up to date so you can continue receiving updates for Laravel, PHP, and this SDK. ## Octane Support From 887f2e2c6f21f068b72b66256016e0dd16faa6f1 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:21:53 -0500 Subject: [PATCH 200/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5186b498..1b5aaac1 100644 --- a/README.md +++ b/README.md @@ -237,7 +237,7 @@ Route::get('/api/public', function () { ## Support Policy -Our support lifecycle mirrors the [Laravel release support](https://laravel.com/docs/releases#support-policy) and [PHP release support schedule](https://www.php.net/supported-versions.php). +Our support lifecycle mirrors the [Laravel release support](https://laravel.com/docs/releases#support-policy) and [PHP release support](https://www.php.net/supported-versions.php) schedules. | SDK Version | Laravel Version | PHP Version | Support Ends | | ----------- | --------------- | ----------- | ------------ | From dcf398c301ff751d7eb46a3a9055ebc76735959f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:22:44 -0500 Subject: [PATCH 201/525] Update CHANGELOG.md --- CHANGELOG.md | 302 +++++++++++++++++++++++++++------------------------ 1 file changed, 160 insertions(+), 142 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ac453e3..24d1239e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,59 +1,75 @@ -# Change Log +# Changelog + +## [Unreleased] ## [7.4.0](https://github.com/auth0/laravel-auth0/tree/7.4.0) (2022-12-12) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.3.0...7.4.0) **Added** -- feat: Add `Auth0\Laravel\Event\Middleware\...` event hooks [\#340](https://github.com/auth0/laravel-auth0/pull/340) ([evansims](https://github.com/evansims)) -- feat: Add `Auth0\Laravel\Event\Configuration\Building` event hook [\#339](https://github.com/auth0/laravel-auth0/pull/339) ([evansims](https://github.com/evansims)) + +- feat: Add `Auth0\Laravel\Event\Middleware\...` event hooks [\#340](https://github.com/auth0/laravel-auth0/pull/340) ([evansims](https://github.com/evansims)) +- feat: Add `Auth0\Laravel\Event\Configuration\Building` event hook [\#339](https://github.com/auth0/laravel-auth0/pull/339) ([evansims](https://github.com/evansims)) ## [7.3.0](https://github.com/auth0/laravel-auth0/tree/7.3.0) (2022-11-07) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.2.2...7.3.0) **Added** -- add: Raise additional Laravel Auth Events [\#331](https://github.com/auth0/laravel-auth0/pull/331) ([evansims](https://github.com/evansims)) + +- add: Raise additional Laravel Auth Events [\#331](https://github.com/auth0/laravel-auth0/pull/331) ([evansims](https://github.com/evansims)) **Fixed** -- fix: `env()` incorrectly assigns `cookieExpires` to a `string` value [\#332](https://github.com/auth0/laravel-auth0/pull/332) ([evansims](https://github.com/evansims)) -- fix: Auth0\Laravel\Cache\LaravelCachePool::createItem returning a cache miss [\#329](https://github.com/auth0/laravel-auth0/pull/329) ([pkivits-litebit](https://github.com/pkivits-litebit)) + +- fix: `env()` incorrectly assigns `cookieExpires` to a `string` value [\#332](https://github.com/auth0/laravel-auth0/pull/332) ([evansims](https://github.com/evansims)) +- fix: Auth0\Laravel\Cache\LaravelCachePool::createItem returning a cache miss [\#329](https://github.com/auth0/laravel-auth0/pull/329) ([pkivits-litebit](https://github.com/pkivits-litebit)) ## [7.2.2](https://github.com/auth0/laravel-auth0/tree/7.2.2) (2022-10-19) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.2.1...7.2.2) **Fixed** -- [SDK-3720] Restore `php artisan vendor:publish` command [\#321](https://github.com/auth0/laravel-auth0/pull/321) ([evansims](https://github.com/evansims)) -- [SDK-3721] Bump minimum `auth0/auth0-php` version to `^8.3.4` [\#322](https://github.com/auth0/laravel-auth0/pull/322) ([evansims](https://github.com/evansims)) + +- [SDK-3720] Restore `php artisan vendor:publish` command [\#321](https://github.com/auth0/laravel-auth0/pull/321) ([evansims](https://github.com/evansims)) +- [SDK-3721] Bump minimum `auth0/auth0-php` version to `^8.3.4` [\#322](https://github.com/auth0/laravel-auth0/pull/322) ([evansims](https://github.com/evansims)) ## [7.2.1](https://github.com/auth0/laravel-auth0/tree/7.2.1) (2022-10-13) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.2.0...7.2.1) **Fixed** -- `Auth0\Laravel\Auth0` no longer requires a session configuration for stateless strategies, restoring previous behavior. [\#317](https://github.com/auth0/laravel-auth0/pull/317) ([evansims](https://github.com/evansims)) -- The SDK now requires `^3.0` of the `psr/cache` dependency, to accomodate breaking changes made in the upstream interface (typed parameters and return types) for PHP 8.0+. [\#316](https://github.com/auth0/laravel-auth0/pull/316) ([evansims](https://github.com/evansims)) + +- `Auth0\Laravel\Auth0` no longer requires a session configuration for stateless strategies, restoring previous behavior. [\#317](https://github.com/auth0/laravel-auth0/pull/317) ([evansims](https://github.com/evansims)) +- The SDK now requires `^3.0` of the `psr/cache` dependency, to accomodate breaking changes made in the upstream interface (typed parameters and return types) for PHP 8.0+. [\#316](https://github.com/auth0/laravel-auth0/pull/316) ([evansims](https://github.com/evansims)) ## [7.2.0](https://github.com/auth0/laravel-auth0/tree/7.2.0) (2022-10-10) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.1.0...7.2.0) Thank you to [tonyfox-disguise](https://github.com/tonyfox-disguise), [jeovajr](https://github.com/jeovajr) and [nie7321](https://github.com/nie7321) for their contributions to this release. **Changed** -- `Auth0\Laravel\Store\LaravelSession` has been added as the default `sessionStorage` and `transientStorage` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Session APIs](https://laravel.com/docs/9.x/session) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims))¹ -- `Auth0\Laravel\Cache\LaravelCachePool` and `Auth0\Laravel\Cache\LaravelCacheItem` have been added as the default `tokenCache` and `managementTokenCache` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Cache APIs](https://laravel.com/docs/9.x/cache) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims)) -- `Auth0\Laravel\Auth\Guard` now supports the `viaRemember` method. [\#306](https://github.com/auth0/laravel-auth0/pull/306) ([tonyfox-disguise](https://github.com/tonyfox-disguise)) -- `Auth0\Laravel\Http\Middleware\Stateless\Authorize` now returns a 401 status instead of 403 for unauthenticated users. [\#304](https://github.com/auth0/laravel-auth0/issues/304) ([jeovajr](https://github.com/jeovajr)) -- PHP 8.0 is now the minimum supported runtime version. Please review the [README](README.md) for more information on support windows. + +- `Auth0\Laravel\Store\LaravelSession` has been added as the default `sessionStorage` and `transientStorage` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Session APIs](https://laravel.com/docs/9.x/session) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims))¹ +- `Auth0\Laravel\Cache\LaravelCachePool` and `Auth0\Laravel\Cache\LaravelCacheItem` have been added as the default `tokenCache` and `managementTokenCache` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Cache APIs](https://laravel.com/docs/9.x/cache) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims)) +- `Auth0\Laravel\Auth\Guard` now supports the `viaRemember` method. [\#306](https://github.com/auth0/laravel-auth0/pull/306) ([tonyfox-disguise](https://github.com/tonyfox-disguise)) +- `Auth0\Laravel\Http\Middleware\Stateless\Authorize` now returns a 401 status instead of 403 for unauthenticated users. [\#304](https://github.com/auth0/laravel-auth0/issues/304) ([jeovajr](https://github.com/jeovajr)) +- PHP 8.0 is now the minimum supported runtime version. Please review the [README](README.md) for more information on support windows. ¹ This change may require your application's users to re-authenticate. You can avoid this by changing the `sessionStorage` and `transientStorage` options in your SDK configuration to their previous default instances of `Auth0\SDK\Store\CookieStore`, but it is recommended you migrate to the new `LaravelSession` default. ## [7.1.0](https://github.com/auth0/laravel-auth0/tree/7.1.0) (2022-08-08) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.0.1...7.1.0) **Changed** -- [SDK-3576] Return interfaces instead of concrete classes [\#296](https://github.com/auth0/laravel-auth0/pull/296) ([evansims](https://github.com/evansims)) -- change: Use class names for app() calls [\#291](https://github.com/auth0/laravel-auth0/pull/291) ([evansims](https://github.com/evansims)) + +- [SDK-3576] Return interfaces instead of concrete classes [\#296](https://github.com/auth0/laravel-auth0/pull/296) ([evansims](https://github.com/evansims)) +- change: Use class names for app() calls [\#291](https://github.com/auth0/laravel-auth0/pull/291) ([evansims](https://github.com/evansims)) **Fixed** -- [SDK-3585] Fix: `Missing Code` error on Callback Route for Octane Customers [\#297](https://github.com/auth0/laravel-auth0/pull/297) ([evansims](https://github.com/evansims)) + +- [SDK-3585] Fix: `Missing Code` error on Callback Route for Octane Customers [\#297](https://github.com/auth0/laravel-auth0/pull/297) ([evansims](https://github.com/evansims)) ## [7.0.1](https://github.com/auth0/laravel-auth0/tree/7.0.1) (2022-06-01) @@ -61,10 +77,11 @@ Thank you to [tonyfox-disguise](https://github.com/tonyfox-disguise), [jeovajr]( **Fixed** -- Fixed an issue in `Auth0\Laravel\Http\Controller\Stateful\Callback` where `$errorDescription`'s value was assigned an incorrect value when an error was encountered. [\#266](https://github.com/auth0/laravel-auth0/pull/288) ([evansims](https://github.com/evansims)) +- Fixed an issue in `Auth0\Laravel\Http\Controller\Stateful\Callback` where `$errorDescription`'s value was assigned an incorrect value when an error was encountered. [\#266](https://github.com/auth0/laravel-auth0/pull/288) ([evansims](https://github.com/evansims)) **Closed Issues** -- Resolves [\#287](https://github.com/auth0/laravel-auth0/issues/287) ([piljac1](https://github.com/piljac1)) + +- Resolves [\#287](https://github.com/auth0/laravel-auth0/issues/287) ([piljac1](https://github.com/piljac1)) ## [7.0.0](https://github.com/auth0/laravel-auth0/tree/7.0.0) (2022-03-21) @@ -72,21 +89,21 @@ Thank you to [tonyfox-disguise](https://github.com/tonyfox-disguise), [jeovajr]( Auth0 Laravel SDK v7 includes many significant changes over previous versions: -- Support for Laravel 9. -- Support for Auth0-PHP SDK 8. -- New authentication route controllers for plug-and-play login support. -- Improved authentication middleware for regular web applications. -- New authorization middleware for token-based backend API applications. +- Support for Laravel 9. +- Support for Auth0-PHP SDK 8. +- New authentication route controllers for plug-and-play login support. +- Improved authentication middleware for regular web applications. +- New authorization middleware for token-based backend API applications. As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes. Please review the [upgrade guide](UPGRADE.md) thoroughly to understand the changes required to migrate your application to v7. **Breaking Changes Summary** -- Namespace has been updated from `Auth0\Login` to `Auth0\Laravel` -- Auth0-PHP SDK dependency updated to V8 -- New configuration format -- SDK now self-registers its services and middleware -- New UserProvider API +- Namespace has been updated from `Auth0\Login` to `Auth0\Laravel` +- Auth0-PHP SDK dependency updated to V8 +- New configuration format +- SDK now self-registers its services and middleware +- New UserProvider API ## [7.0.0-BETA2](https://github.com/auth0/laravel-auth0/tree/7.0.0-BETA2) (2022-03-09) @@ -95,9 +112,10 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes Please review the [BETA1 changelog notes below](#700-beta1-2022-02-08) before upgrading your application from 6.x, as 7.0 is a new major containing breaking changes. As with all beta releases, this should not be considered stable or suitable for production use, but your experimentation with and feedback around it is greatly appreciated. **Changes** -- Update Middleware interface checks for custom user model types [\#263](https://github.com/auth0/laravel-auth0/pull/263) ([sheggi](https://github.com/sheggi)) -- Updated UserProvider API [\#264](https://github.com/auth0/laravel-auth0/pull/264) ([evansims](https://github.com/evansims)) -- Add Rector to test suite [\#265](https://github.com/auth0/laravel-auth0/pull/265) ([evansims](https://github.com/evansims)) + +- Update Middleware interface checks for custom user model types [\#263](https://github.com/auth0/laravel-auth0/pull/263) ([sheggi](https://github.com/sheggi)) +- Updated UserProvider API [\#264](https://github.com/auth0/laravel-auth0/pull/264) ([evansims](https://github.com/evansims)) +- Add Rector to test suite [\#265](https://github.com/auth0/laravel-auth0/pull/265) ([evansims](https://github.com/evansims)) ## [7.0.0-BETA1](https://github.com/auth0/laravel-auth0/tree/7.0.0-BETA1) (2022-02-08) @@ -105,20 +123,20 @@ Please review the [BETA1 changelog notes below](#700-beta1-2022-02-08) before up Auth0 Laravel SDK v7 includes many significant changes over previous versions: -- Support for Laravel 9. -- Support for Auth0-PHP SDK 8. -- New authentication route controllers for plug-and-play login support. -- Improved authentication middleware for regular web applications. -- New authorization middleware for token-based backend API applications. +- Support for Laravel 9. +- Support for Auth0-PHP SDK 8. +- New authentication route controllers for plug-and-play login support. +- Improved authentication middleware for regular web applications. +- New authorization middleware for token-based backend API applications. As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes. Please review the [upgrade guide](UPGRADE.md) thoroughly to understand the changes required to migrate your application to v7. **Breaking Changes Summary** -- Namespace has been updated from `Auth0\Login` to `Auth0\Laravel` -- Auth0-PHP SDK dependency updated to V8 -- New configuration format -- SDK now self-registers its services and middleware +- Namespace has been updated from `Auth0\Login` to `Auth0\Laravel` +- Auth0-PHP SDK dependency updated to V8 +- New configuration format +- SDK now self-registers its services and middleware ## [6.5.0](https://github.com/auth0/laravel-auth0/tree/6.5.0) (2021-10-15) @@ -126,7 +144,7 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes **Added** -- Add SDK alias methods for passwordless endpoints [\#228](https://github.com/auth0/laravel-auth0/pull/228) ([evansims](https://github.com/evansims)) +- Add SDK alias methods for passwordless endpoints [\#228](https://github.com/auth0/laravel-auth0/pull/228) ([evansims](https://github.com/evansims)) ## [6.4.1](https://github.com/auth0/laravel-auth0/tree/6.4.0) (2021-08-02) @@ -134,9 +152,9 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes **Fixed** -- Use the fully qualified facade class names [\#215](https://github.com/auth0/laravel-auth0/pull/215) ([Rezouce](https://github.com/Rezouce)) -- Update auth0-PHP dependency [\#222](https://github.com/auth0/laravel-auth0/pull/222) ([evansims](https://github.com/evansims)) -- Pass api_identifier config as audience to Auth0\SDK\Auth0 [\#214](https://github.com/auth0/laravel-auth0/pull/214) ([iSerter](https://github.com/iSerter)) +- Use the fully qualified facade class names [\#215](https://github.com/auth0/laravel-auth0/pull/215) ([Rezouce](https://github.com/Rezouce)) +- Update auth0-PHP dependency [\#222](https://github.com/auth0/laravel-auth0/pull/222) ([evansims](https://github.com/evansims)) +- Pass api_identifier config as audience to Auth0\SDK\Auth0 [\#214](https://github.com/auth0/laravel-auth0/pull/214) ([iSerter](https://github.com/iSerter)) ## [6.4.0](https://github.com/auth0/laravel-auth0/tree/6.4.0) (2021-03-25) @@ -144,7 +162,7 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes **Changed** -- Add support for Auth0 Organizations [\#209](https://github.com/auth0/laravel-auth0/pull/209) ([evansims](https://github.com/evansims)) +- Add support for Auth0 Organizations [\#209](https://github.com/auth0/laravel-auth0/pull/209) ([evansims](https://github.com/evansims)) ## [6.3.0](https://github.com/auth0/laravel-auth0/tree/6.3.0) (2020-02-18) @@ -152,11 +170,11 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes **Changed** -- Store changes made to the user object during the onLogin event hook [\#206](https://github.com/auth0/laravel-auth0/pull/206) ([evansims](https://github.com/evansims)) +- Store changes made to the user object during the onLogin event hook [\#206](https://github.com/auth0/laravel-auth0/pull/206) ([evansims](https://github.com/evansims)) **Fixed** -- Avoid throwing an error when calling getUserByUserInfo() during login callback event when the supplied profile is empty/null [\#207](https://github.com/auth0/laravel-auth0/pull/207) ([evansims](https://github.com/evansims)) +- Avoid throwing an error when calling getUserByUserInfo() during login callback event when the supplied profile is empty/null [\#207](https://github.com/auth0/laravel-auth0/pull/207) ([evansims](https://github.com/evansims)) ## [6.2.0](https://github.com/auth0/laravel-auth0/tree/6.2.0) (2020-01-15) @@ -164,11 +182,11 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes **Added** -- Support PHP 8.0 [\#200](https://github.com/auth0/laravel-auth0/pull/200) ([evansims](https://github.com/evansims)) +- Support PHP 8.0 [\#200](https://github.com/auth0/laravel-auth0/pull/200) ([evansims](https://github.com/evansims)) **Fixed** -- Fix the missing `return null;` in `getUserByIdentifier` [\#201](https://github.com/auth0/laravel-auth0/pull/201) ([sebwas](https://github.com/sebwas)) +- Fix the missing `return null;` in `getUserByIdentifier` [\#201](https://github.com/auth0/laravel-auth0/pull/201) ([sebwas](https://github.com/sebwas)) ## [6.1.0](https://github.com/auth0/laravel-auth0/tree/6.1.0) (2020-09-17) @@ -176,11 +194,11 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes **Added** -- Support Laravel 8 [\#190](https://github.com/auth0/laravel-auth0/pull/190) ([giannidhooge](https://github.com/giannidhooge)) +- Support Laravel 8 [\#190](https://github.com/auth0/laravel-auth0/pull/190) ([giannidhooge](https://github.com/giannidhooge)) **Fixed** -- Fix composer.json whitespace issue [\#192](https://github.com/auth0/laravel-auth0/pull/192) ([jimmyjames](https://github.com/jimmyjames)) +- Fix composer.json whitespace issue [\#192](https://github.com/auth0/laravel-auth0/pull/192) ([jimmyjames](https://github.com/jimmyjames)) ## [6.0.1](https://github.com/auth0/laravel-auth0/tree/6.0.1) (2020-04-28) @@ -188,7 +206,7 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes **Fixed** -- Fix access token decoding and validation [\#183](https://github.com/auth0/laravel-auth0/pull/183) ([jimmyjames](https://github.com/jimmyjames)) +- Fix access token decoding and validation [\#183](https://github.com/auth0/laravel-auth0/pull/183) ([jimmyjames](https://github.com/jimmyjames)) ## [6.0.0](https://github.com/auth0/laravel-auth0/tree/6.0.0) (2020-04-09) @@ -198,22 +216,22 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes **Closed issues** -- auth0-PHP 7.0 - State and nonce handling [\#163](https://github.com/auth0/laravel-auth0/issues/163) -- Cannot use actingAs unit tests functionality [\#161](https://github.com/auth0/laravel-auth0/issues/161) +- auth0-PHP 7.0 - State and nonce handling [\#163](https://github.com/auth0/laravel-auth0/issues/163) +- Cannot use actingAs unit tests functionality [\#161](https://github.com/auth0/laravel-auth0/issues/161) **Added** -- Implement auth0 guard [\#166](https://github.com/auth0/laravel-auth0/pull/166) ([Tamrael](https://github.com/Tamrael)) +- Implement auth0 guard [\#166](https://github.com/auth0/laravel-auth0/pull/166) ([Tamrael](https://github.com/Tamrael)) **Changed** -- Use array for Auth0JWTUser and add repo return types [\#176](https://github.com/auth0/laravel-auth0/pull/176) ([joshcanhelp](https://github.com/joshcanhelp)) -- Update PHP SDK to v7.0.0 [\#162](https://github.com/auth0/laravel-auth0/pull/162) ([joshcanhelp](https://github.com/joshcanhelp)) -- Bind SessionState handler interface in container [\#147](https://github.com/auth0/laravel-auth0/pull/147) ([nstapelbroek](https://github.com/nstapelbroek)) +- Use array for Auth0JWTUser and add repo return types [\#176](https://github.com/auth0/laravel-auth0/pull/176) ([joshcanhelp](https://github.com/joshcanhelp)) +- Update PHP SDK to v7.0.0 [\#162](https://github.com/auth0/laravel-auth0/pull/162) ([joshcanhelp](https://github.com/joshcanhelp)) +- Bind SessionState handler interface in container [\#147](https://github.com/auth0/laravel-auth0/pull/147) ([nstapelbroek](https://github.com/nstapelbroek)) **Fixed** -- Fix Laravel session management [\#174](https://github.com/auth0/laravel-auth0/pull/174) ([joshcanhelp](https://github.com/joshcanhelp)) +- Fix Laravel session management [\#174](https://github.com/auth0/laravel-auth0/pull/174) ([joshcanhelp](https://github.com/joshcanhelp)) ## [5.4.0](https://github.com/auth0/laravel-auth0/tree/5.4.0) (2020-03-27) @@ -221,15 +239,15 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes **Closed issues** -- Laravel 7.0 supported release. [\#171](https://github.com/auth0/laravel-auth0/issues/171) +- Laravel 7.0 supported release. [\#171](https://github.com/auth0/laravel-auth0/issues/171) **Fixed** -- Fixed PHPDocs [\#170](https://github.com/auth0/laravel-auth0/pull/170) ([YAhiru](https://github.com/YAhiru)) +- Fixed PHPDocs [\#170](https://github.com/auth0/laravel-auth0/pull/170) ([YAhiru](https://github.com/YAhiru)) **Added** -- Laravel 7 support [\#167](https://github.com/auth0/laravel-auth0/pull/167) ([giannidhooge](https://github.com/giannidhooge)) +- Laravel 7 support [\#167](https://github.com/auth0/laravel-auth0/pull/167) ([giannidhooge](https://github.com/giannidhooge)) ## [5.3.1](https://github.com/auth0/laravel-auth0/tree/5.3.1) (2019-11-14) @@ -237,13 +255,13 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes **Closed issues** -- Setting of state_handler in Auth0Service causes "Invalid state" error [\#154](https://github.com/auth0/laravel-auth0/issues/154) +- Setting of state_handler in Auth0Service causes "Invalid state" error [\#154](https://github.com/auth0/laravel-auth0/issues/154) **Fixed** -- Allow store and state_handler to be passed in from config [\#156](https://github.com/auth0/laravel-auth0/pull/156) ([joshcanhelp](https://github.com/joshcanhelp)) -- Add 'persist_refresh_token' key to laravel-auth0 configuration file. [\#152](https://github.com/auth0/laravel-auth0/pull/152) ([tpenaranda](https://github.com/tpenaranda)) -- Replace `setEnvironment` with `setEnvProperty` [\#145](https://github.com/auth0/laravel-auth0/pull/145) ([nstapelbroek](https://github.com/nstapelbroek)) +- Allow store and state_handler to be passed in from config [\#156](https://github.com/auth0/laravel-auth0/pull/156) ([joshcanhelp](https://github.com/joshcanhelp)) +- Add 'persist_refresh_token' key to laravel-auth0 configuration file. [\#152](https://github.com/auth0/laravel-auth0/pull/152) ([tpenaranda](https://github.com/tpenaranda)) +- Replace `setEnvironment` with `setEnvProperty` [\#145](https://github.com/auth0/laravel-auth0/pull/145) ([nstapelbroek](https://github.com/nstapelbroek)) ## [5.3.0](https://github.com/auth0/laravel-auth0/tree/5.3.0) (2019-09-26) @@ -251,16 +269,16 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes **Closed issues** -- Feature request: Add Laravel 6 support [\#138](https://github.com/auth0/laravel-auth0/issues/138) -- SessionStateHandler should use LaravelSessionStore not SessionStore [\#125](https://github.com/auth0/laravel-auth0/issues/125) +- Feature request: Add Laravel 6 support [\#138](https://github.com/auth0/laravel-auth0/issues/138) +- SessionStateHandler should use LaravelSessionStore not SessionStore [\#125](https://github.com/auth0/laravel-auth0/issues/125) **Added** -- Support Laravel 6 [\#139](https://github.com/auth0/laravel-auth0/pull/139) ([FreekVR](https://github.com/FreekVR)) +- Support Laravel 6 [\#139](https://github.com/auth0/laravel-auth0/pull/139) ([FreekVR](https://github.com/FreekVR)) **Fixed** -- Use LaravelSessionStore in the SessionStateHandler. [\#135](https://github.com/auth0/laravel-auth0/pull/135) ([nstapelbroek](https://github.com/nstapelbroek)) +- Use LaravelSessionStore in the SessionStateHandler. [\#135](https://github.com/auth0/laravel-auth0/pull/135) ([nstapelbroek](https://github.com/nstapelbroek)) ## [5.2.0](https://github.com/auth0/laravel-auth0/tree/5.2.0) (2019-06-27) @@ -268,36 +286,36 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes **Closed issues** -- Authenticate as a Laravel API user using the Auth0 token [\#129](https://github.com/auth0/laravel-auth0/issues/129) -- Redirect to previous page after login [\#122](https://github.com/auth0/laravel-auth0/issues/122) -- Auth0User uses private variables so they cannot be accessed or overridden in child class [\#120](https://github.com/auth0/laravel-auth0/issues/120) -- API routes broken in auth0-laravel-php-web-app (and in general)? [\#117](https://github.com/auth0/laravel-auth0/issues/117) -- API returning "token algorithm not supported" [\#116](https://github.com/auth0/laravel-auth0/issues/116) -- Changing name of user identifier [\#115](https://github.com/auth0/laravel-auth0/issues/115) -- Possible to use User object functions? [\#114](https://github.com/auth0/laravel-auth0/issues/114) -- Auth0-PHP@5.3.1 breaks Laravel-Auth0 [\#108](https://github.com/auth0/laravel-auth0/issues/108) -- Extend Illuminate\Foundation\Auth\User [\#104](https://github.com/auth0/laravel-auth0/issues/104) -- [Bug] Inconsistencies with the singleton Auth0Service [\#103](https://github.com/auth0/laravel-auth0/issues/103) -- How do you combine Auth0 Lock with Laravel Auth0? [\#102](https://github.com/auth0/laravel-auth0/issues/102) -- OnLogin callback question [\#97](https://github.com/auth0/laravel-auth0/issues/97) +- Authenticate as a Laravel API user using the Auth0 token [\#129](https://github.com/auth0/laravel-auth0/issues/129) +- Redirect to previous page after login [\#122](https://github.com/auth0/laravel-auth0/issues/122) +- Auth0User uses private variables so they cannot be accessed or overridden in child class [\#120](https://github.com/auth0/laravel-auth0/issues/120) +- API routes broken in auth0-laravel-php-web-app (and in general)? [\#117](https://github.com/auth0/laravel-auth0/issues/117) +- API returning "token algorithm not supported" [\#116](https://github.com/auth0/laravel-auth0/issues/116) +- Changing name of user identifier [\#115](https://github.com/auth0/laravel-auth0/issues/115) +- Possible to use User object functions? [\#114](https://github.com/auth0/laravel-auth0/issues/114) +- Auth0-PHP@5.3.1 breaks Laravel-Auth0 [\#108](https://github.com/auth0/laravel-auth0/issues/108) +- Extend Illuminate\Foundation\Auth\User [\#104](https://github.com/auth0/laravel-auth0/issues/104) +- [Bug] Inconsistencies with the singleton Auth0Service [\#103](https://github.com/auth0/laravel-auth0/issues/103) +- How do you combine Auth0 Lock with Laravel Auth0? [\#102](https://github.com/auth0/laravel-auth0/issues/102) +- OnLogin callback question [\#97](https://github.com/auth0/laravel-auth0/issues/97) **Added** -- Add composer.lock file [\#123](https://github.com/auth0/laravel-auth0/pull/123) ([lbalmaceda](https://github.com/lbalmaceda)) +- Add composer.lock file [\#123](https://github.com/auth0/laravel-auth0/pull/123) ([lbalmaceda](https://github.com/lbalmaceda)) **Changed** -- Change private properties to protected [\#132](https://github.com/auth0/laravel-auth0/pull/132) ([joshcanhelp](https://github.com/joshcanhelp)) -- Return null instead of false in Auth0UserProvider. [\#128](https://github.com/auth0/laravel-auth0/pull/128) ([afreakk](https://github.com/afreakk)) -- Change the visibility of the getter method from private to public [\#121](https://github.com/auth0/laravel-auth0/pull/121) ([irieznykov](https://github.com/irieznykov)) -- Updated required PHP version to 5.4 in composer [\#118](https://github.com/auth0/laravel-auth0/pull/118) ([dmyers](https://github.com/dmyers)) -- Changed arrays to use short array syntax [\#110](https://github.com/auth0/laravel-auth0/pull/110) ([dmyers](https://github.com/dmyers)) +- Change private properties to protected [\#132](https://github.com/auth0/laravel-auth0/pull/132) ([joshcanhelp](https://github.com/joshcanhelp)) +- Return null instead of false in Auth0UserProvider. [\#128](https://github.com/auth0/laravel-auth0/pull/128) ([afreakk](https://github.com/afreakk)) +- Change the visibility of the getter method from private to public [\#121](https://github.com/auth0/laravel-auth0/pull/121) ([irieznykov](https://github.com/irieznykov)) +- Updated required PHP version to 5.4 in composer [\#118](https://github.com/auth0/laravel-auth0/pull/118) ([dmyers](https://github.com/dmyers)) +- Changed arrays to use short array syntax [\#110](https://github.com/auth0/laravel-auth0/pull/110) ([dmyers](https://github.com/dmyers)) **Fixed** -- Fix cachehandler resolving issues [\#131](https://github.com/auth0/laravel-auth0/pull/131) ([deviouspk](https://github.com/deviouspk)) -- Added the Auth0Service as a singleton through the classname [\#107](https://github.com/auth0/laravel-auth0/pull/107) ([JCombee](https://github.com/JCombee)) -- Fixed typo [\#106](https://github.com/auth0/laravel-auth0/pull/106) ([IvanArjona](https://github.com/IvanArjona)) +- Fix cachehandler resolving issues [\#131](https://github.com/auth0/laravel-auth0/pull/131) ([deviouspk](https://github.com/deviouspk)) +- Added the Auth0Service as a singleton through the classname [\#107](https://github.com/auth0/laravel-auth0/pull/107) ([JCombee](https://github.com/JCombee)) +- Fixed typo [\#106](https://github.com/auth0/laravel-auth0/pull/106) ([IvanArjona](https://github.com/IvanArjona)) ## [5.1.0](https://github.com/auth0/laravel-auth0/tree/5.1.0) (2018-03-20) @@ -305,22 +323,22 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes **Closed issues** -- pls change config arg name [\#95](https://github.com/auth0/laravel-auth0/issues/95) +- pls change config arg name [\#95](https://github.com/auth0/laravel-auth0/issues/95) **Added** -- AutoDiscovery [\#91](https://github.com/auth0/laravel-auth0/pull/91) ([m1guelpf](https://github.com/m1guelpf)) -- Added guzzle options to config to allow for connection options [\#88](https://github.com/auth0/laravel-auth0/pull/88) ([mjmgooch](https://github.com/mjmgooch)) +- AutoDiscovery [\#91](https://github.com/auth0/laravel-auth0/pull/91) ([m1guelpf](https://github.com/m1guelpf)) +- Added guzzle options to config to allow for connection options [\#88](https://github.com/auth0/laravel-auth0/pull/88) ([mjmgooch](https://github.com/mjmgooch)) **Changed** -- Change default settings file [\#96](https://github.com/auth0/laravel-auth0/pull/96) ([joshcanhelp](https://github.com/joshcanhelp)) -- Utilise Auth0->Login to ensure state validation [\#90](https://github.com/auth0/laravel-auth0/pull/90) ([cocojoe](https://github.com/cocojoe)) +- Change default settings file [\#96](https://github.com/auth0/laravel-auth0/pull/96) ([joshcanhelp](https://github.com/joshcanhelp)) +- Utilise Auth0->Login to ensure state validation [\#90](https://github.com/auth0/laravel-auth0/pull/90) ([cocojoe](https://github.com/cocojoe)) **Fixed** -- Make code comments gender neutral [\#98](https://github.com/auth0/laravel-auth0/pull/98) ([devjack](https://github.com/devjack)) -- Fix README and CHANGELOG [\#99](https://github.com/auth0/laravel-auth0/pull/99) ([joshcanhelp](https://github.com/joshcanhelp)) +- Make code comments gender neutral [\#98](https://github.com/auth0/laravel-auth0/pull/98) ([devjack](https://github.com/devjack)) +- Fix README and CHANGELOG [\#99](https://github.com/auth0/laravel-auth0/pull/99) ([joshcanhelp](https://github.com/joshcanhelp)) ## [5.0.2](https://github.com/auth0/laravel-auth0/tree/5.0.2) (2017-08-30) @@ -328,7 +346,7 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes **Merged pull requests:** -- Use instead of to identify the Auth0 user [\#80](https://github.com/auth0/laravel-auth0/pull/80) ([glena](https://github.com/glena)) +- Use instead of to identify the Auth0 user [\#80](https://github.com/auth0/laravel-auth0/pull/80) ([glena](https://github.com/glena)) ## [5.0.1](https://github.com/auth0/laravel-auth0/tree/5.0.1) (2017-02-23) @@ -342,7 +360,7 @@ Fixed `supported_algs` configuration name **Merged pull requests:** -- V5: update to auth0 sdk v5 [\#69](https://github.com/auth0/laravel-auth0/pull/69) ([glena](https://github.com/glena)) +- V5: update to auth0 sdk v5 [\#69](https://github.com/auth0/laravel-auth0/pull/69) ([glena](https://github.com/glena)) ## [4.0.8](https://github.com/auth0/laravel-auth0/tree/4.0.8) (2017-01-27) @@ -350,12 +368,12 @@ Fixed `supported_algs` configuration name **Closed issues** -- Allow use of RS256 Protocol [\#63](https://github.com/auth0/wp-auth0/issues/63) -- Add RS256 to the list of supported algorithms [\#62](https://github.com/auth0/wp-auth0/issues/62) +- Allow use of RS256 Protocol [\#63](https://github.com/auth0/wp-auth0/issues/63) +- Add RS256 to the list of supported algorithms [\#62](https://github.com/auth0/wp-auth0/issues/62) **Merged pull requests:** -- allow to configure the algorithm supported for token verification [\#65](https://github.com/auth0/laravel-auth0/pull/65) ([glena](https://github.com/glena)) +- allow to configure the algorithm supported for token verification [\#65](https://github.com/auth0/laravel-auth0/pull/65) ([glena](https://github.com/glena)) ## [4.0.7](https://github.com/auth0/laravel-auth0/tree/4.0.7) (2017-01-02) @@ -363,7 +381,7 @@ Fixed `supported_algs` configuration name **Merged pull requests:** -- it should pass all the configs to the oauth client [\#64](https://github.com/auth0/laravel-auth0/pull/64) ([glena](https://github.com/glena)) +- it should pass all the configs to the oauth client [\#64](https://github.com/auth0/laravel-auth0/pull/64) ([glena](https://github.com/glena)) ## [4.0.6](https://github.com/auth0/laravel-auth0/tree/4.0.6) (2016-11-29) @@ -371,8 +389,8 @@ Fixed `supported_algs` configuration name **Merged pull requests:** -- Code style & docblocks [\#56](https://github.com/auth0/laravel-auth0/pull/56) ([seanmangar](https://github.com/seanmangar)) -- Adding accessor to retrieve JWT from Auth0Service [\#58](https://github.com/auth0/laravel-auth0/pull/58) ([ryantology](https://github.com/ryantology)) +- Code style & docblocks [\#56](https://github.com/auth0/laravel-auth0/pull/56) ([seanmangar](https://github.com/seanmangar)) +- Adding accessor to retrieve JWT from Auth0Service [\#58](https://github.com/auth0/laravel-auth0/pull/58) ([ryantology](https://github.com/ryantology)) ## [4.0.5](https://github.com/auth0/laravel-auth0/tree/4.0.5) (2016-11-29) @@ -380,7 +398,7 @@ Fixed `supported_algs` configuration name **Merged pull requests:** -- Added flag for not encoded tokens + removed example [\#57](https://github.com/auth0/laravel-auth0/pull/57) ([glena](https://github.com/glena)) +- Added flag for not encoded tokens + removed example [\#57](https://github.com/auth0/laravel-auth0/pull/57) ([glena](https://github.com/glena)) ## [4.0.4](https://github.com/auth0/laravel-auth0/tree/4.0.4) (2016-11-25) @@ -388,7 +406,7 @@ Fixed `supported_algs` configuration name **Merged pull requests:** -- Fixing config type [\#55](https://github.com/auth0/laravel-auth0/pull/55) ([adamgoose](https://github.com/adamgoose)) +- Fixing config type [\#55](https://github.com/auth0/laravel-auth0/pull/55) ([adamgoose](https://github.com/adamgoose)) ## [4.0.2](https://github.com/auth0/laravel-auth0/tree/4.0.2) (2016-10-03) @@ -396,7 +414,7 @@ Fixed `supported_algs` configuration name **Merged pull requests:** -- Fixing JWTVerifier [\#54](https://github.com/auth0/laravel-auth0/pull/54) ([adamgoose](https://github.com/adamgoose)) +- Fixing JWTVerifier [\#54](https://github.com/auth0/laravel-auth0/pull/54) ([adamgoose](https://github.com/adamgoose)) ## [4.0.1](https://github.com/auth0/laravel-auth0/tree/4.0.1) (2016-09-19) @@ -404,7 +422,7 @@ Fixed `supported_algs` configuration name **Merged pull requests:** -- fix error becuase of contract and class with the same name [\#52](https://github.com/auth0/laravel-auth0/pull/52) ([glena](https://github.com/glena)) +- fix error becuase of contract and class with the same name [\#52](https://github.com/auth0/laravel-auth0/pull/52) ([glena](https://github.com/glena)) ## [4.0.0](https://github.com/auth0/laravel-auth0/tree/4.0.0) (2016-09-15) @@ -415,7 +433,7 @@ Support of auth0 PHP sdk v4 with JWKs cache **Merged pull requests:** -- Merge pull request #50 from auth0/4.x.x-dev [\#50](https://github.com/auth0/laravel-auth0/pull/50) ([glena](https://github.com/glena)) +- Merge pull request #50 from auth0/4.x.x-dev [\#50](https://github.com/auth0/laravel-auth0/pull/50) ([glena](https://github.com/glena)) ## [3.2.1](https://github.com/auth0/laravel-auth0/tree/3.2.1) (2016-09-12) @@ -423,7 +441,7 @@ Support of auth0 PHP sdk v4 with JWKs cache **Merged pull requests:** -- Fix for Laravel 5.2 [\#49](https://github.com/auth0/laravel-auth0/pull/49) ([dscafati](https://github.com/dscafati)) +- Fix for Laravel 5.2 [\#49](https://github.com/auth0/laravel-auth0/pull/49) ([dscafati](https://github.com/dscafati)) ## [3.2.0](https://github.com/auth0/laravel-auth0/tree/3.2.0) (2016-07-11) @@ -431,7 +449,7 @@ Support of auth0 PHP sdk v4 with JWKs cache **Merged pull requests:** -- New optional jwt middleware [\#40](https://github.com/auth0/laravel-auth0/pull/40) ([glena](https://github.com/glena)) +- New optional jwt middleware [\#40](https://github.com/auth0/laravel-auth0/pull/40) ([glena](https://github.com/glena)) ## [3.1.0](https://github.com/auth0/laravel-auth0/tree/3.1.0) (2016-05-02) @@ -439,7 +457,7 @@ Support of auth0 PHP sdk v4 with JWKs cache **Merged pull requests:** -- 3.1.0 [\#36](https://github.com/auth0/laravel-auth0/pull/36) ([glena](https://github.com/glena)) +- 3.1.0 [\#36](https://github.com/auth0/laravel-auth0/pull/36) ([glena](https://github.com/glena)) ## [3.0.3](https://github.com/auth0/laravel-auth0/tree/3.0.3) (2016-01-28) @@ -447,11 +465,11 @@ Support of auth0 PHP sdk v4 with JWKs cache **Closed issues:** -- Tag 2.2.2 breaks on Laravel 5.1 [\#30](https://github.com/auth0/laravel-auth0/issues/30) +- Tag 2.2.2 breaks on Laravel 5.1 [\#30](https://github.com/auth0/laravel-auth0/issues/30) **Merged pull requests:** -- Conform to 5.2's Authenticatable contract [\#31](https://github.com/auth0/laravel-auth0/pull/31) ([ryannjohnson](https://github.com/ryannjohnson)) +- Conform to 5.2's Authenticatable contract [\#31](https://github.com/auth0/laravel-auth0/pull/31) ([ryannjohnson](https://github.com/ryannjohnson)) ## [3.0.2](https://github.com/auth0/laravel-auth0/tree/3.0.2) (2016-01-25) @@ -459,7 +477,7 @@ Support of auth0 PHP sdk v4 with JWKs cache **Merged pull requests:** -- Added optional persistence configuration values [\#29](https://github.com/auth0/laravel-auth0/pull/29) ([carnevalle](https://github.com/carnevalle)) +- Added optional persistence configuration values [\#29](https://github.com/auth0/laravel-auth0/pull/29) ([carnevalle](https://github.com/carnevalle)) ## [2.2.1](https://github.com/auth0/laravel-auth0/tree/2.2.1) (2016-01-22) @@ -467,11 +485,11 @@ Support of auth0 PHP sdk v4 with JWKs cache **Closed issues:** -- Create a logout route [\#25](https://github.com/auth0/laravel-auth0/issues/25) +- Create a logout route [\#25](https://github.com/auth0/laravel-auth0/issues/25) **Merged pull requests:** -- Auth0 SDK checks for null values instead of false [\#27](https://github.com/auth0/laravel-auth0/pull/27) ([thijsvdanker](https://github.com/thijsvdanker)) +- Auth0 SDK checks for null values instead of false [\#27](https://github.com/auth0/laravel-auth0/pull/27) ([thijsvdanker](https://github.com/thijsvdanker)) ## [3.0.1](https://github.com/auth0/laravel-auth0/tree/3.0.1) (2016-01-18) @@ -479,7 +497,7 @@ Support of auth0 PHP sdk v4 with JWKs cache **Merged pull requests:** -- updated auth0-php dependency [\#24](https://github.com/auth0/laravel-auth0/pull/24) ([glena](https://github.com/glena)) +- updated auth0-php dependency [\#24](https://github.com/auth0/laravel-auth0/pull/24) ([glena](https://github.com/glena)) ## [3.0.0](https://github.com/auth0/laravel-auth0/tree/3.0.0) (2016-01-06) @@ -487,11 +505,11 @@ Support of auth0 PHP sdk v4 with JWKs cache **Closed issues:** -- auth0/auth0-php ~1.0 requirement doesn't support latest GuzzleHttp [\#21](https://github.com/auth0/laravel-auth0/issues/21) +- auth0/auth0-php ~1.0 requirement doesn't support latest GuzzleHttp [\#21](https://github.com/auth0/laravel-auth0/issues/21) **Merged pull requests:** -- updated to be compatible with laravel 5.2 [\#23](https://github.com/auth0/laravel-auth0/pull/23) ([glena](https://github.com/glena)) +- updated to be compatible with laravel 5.2 [\#23](https://github.com/auth0/laravel-auth0/pull/23) ([glena](https://github.com/glena)) ## [2.2.0](https://github.com/auth0/laravel-auth0/tree/2.2.0) (2015-11-30) @@ -499,8 +517,8 @@ Support of auth0 PHP sdk v4 with JWKs cache **Merged pull requests:** -- updated auth0-php dependency version [\#22](https://github.com/auth0/laravel-auth0/pull/22) ([glena](https://github.com/glena)) -- Update login.blade.php [\#20](https://github.com/auth0/laravel-auth0/pull/20) ([Annyv2](https://github.com/Annyv2)) +- updated auth0-php dependency version [\#22](https://github.com/auth0/laravel-auth0/pull/22) ([glena](https://github.com/glena)) +- Update login.blade.php [\#20](https://github.com/auth0/laravel-auth0/pull/20) ([Annyv2](https://github.com/Annyv2)) ## [2.1.4](https://github.com/auth0/laravel-auth0/tree/2.1.4) (2015-10-27) @@ -508,11 +526,11 @@ Support of auth0 PHP sdk v4 with JWKs cache **Merged pull requests:** -- Middleware contract has been deprecated in 5.1 [\#19](https://github.com/auth0/laravel-auth0/pull/19) ([thijsvdanker](https://github.com/thijsvdanker)) -- Fixed some typo's in the comments. [\#18](https://github.com/auth0/laravel-auth0/pull/18) ([thijsvdanker](https://github.com/thijsvdanker)) -- Removed note about unstable dependency from README [\#17](https://github.com/auth0/laravel-auth0/pull/17) ([thijsvdanker](https://github.com/thijsvdanker)) -- Update composer instructions [\#16](https://github.com/auth0/laravel-auth0/pull/16) ([iWader](https://github.com/iWader)) -- Use a tagged release of adoy/oauth2 [\#15](https://github.com/auth0/laravel-auth0/pull/15) ([thijsvdanker](https://github.com/thijsvdanker)) +- Middleware contract has been deprecated in 5.1 [\#19](https://github.com/auth0/laravel-auth0/pull/19) ([thijsvdanker](https://github.com/thijsvdanker)) +- Fixed some typo's in the comments. [\#18](https://github.com/auth0/laravel-auth0/pull/18) ([thijsvdanker](https://github.com/thijsvdanker)) +- Removed note about unstable dependency from README [\#17](https://github.com/auth0/laravel-auth0/pull/17) ([thijsvdanker](https://github.com/thijsvdanker)) +- Update composer instructions [\#16](https://github.com/auth0/laravel-auth0/pull/16) ([iWader](https://github.com/iWader)) +- Use a tagged release of adoy/oauth2 [\#15](https://github.com/auth0/laravel-auth0/pull/15) ([thijsvdanker](https://github.com/thijsvdanker)) ## [2.1.3](https://github.com/auth0/laravel-auth0/tree/2.1.3) (2015-07-17) @@ -520,7 +538,7 @@ Support of auth0 PHP sdk v4 with JWKs cache **Merged pull requests:** -- updated jwt dependency [\#14](https://github.com/auth0/laravel-auth0/pull/14) ([glena](https://github.com/glena)) +- updated jwt dependency [\#14](https://github.com/auth0/laravel-auth0/pull/14) ([glena](https://github.com/glena)) ## [2.1.2](https://github.com/auth0/laravel-auth0/tree/2.1.2) (2015-05-15) @@ -528,7 +546,7 @@ Support of auth0 PHP sdk v4 with JWKs cache **Merged pull requests:** -- Added override of info headers [\#13](https://github.com/auth0/laravel-auth0/pull/13) ([glena](https://github.com/glena)) +- Added override of info headers [\#13](https://github.com/auth0/laravel-auth0/pull/13) ([glena](https://github.com/glena)) ## [2.1.1](https://github.com/auth0/laravel-auth0/tree/2.1.1) (2015-05-12) @@ -536,12 +554,12 @@ Support of auth0 PHP sdk v4 with JWKs cache **Closed issues:** -- SDK Client headers spec compliant [\#11](https://github.com/auth0/laravel-auth0/issues/11) -- Support for Laravel 5? [\#6](https://github.com/auth0/laravel-auth0/issues/6) +- SDK Client headers spec compliant [\#11](https://github.com/auth0/laravel-auth0/issues/11) +- Support for Laravel 5? [\#6](https://github.com/auth0/laravel-auth0/issues/6) **Merged pull requests:** -- SDK Client headers spec compliant \#11 [\#12](https://github.com/auth0/laravel-auth0/pull/12) ([glena](https://github.com/glena)) +- SDK Client headers spec compliant \#11 [\#12](https://github.com/auth0/laravel-auth0/pull/12) ([glena](https://github.com/glena)) ## [2.1.0](https://github.com/auth0/laravel-auth0/tree/2.1.0) (2015-05-07) @@ -549,7 +567,7 @@ Support of auth0 PHP sdk v4 with JWKs cache **Merged pull requests:** -- Upgrade to auth-php 1.0.0: Added support to API V2 [\#10](https://github.com/auth0/laravel-auth0/pull/10) ([glena](https://github.com/glena)) +- Upgrade to auth-php 1.0.0: Added support to API V2 [\#10](https://github.com/auth0/laravel-auth0/pull/10) ([glena](https://github.com/glena)) ## [2.0.0](https://github.com/auth0/laravel-auth0/tree/2.0.0) (2015-04-20) @@ -557,7 +575,7 @@ Support of auth0 PHP sdk v4 with JWKs cache **Merged pull requests:** -- Package V2 for Laravel5 [\#9](https://github.com/auth0/laravel-auth0/pull/9) ([glena](https://github.com/glena)) +- Package V2 for Laravel5 [\#9](https://github.com/auth0/laravel-auth0/pull/9) ([glena](https://github.com/glena)) ## [1.0.8](https://github.com/auth0/laravel-auth0/tree/1.0.8) (2015-04-14) @@ -569,8 +587,8 @@ Support of auth0 PHP sdk v4 with JWKs cache **Merged pull requests:** -- Fixed the way the access token is pased to the A0User [\#7](https://github.com/auth0/laravel-auth0/pull/7) ([glena](https://github.com/glena)) -- Update README.md [\#5](https://github.com/auth0/laravel-auth0/pull/5) ([pose](https://github.com/pose)) +- Fixed the way the access token is pased to the A0User [\#7](https://github.com/auth0/laravel-auth0/pull/7) ([glena](https://github.com/glena)) +- Update README.md [\#5](https://github.com/auth0/laravel-auth0/pull/5) ([pose](https://github.com/pose)) ## [1.0.6](https://github.com/auth0/laravel-auth0/tree/1.0.6) (2014-08-01) @@ -582,11 +600,11 @@ Support of auth0 PHP sdk v4 with JWKs cache **Closed issues:** -- Problem with normal laravel user table [\#4](https://github.com/auth0/laravel-auth0/issues/4) +- Problem with normal laravel user table [\#4](https://github.com/auth0/laravel-auth0/issues/4) **Merged pull requests:** -- Update README.md [\#3](https://github.com/auth0/laravel-auth0/pull/3) ([patekuru](https://github.com/patekuru)) +- Update README.md [\#3](https://github.com/auth0/laravel-auth0/pull/3) ([patekuru](https://github.com/patekuru)) ## [1.0.4](https://github.com/auth0/laravel-auth0/tree/1.0.4) (2014-05-07) From 8d8bbd32dd7e8364fd2bf63411c391a6a9bb4b7b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:24:18 -0500 Subject: [PATCH 202/525] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24d1239e..da3d6e55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## [Unreleased] +**Added** + +- Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) + +Thanks to our contributors for this release: [taida957789](https://github.com/taida957789) + ## [7.4.0](https://github.com/auth0/laravel-auth0/tree/7.4.0) (2022-12-12) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.3.0...7.4.0) From a28c403262f010dc5cd9182fbc9ad9c80f7c2ad2 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:24:58 -0500 Subject: [PATCH 203/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1b5aaac1..f57414d0 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. - PHP 8.0+ - [Composer](https://getcomposer.org/) -- Laravel 9.x/10.x +- Laravel 9.0+, 10.0+ - `Illuminate\Session\Middleware\StartSession` enabled in `app/Http/Kernel.php` - PHP Extensions: - [mbstring](https://www.php.net/manual/en/book.mbstring.php) From 0794aa2ff3aeae5ae797b0a29d225887c37e783a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:43:22 -0500 Subject: [PATCH 204/525] Replace StateInstance with Credentials --- CHANGELOG.md | 7 + src/Contract/Entities/Credential.php | 126 +++++++++++++++++ src/Contract/StateInstance.php | 94 ------------- src/Entities/Credential.php | 164 ++++++++++++++++++++++ src/StateInstance.php | 201 --------------------------- 5 files changed, 297 insertions(+), 295 deletions(-) create mode 100644 src/Contract/Entities/Credential.php delete mode 100644 src/Contract/StateInstance.php create mode 100644 src/Entities/Credential.php delete mode 100644 src/StateInstance.php diff --git a/CHANGELOG.md b/CHANGELOG.md index da3d6e55..7e351f6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ - Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) +**Changed** +The following changes have no effect on the external API of this package, but may affect internal usage. + +- `StateInstance` concept has been replaced by new `Credentials` entity. +- `Guard` updated to use new `Credentials` entity as primary internal storage for user data. +- + Thanks to our contributors for this release: [taida957789](https://github.com/taida957789) ## [7.4.0](https://github.com/auth0/laravel-auth0/tree/7.4.0) (2022-12-12) diff --git a/src/Contract/Entities/Credential.php b/src/Contract/Entities/Credential.php new file mode 100644 index 00000000..a00b89c7 --- /dev/null +++ b/src/Contract/Entities/Credential.php @@ -0,0 +1,126 @@ + + */ + public function getAccessTokenScope(): ?array; + + /** + * Get the ID token for this credential. + */ + public function getIdToken(): ?string; + + /** + * Get the refresh token for this credential. + */ + public function getRefreshToken(): ?string; + + /** + * Get the user entity this credential represents. + */ + public function getUser(): ?Authenticatable; + + /** + * Set the access token for this credential. + * + * @param null|string $accessToken The access token for this credential. + */ + public function setAccessToken( + ?string $accessToken = null, + ): self; + + /** + * Set the access token expiration for this credential. + * + * @param null|int $accessTokenExpiration The access token expiration for this credential. + */ + public function setAccessTokenExpiration( + ?int $accessTokenExpiration = null, + ): self; + + /** + * Set the access token scope for this credential. + * + * @param null|array $accessTokenScope The access token scope for this credential. + */ + public function setAccessTokenScope( + ?array $accessTokenScope = null, + ): self; + + /** + * Set the ID token for this credential. + * + * @param null|string $idToken The ID token for this credential. + */ + public function setIdToken( + ?string $idToken = null, + ): self; + + /** + * Set the refresh token for this credential. + * + * @param null|string $refreshToken The refresh token for this credential. + */ + public function setRefreshToken( + ?string $refreshToken = null, + ): self; + + /** + * Set the user entity this credential represents. + * + * @param null|Authenticatable $user The user entity this credential represents. + */ + public function setUser( + ?Authenticatable $user = null, + ): self; + + /** + * Create a new Credential instance. + * + * @param null|Authenticatable $user The user entity this credential represents. + * @param null|string $idToken The ID token for this credential. + * @param null|string $accessToken The access token for this credential. + * @param null|array $accessTokenScope The access token scope for this credential. + * @param null|int $accessTokenExpiration The access token expiration for this credential. + * @param null|string $refreshToken The refresh token for this credential. + */ + public static function create( + ?Authenticatable $user = null, + ?string $idToken = null, + ?string $accessToken = null, + ?array $accessTokenScope = null, + ?int $accessTokenExpiration = null, + ?string $refreshToken = null, + ): self; +} diff --git a/src/Contract/StateInstance.php b/src/Contract/StateInstance.php deleted file mode 100644 index fe356552..00000000 --- a/src/Contract/StateInstance.php +++ /dev/null @@ -1,94 +0,0 @@ - $accessTokenScope The access token scope for this credential. + * @param null|int $accessTokenExpiration The access token expiration for this credential. + * @param null|string $refreshToken The refresh token for this credential. + */ + public function __construct( + private ?Authenticatable $user = null, + private ?string $idToken = null, + private ?string $accessToken = null, + private ?array $accessTokenScope = null, + private ?int $accessTokenExpiration = null, + private ?string $refreshToken = null, + ) { + } + + public function clear(): self + { + $this->user = null; + $this->idToken = null; + $this->accessToken = null; + $this->accessTokenScope = null; + $this->accessTokenExpiration = null; + $this->refreshToken = null; + + return $this; + } + + public function getAccessToken(): ?string + { + return $this->accessToken; + } + + public function getAccessTokenExpiration(): ?int + { + return $this->accessTokenExpiration; + } + + public function getAccessTokenExpired(): ?bool + { + $expires = $this->getAccessTokenExpiration(); + + if (null === $expires || $expires <= 0) { + return null; + } + + return time() >= $expires; + } + + /** + * @psalm-suppress MixedReturnTypeCoercion + */ + public function getAccessTokenScope(): ?array + { + return $this->accessTokenScope; + } + + public function getIdToken(): ?string + { + return $this->idToken; + } + + public function getRefreshToken(): ?string + { + return $this->refreshToken; + } + + public function getUser(): ?Authenticatable + { + return $this->user; + } + + public function jsonSerialize(): mixed + { + return [ + 'user' => json_encode($this->getUser(), JSON_FORCE_OBJECT), + 'idToken' => $this->getIdToken(), + 'accessToken' => $this->getAccessToken(), + 'accessTokenScope' => $this->getAccessTokenScope(), + 'accessTokenExpiration' => $this->getAccessTokenExpiration(), + 'accessTokenExpired' => $this->getAccessTokenExpired(), + 'refreshToken' => $this->getRefreshToken(), + ]; + } + + public function setAccessToken( + ?string $accessToken = null, + ): self { + $this->accessToken = $accessToken; + + return $this; + } + + public function setAccessTokenExpiration( + ?int $accessTokenExpiration = null, + ): self { + $this->accessTokenExpiration = $accessTokenExpiration; + + return $this; + } + + public function setAccessTokenScope( + ?array $accessTokenScope = null, + ): self { + $this->accessTokenScope = $accessTokenScope; + + return $this; + } + + public function setIdToken( + ?string $idToken = null, + ): self { + $this->idToken = $idToken; + + return $this; + } + + public function setRefreshToken( + ?string $refreshToken = null, + ): self { + $this->refreshToken = $refreshToken; + + return $this; + } + + public function setUser( + ?Authenticatable $user = null, + ): self { + $this->user = $user; + + return $this; + } + + public static function create( + ?Authenticatable $user = null, + ?string $idToken = null, + ?string $accessToken = null, + ?array $accessTokenScope = null, + ?int $accessTokenExpiration = null, + ?string $refreshToken = null, + ): self { + return new self( + $user, + $idToken, + $accessToken, + $accessTokenScope, + $accessTokenExpiration, + $refreshToken, + ); + } +} diff --git a/src/StateInstance.php b/src/StateInstance.php deleted file mode 100644 index fbdf369e..00000000 --- a/src/StateInstance.php +++ /dev/null @@ -1,201 +0,0 @@ -user = null; - $this->decoded = null; - $this->idToken = null; - $this->accessToken = null; - $this->accessTokenScope = null; - $this->accessTokenExpiration = null; - $this->refreshToken = null; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function getUser(): ?Authenticatable - { - return $this->user; - } - - /** - * {@inheritdoc} - */ - public function setUser(?Authenticatable $user): self - { - $this->user = $user; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function getDecoded(): ?array - { - return $this->decoded; - } - - /** - * {@inheritdoc} - */ - public function setDecoded(?array $data): self - { - $this->decoded = $data; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function getIdToken(): ?string - { - return $this->idToken; - } - - /** - * {@inheritdoc} - */ - public function setIdToken(?string $idToken): self - { - $this->idToken = $idToken; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function getAccessToken(): ?string - { - return $this->accessToken; - } - - /** - * {@inheritdoc} - */ - public function setAccessToken(?string $accessToken): self - { - $this->accessToken = $accessToken; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function getAccessTokenScope(): ?array - { - return $this->accessTokenScope; - } - - /** - * {@inheritdoc} - */ - public function setAccessTokenScope(?array $accessTokenScope): self - { - $this->accessTokenScope = $accessTokenScope; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function getAccessTokenExpiration(): ?int - { - return $this->accessTokenExpiration; - } - - /** - * {@inheritdoc} - */ - public function setAccessTokenExpiration(?int $accessTokenExpiration): self - { - $this->accessTokenExpiration = $accessTokenExpiration; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function getAccessTokenExpired(): ?bool - { - $expires = $this->getAccessTokenExpiration(); - - if (null === $expires) { - return null; - } - - return time() >= $expires; - } - - /** - * {@inheritdoc} - */ - public function getRefreshToken(): ?string - { - return $this->refreshToken; - } - - /** - * {@inheritdoc} - */ - public function setRefreshToken(?string $refreshToken): self - { - $this->refreshToken = $refreshToken; - - return $this; - } -} From b482f8351c23ec7f533ffebe194666880680469d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:45:15 -0500 Subject: [PATCH 205/525] Update Traits to use Credentials --- CHANGELOG.md | 3 +- src/Traits/ActingAsAuth0User.php | 66 ++++++++++++++++++++------------ src/Traits/Impersonate.php | 40 +++++++++++++++++++ 3 files changed, 84 insertions(+), 25 deletions(-) create mode 100644 src/Traits/Impersonate.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e351f6d..00f0a12e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,13 +5,14 @@ **Added** - Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) +- New `Auth0\Laravel\Traits\Imposter` trait to allow for easier testing. **Changed** The following changes have no effect on the external API of this package, but may affect internal usage. - `StateInstance` concept has been replaced by new `Credentials` entity. - `Guard` updated to use new `Credentials` entity as primary internal storage for user data. -- +- `Auth0\Laravel\Traits\ActingAsAuth0User` was updated to use new`Credentials` entity. Thanks to our contributors for this release: [taida957789](https://github.com/taida957789) diff --git a/src/Traits/ActingAsAuth0User.php b/src/Traits/ActingAsAuth0User.php index 10a3b880..3eac4064 100644 --- a/src/Traits/ActingAsAuth0User.php +++ b/src/Traits/ActingAsAuth0User.php @@ -4,36 +4,54 @@ namespace Auth0\Laravel\Traits; -use Auth0\Laravel\Model\Stateless\User; -use Auth0\Laravel\StateInstance; -use Illuminate\Contracts\Auth\Authenticatable as UserContract; - +use Auth0\Laravel\Auth\Guard; +use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Entities\Credential; +use Auth0\Laravel\Model\Imposter; +use Illuminate\Contracts\Auth\Authenticatable; + +/** + * @deprecated 7.5.0 Use of this trait is longer recommended. Use the Impersonate trait instead. This trait will be removed in the next major release. + */ trait ActingAsAuth0User { - abstract public function actingAs(UserContract $user, $guard = null); - /** - * use this method to impersonate a specific auth0 user - * if you pass an attributes array, it will be merged with a set of default values. + * Set the currently logged in user for the application. * - * @return mixed + * @param array $attributes The attributes to use for the user. + * @param null|string $guard The guard to impersonate with. + * + * @return $this The current test case instance. */ - public function actingAsAuth0User(array $attributes = []) - { - $defaults = [ - 'sub' => 'some-auth0-user-id', - 'azp' => 'some-auth0-appplication-client-id', - 'iat' => time(), - 'exp' => time() + 60 * 60, - 'scope' => '', - ]; - - $auth0user = new User(array_merge($defaults, $attributes)); - - if ($auth0user->getAttribute('scope')) { - app(StateInstance::class)->setAccessTokenScope(explode(' ', $auth0user->getAttribute('scope'))); + public function actingAsAuth0User( + array $attributes = [], + ?string $guard = 'auth0', + ) { + $issued = time(); + $expires = $issued + 60 * 60; + $timestamps = ['iat' => $issued, 'exp' => $expires]; + $attributes = array_merge($this->defaultActingAsAttributes, $timestamps, $attributes); + + $instance = auth()->guard($guard); + $user = new Imposter($attributes); + + if ($instance instanceof GuardContract) { + $credential = Credential::create( + user: $user, + accessTokenScope: $attributes['scope'] ? explode(' ', $attributes['scope']) : [], + ); + + $instance->setCredential($credential, Guard::SOURCE_IMPERSONATE); + $instance->setImpersonating(true); } - return $this->actingAs($auth0user, 'auth0'); + return $this->actingAs($user, $guard); } + + abstract public function actingAs(Authenticatable $user, $guard = null); + public array $defaultActingAsAttributes = [ + 'sub' => 'some-auth0-user-id', + 'azp' => 'some-auth0-application-client-id', + 'scope' => '', + ]; } diff --git a/src/Traits/Impersonate.php b/src/Traits/Impersonate.php new file mode 100644 index 00000000..6566498c --- /dev/null +++ b/src/Traits/Impersonate.php @@ -0,0 +1,40 @@ +guard($guard); + $user = $credential->getUser() ?? new User([]); + + if ($instance instanceof Guard) { + $instance->setCredential($credential, $source); + $instance->setImpersonating(true); + } + + return $this->actingAs($user, $guard); + } + + abstract public function actingAs(Authenticatable $user, $guard = null); +} From 626155b3f8a2954f3eea6f8f172e5e1ef2d557d0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:57:38 -0500 Subject: [PATCH 206/525] Refactor codebase --- src/Auth/Guard.php | 675 ++++++++++++------ src/Auth/User/Provider.php | 118 ++- src/Auth/User/Repository.php | 19 +- src/Auth0.php | 130 ++-- src/Cache/LaravelCacheItem.php | 81 +-- src/Cache/LaravelCachePool.php | 199 +++--- src/Configuration.php | 41 +- src/Contract/Auth/Guard.php | 145 +++- src/Contract/Auth/User/Provider.php | 4 +- src/Contract/Auth/User/Repository.php | 12 +- src/Contract/Auth0.php | 18 +- src/Contract/Configuration.php | 8 +- src/Contract/Event/Configuration/Building.php | 4 +- src/Contract/Event/Configuration/Built.php | 4 +- .../Event/Stateful/AuthenticationFailed.php | 30 +- .../Stateful/AuthenticationSucceeded.php | 14 +- .../Stateless/TokenVerificationAttempting.php | 14 +- .../Stateless/TokenVerificationFailed.php | 14 +- .../Stateless/TokenVerificationSucceeded.php | 14 +- .../Exception/AuthenticationException.php | 12 + src/Contract/Exception/GuardException.php | 14 + src/Contract/Exception/SessionException.php | 11 + .../Exception/Stateful/CallbackException.php | 11 +- .../Http/Controller/Stateful/Callback.php | 6 +- .../Http/Controller/Stateful/Login.php | 6 +- .../Http/Controller/Stateful/Logout.php | 6 +- .../Http/Middleware/Stateful/Authenticate.php | 9 +- .../Stateful/AuthenticateOptional.php | 9 +- .../Http/Middleware/Stateless/Authorize.php | 9 +- .../Stateless/AuthorizeOptional.php | 8 +- src/Contract/Model/User.php | 32 +- src/Contract/ServiceProvider.php | 4 +- src/Event/Auth0Event.php | 14 +- src/Event/Configuration/Building.php | 24 +- src/Event/Configuration/Built.php | 23 +- src/Event/Middleware/StatefulRequest.php | 9 +- src/Event/Middleware/StatelessRequest.php | 9 +- src/Event/Stateful/AuthenticationFailed.php | 45 +- .../Stateful/AuthenticationSucceeded.php | 25 +- src/Event/Stateful/TokenExpired.php | 5 +- src/Event/Stateful/TokenRefreshFailed.php | 5 +- src/Event/Stateful/TokenRefreshSucceeded.php | 5 +- .../Stateless/TokenVerificationAttempting.php | 28 +- .../Stateless/TokenVerificationFailed.php | 23 +- .../Stateless/TokenVerificationSucceeded.php | 24 +- src/Exception/AuthenticationException.php | 16 + src/Exception/GuardException.php | 16 + src/Exception/SessionException.php | 17 + src/Exception/Stateful/CallbackException.php | 14 +- src/Facade/Auth0.php | 4 +- src/Http/Controller/ControllerAbstract.php | 29 + src/Http/Controller/Stateful/Callback.php | 125 ++-- src/Http/Controller/Stateful/Login.php | 43 +- src/Http/Controller/Stateful/Logout.php | 48 +- src/Http/Middleware/MiddlewareAbstract.php | 12 + src/Http/Middleware/Stateful/Authenticate.php | 48 +- .../Stateful/AuthenticateOptional.php | 50 +- src/Http/Middleware/Stateless/Authorize.php | 59 +- .../Stateless/AuthorizeOptional.php | 51 +- src/Model/Imposter.php | 11 + src/Model/Stateful/User.php | 5 +- src/Model/Stateless/User.php | 5 +- src/Model/User.php | 78 +- src/ServiceProvider.php | 96 +-- src/Store/LaravelSession.php | 159 +++-- 65 files changed, 1717 insertions(+), 1089 deletions(-) create mode 100644 src/Contract/Exception/AuthenticationException.php create mode 100644 src/Contract/Exception/GuardException.php create mode 100644 src/Contract/Exception/SessionException.php create mode 100644 src/Exception/AuthenticationException.php create mode 100644 src/Exception/GuardException.php create mode 100644 src/Exception/SessionException.php create mode 100644 src/Http/Controller/ControllerAbstract.php create mode 100644 src/Http/Middleware/MiddlewareAbstract.php create mode 100644 src/Model/Imposter.php diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 0e034961..3507e1bf 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -5,337 +5,564 @@ namespace Auth0\Laravel\Auth; use Auth0\Laravel\Auth0; -use Auth0\Laravel\Contract\Auth\User\Provider; -use Auth0\Laravel\Contract\StateInstance; -use Auth0\Laravel\StateInstance as ConcreteStateInstance; -use Auth0\SDK\Configuration\SdkConfiguration; -use Illuminate\Contracts\Auth\Authenticatable; -use Illuminate\Contracts\Auth\UserProvider; -use Illuminate\Support\Facades\Session; -use RuntimeException; - -final class Guard implements \Auth0\Laravel\Contract\Auth\Guard, \Illuminate\Contracts\Auth\Guard +use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Contract\Entities\Credential; +use Auth0\Laravel\Contract\Exception\GuardException as GuardExceptionContract; +use Auth0\Laravel\Entities\Credential as CredentialConcrete; +use Auth0\Laravel\Event\Stateful\{TokenRefreshFailed, TokenRefreshSucceeded}; +use Auth0\Laravel\Event\Stateless\{TokenVerificationAttempting, TokenVerificationFailed, TokenVerificationSucceeded}; +use Auth0\Laravel\Exception\{AuthenticationException, GuardException}; +use Auth0\Laravel\Model\Stateful\User as StatefulUser; +use Auth0\SDK\Contract\Auth0Interface; +use Auth0\SDK\Exception\InvalidTokenException; +use Auth0\SDK\Token; +use Exception; +use Illuminate\Auth\Events\{Login, Logout}; +use Illuminate\Contracts\Auth\{Authenticatable, UserProvider}; +use Illuminate\Contracts\Container\BindingResolutionException; +use Illuminate\Contracts\Session\Session; +use Psr\Container\{ContainerExceptionInterface, NotFoundExceptionInterface}; +use function in_array; +use function is_array; +use function is_int; +use function is_object; +use function is_string; + +final class Guard implements GuardContract { + public const SOURCE_IMPERSONATE = 0; // Manually set, presumably through a test case's impersonate() method. + public const SOURCE_SESSION = 2; // Assigned from a session. + public const SOURCE_TOKEN = 1; // Assigned from a decoded token. + + public function __construct( + private string $name = '', + private ?array $config = null, + ) { + } + /** - * {@inheritdoc} + * Get a credential candidate from an Auth0-PHP SDK session. + * + * @return null|Credential Credential when a valid token is found, null otherwise. */ - public function login(Authenticatable $user): self + private function findSession(): ?Credential { - $this->getState()->setUser($user); + $this->getSession(); + $session = $this->pullState(); + $user = $session?->getUser(); + + if (null !== $session && $user instanceof Authenticatable) { + $user = $this->getProvider()->retrieveByCredentials($this->normalizeUserArray($user)); + + if ($user instanceof Authenticatable) { + $credential = CredentialConcrete::create( + user: $user, + idToken: $session->getIdToken(), + accessToken: $session->getAccessToken(), + accessTokenScope: $session->getAccessTokenScope(), + accessTokenExpiration: $session->getAccessTokenExpiration(), + refreshToken: $session->getRefreshToken(), + ); + + return $this->refreshSession($credential); + } + } - return $this; + return null; } /** - * {@inheritdoc} + * Get a credential candidate from a provided access token. + * + * @return null|Credential Credential object if a valid token is found, null otherwise. */ - public function logout(): self + private function findToken(): ?Credential { - // Although user() should never return null in this instance, default to an empty dummy user in such an event to avoid throwing an exception. - $user = $this->user() ?? new \Auth0\Laravel\Model\Stateful\User([]); + $token = trim(app('request')->bearerToken() ?? ''); + + if ('' === $token) { + return null; + } - event(new \Illuminate\Auth\Events\Logout(Guard::class, $user)); + $user = $this->getProvider()->retrieveByToken('token', $token); - app()->instance(StateInstance::class, null); - Session::flush(); + if ($user instanceof Authenticatable) { + $data = $this->normalizeUserArray($user); - app(Auth0::class)->getSdk()->clear(); + if ([] !== $data) { + $scope = isset($data['scope']) && is_string($data['scope']) ? explode(' ', $data['scope']) : []; + $exp = isset($data['exp']) && is_numeric($data['exp']) ? (int) $data['exp'] : null; - return $this; + return CredentialConcrete::create( + user: $user, + accessToken: $token, + accessTokenScope: $scope, + accessTokenExpiration: $exp, + ); + } + } + + return null; } /** - * {@inheritdoc} + * Get the Auth0 PHP SDK instance. + * + * @throws BindingResolutionException If the Auth0 class cannot be resolved. + * @throws NotFoundExceptionInterface If the Auth0 service cannot be found. + * @throws ContainerExceptionInterface If the Auth0 service cannot be resolved. + * + * @return Auth0Interface Auth0 PHP SDK instance. */ - public function check(): bool + private function getSdk(): Auth0Interface { - return null !== $this->user(); + return $this->getService()->getSdk(); } /** - * {@inheritdoc} + * Get the Auth0 service instance. + * + * @throws BindingResolutionException If the Auth0 class cannot be resolved. + * + * @return Auth0 Auth0 service. */ - public function guest(): bool + private function getService(): Auth0 { - return ! $this->check(); + return app('auth0'); } /** - * {@inheritdoc} + * Normalize a user model object for easier storage or comparison. + * + * @param Authenticatable $user User model object. + * + * @throws Exception If the user model object cannot be normalized. + * + * @return array Normalized user model object. + * + * @psalm-suppress TypeDoesNotContainType + * + * @codeCoverageIgnore */ - public function user(): ?Authenticatable + private function normalizeUserArray( + Authenticatable $user, + ): array { + $implements = class_implements($user); + $fail = false; + + // @phpstan-ignore-next-line + if (in_array('JsonSerializable', $implements, true) && method_exists($user, 'jsonSerialize')) { + /** @phpstan-ignore-next-line */ + $user = (array) $user->jsonSerialize(); + // @phpstan-ignore-next-line + } elseif (in_array('Illuminate\Contracts\Support\Arrayable', $implements, true) && method_exists($user, 'toArray')) { + /** @phpstan-ignore-next-line */ + $user = (array) $user->toArray(); + // @phpstan-ignore-next-line + } elseif (in_array('Illuminate\Contracts\Support\Jsonable', $implements, true) && method_exists($user, 'toJson')) { + /** @phpstan-ignore-next-line */ + $user = (array) $user->toJson(); + // @phpstan-ignore-next-line + } elseif (method_exists($user, 'attributesToArray')) { + /** @phpstan-ignore-next-line */ + $user = (array) $user->attributesToArray(); + } else { + $fail = true; + } + // @phpstan-ignore-end + + if ($fail) { + throw new GuardException(GuardExceptionContract::USER_MODEL_NORMALIZATION_FAILURE); + } + + try { + // @phpstan-ignore-next-line + return json_decode(json_encode($user, JSON_THROW_ON_ERROR), true, 512, JSON_THROW_ON_ERROR); + } catch (\JsonException) { + throw new GuardException(GuardExceptionContract::USER_MODEL_NORMALIZATION_FAILURE); + } + } + + private function pullState(): ?Credential { - $user = $this->getState()->getUser(); + $sdk = $this->getSdk(); + $sdk->refreshState(); + $credentials = $sdk->getCredentials(); + + /** @var mixed $credentials */ + if (is_object($credentials) && property_exists($credentials, 'user') && property_exists($credentials, 'idToken') && property_exists($credentials, 'accessToken') && property_exists($credentials, 'accessTokenScope') && property_exists($credentials, 'accessTokenExpiration') && property_exists($credentials, 'refreshToken')) { + return CredentialConcrete::create( + user: new StatefulUser($credentials->user), + idToken: $credentials->idToken, + accessToken: $credentials->accessToken, + accessTokenScope: $credentials->accessTokenScope, + accessTokenExpiration: $credentials->accessTokenExpiration, + refreshToken: $credentials->refreshToken, + ); + } - if (! $user instanceof Authenticatable) { - $configuration = app(Auth0::class)->getConfiguration(); + return null; + } - $apiOnly = \in_array($configuration->getStrategy(), [SdkConfiguration::STRATEGY_API, SdkConfiguration::STRATEGY_MANAGEMENT_API], true); + private function pushState( + ?Credential $credential = null, + ): self { + if (self::SOURCE_SESSION !== $this->getCredentialSource()) { + return $this; + } - if ($apiOnly) { - $user = $this->getUserFromToken(); - } + $sdk = $this->getSdk(); + $credential ??= $this->getCredential(); - if (! $apiOnly) { - $user = $this->getUserFromSession(); - } + if (null === $credential) { + $sdk->clear(true); + + return $this; } - return $user; + $pushHash = json_encode($credential); + + // @codeCoverageIgnoreStart + if (! is_string($pushHash)) { + $pushHash = ''; + } + // @codeCoverageIgnoreEnd + $pushHash = md5($pushHash); + + if ($pushHash === $this->pushHash) { + return $this; + } + + $user = $credential->getUser(); + $idToken = $credential->getIdToken(); + $accessToken = $credential->getAccessToken(); + $accessTokenScope = $credential->getAccessTokenScope(); + $accessTokenExpiration = $credential->getAccessTokenExpiration(); + $refreshToken = $credential->getRefreshToken(); + + if ($user instanceof Authenticatable) { + $sdk->setUser($this->normalizeUserArray($user)); + } + + if (null !== $idToken) { + $sdk->setIdToken($idToken); + } + + if (null !== $accessToken) { + $sdk->setAccessToken($accessToken); + } + + if (null !== $accessTokenScope) { + $sdk->setAccessTokenScope($accessTokenScope); + } + + if (null !== $accessTokenExpiration) { + $sdk->setAccessTokenExpiration($accessTokenExpiration); + } + + if (null !== $refreshToken) { + $sdk->setRefreshToken($refreshToken); + } + + $this->pushHash = $pushHash; + + return $this; } - /** - * {@inheritdoc} - */ - public function id() - { - $response = null; - $user = $this->user(); + private function refreshSession( + ?Credential $credential, + ): ?Credential { + if (null === $credential || true !== $credential->getAccessTokenExpired()) { + return $credential; + } - if (null !== $user) { - $id = $user->getAuthIdentifier(); + if (null === $credential->getRefreshToken()) { + return null; + } - if (\is_string($id) || \is_int($id)) { - $response = $id; + try { + $this->getSdk()->renew(); + $session = $this->pullState(); + } catch (\Throwable) { + event(new TokenRefreshFailed()); + $session = null; + } + + if (null !== $session) { + event(new TokenRefreshSucceeded()); + + $user = $this->getProvider()->retrieveByCredentials((array) $session->getUser()); + + if ($user instanceof Authenticatable) { + return CredentialConcrete::create( + user: $user, + idToken: $session->getIdToken(), + accessToken: $session->getAccessToken(), + accessTokenScope: $session->getAccessTokenScope(), + accessTokenExpiration: $session->getAccessTokenExpiration(), + refreshToken: $session->getRefreshToken(), + ); } } - return $response; + $this->setCredential(null, null); + $this->pushState(); + + return null; } - /** - * {@inheritdoc} - * - * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter - */ - public function validate(array $credentials = []): bool + public function authenticate(): Authenticatable { - return false; + if (null !== ($user = $this->user())) { + return $user; + } + + throw new AuthenticationException(AuthenticationException::UNAUTHENTICATED); } - /** - * {@inheritdoc} - * - * @psalm-suppress UnusedVariable - */ - public function setUser(Authenticatable $user): self + public function check(): bool { - $user = $this->getState()-> - setUser($user); + return $this->hasUser(); + } - return $this; + public function find( + int $source, + ): ?Credential { + if ($this->impersonating) { + return $this->getCredential(); + } + + if (self::SOURCE_TOKEN === $source) { + $candidate = $this->findToken(); + + if (null !== $candidate) { + return $candidate; + } + } + + if (self::SOURCE_SESSION === $source) { + $candidate = $this->findSession(); + + if (null !== $candidate) { + return $candidate; + } + } + + return null; } - /** - * {@inheritdoc} - */ - public function hasUser(): bool + public function forgetUser(): self { - return null !== $this->getState()->getUser(); + $this->setCredential(); + + return $this; } - /** - * {@inheritdoc} - */ - public function hasScope(string $scope): bool + public function getCredential(): ?Credential { - $state = $this->getState(); + if (! $this->impersonating && self::SOURCE_SESSION === $this->getCredentialSource() && null !== $this->credential) { + $updated = $this->findSession(); + $source = null !== $updated ? self::SOURCE_SESSION : null; + $this->setCredential($updated, $source); + $this->pushState($updated); + } - return \in_array($scope, $state->getAccessTokenScope() ?? [], true); + return $this->credential; } - /** - * Always returns false to keep third-party apps happy. - */ - public function viaRemember(): bool + public function getCredentialSource(): ?int { - return false; + return $this->credentialSource; } - /** - * Get the user context from a provided access token. - */ - private function getUserFromToken(): ?Authenticatable + public function getName(): string { - // Retrieve an available bearer token from the request. - $request = request(); + return $this->name; + } - // @phpstan-ignore-next-line - if (! $request instanceof \Illuminate\Http\Request) { - return null; + public function getProvider(): UserProvider + { + if ($this->provider instanceof UserProvider) { + return $this->provider; } - $token = $request->bearerToken(); + $providerName = $this->config['provider'] ?? ''; - // If a session is not available, return null. - if (! \is_string($token)) { - return null; + if (! is_string($providerName) || '' === $providerName) { + // @codeCoverageIgnoreStart + throw new GuardException(GuardExceptionContract::USER_PROVIDER_UNCONFIGURED); + // @codeCoverageIgnoreEnd } - $event = new \Auth0\Laravel\Event\Stateless\TokenVerificationAttempting($token); - event($event); - $token = $event->getToken(); + $providerName = trim($providerName); + $provider = app('auth')->createUserProvider($providerName); - try { - // Attempt to decode the bearer token. - $decoded = app(Auth0::class)->getSdk()->decode( - token: $token, - tokenType: \Auth0\SDK\Token::TYPE_TOKEN, - )->toArray(); - } catch (\Auth0\SDK\Exception\InvalidTokenException $invalidToken) { - event(new \Auth0\Laravel\Event\Stateless\TokenVerificationFailed($token, $invalidToken)); - - // Invalid bearer token. - return null; - } + if ($provider instanceof UserProvider) { + $this->provider = $provider; - // Query the UserProvider to retrieve tue user for the token. - $provider = $this->getProvider(); + return $provider; + } - /** - * @var Provider $provider - * @var array{scope: string|null, exp: int|null} $decoded - */ - $user = $provider-> - getRepository()-> - fromAccessToken($decoded); + // @codeCoverageIgnoreStart + throw new GuardException(sprintf(GuardExceptionContract::USER_PROVIDER_UNAVAILABLE, $providerName)); + // @codeCoverageIgnoreEnd + } - // Was a user retrieved successfully? - if (null !== $user) { - if (! $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { - exit('User model returned fromAccessToken must implement \Auth0\Laravel\Contract\Model\Stateless\User.'); - } + public function getSession(): Session + { + $store = app('session.store'); + $request = app('request'); - event(new \Auth0\Laravel\Event\Stateless\TokenVerificationSucceeded($token, $decoded)); + if (! $request->hasSession(true)) { + $request->setLaravelSession($store); + } - $this->getState()-> - clear()-> - setDecoded($decoded)-> - setAccessToken($token)-> - setAccessTokenScope(explode(' ', $decoded['scope'] ?? ''))-> - setAccessTokenExpiration($decoded['exp'] ?? null); + if (! $store->isStarted()) { + $store->start(); } - return $user; + return $store; } - /** - * Get the user context from an Auth0-PHP SDK session.. - */ - private function getUserFromSession(): ?Authenticatable + public function guest(): bool { - // Retrieve an available session from the Auth0-PHP SDK. - $session = app(Auth0::class)->getSdk()->getCredentials(); + return ! $this->check(); + } - // If a session is not available, return null. - if (null === $session) { - return null; + public function hasScope( + string $scope, + Credential $credential, + ): bool { + if ('*' === $scope) { + return true; } - // Query the UserProvider to retrieve tue user for the token. - $provider = $this->getProvider(); + $available = $credential->getAccessTokenScope(); - /** - * @var Provider $provider - */ + if (is_array($available) && [] !== $available) { + return in_array($scope, $available, true); + } - // Query the UserProvider to retrieve tue user for the session. - $user = $provider-> - getRepository()-> - fromSession($session->user); // @phpstan-ignore-line + return false; + } - // Was a user retrieved successfully? - if (null !== $user) { - if (! $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { - exit('User model returned fromSession must implement \Auth0\Laravel\Contract\Model\Stateful\User.'); - } + public function hasUser(): bool + { + return null !== $this->getCredential()?->getUser(); + } - $this->getState()-> - clear()-> - setDecoded($session->user)-> // @phpstan-ignore-line - setIdToken($session->idToken)-> // @phpstan-ignore-line - setAccessToken($session->accessToken)-> // @phpstan-ignore-line - setAccessTokenScope($session->accessTokenScope)-> // @phpstan-ignore-line - setAccessTokenExpiration($session->accessTokenExpiration)-> // @phpstan-ignore-line - setRefreshToken($session->refreshToken); /** @phpstan-ignore-line */ - $user = $this->handleSessionExpiration($user); + public function id(): int | string | null + { + $user = $this->user()?->getAuthIdentifier(); + + if (is_string($user) || is_int($user)) { + return $user; } - return $user; + return null; } - /** - * Handle instances of session token expiration. - */ - private function handleSessionExpiration( - ?Authenticatable $user, - ): ?Authenticatable { - $state = $this->getState(); + public function login( + ?Credential $credential, + ?int $source = null, + ): self { + $this->setCredential($credential, $source); + $this->pushState($credential); + $user = $credential?->getUser(); - // Unless our token expired, we have nothing to do here. - if (true !== $state->getAccessTokenExpired()) { - return $user; + if (null !== $credential && $user instanceof Authenticatable) { + event(new Login(self::class, $user, true)); } - // Do we have a refresh token? - if (null !== $state->getRefreshToken()) { - try { - // Try to renew our token. - app(Auth0::class)->getSdk()->renew(); - } catch (\Auth0\SDK\Exception\StateException $tokenRefreshFailed) { - // Renew failed. Inform application. - event(new \Auth0\Laravel\Event\Stateful\TokenRefreshFailed()); - } + return $this; + } - // Retrieve updated state data - $refreshed = app(Auth0::class)->getSdk()->getCredentials(); + public function logout(): self + { + $this->impersonating = false; + $user = $this->user(); - // @phpstan-ignore-next-line - if (null !== $refreshed && false === $refreshed->accessTokenExpired) { - event(new \Auth0\Laravel\Event\Stateful\TokenRefreshSucceeded()); + if (null !== $user) { + event(new Logout(self::class, $user)); + } - return $user; - } + $this->setCredential(null, $this->getCredentialSource()); + $this->pushState(); + $this->forgetUser(); + + return $this; + } + + public function processToken( + string $token, + ): ?array { + $event = new TokenVerificationAttempting($token); + event($event); + $token = $event->getToken(); + + try { + $data = $this->getSdk()->decode(token: $token, tokenType: Token::TYPE_ACCESS_TOKEN)->toArray(); + event(new TokenVerificationSucceeded($token, $data)); + + return $data; + } catch (InvalidTokenException $invalidToken) { + event(new TokenVerificationFailed($token, $invalidToken)); + + return null; } + } - // We didn't have a refresh token, or the refresh failed. - // Clear session. - $state->clear(); - app(Auth0::class)->getSdk()->clear(); + public function setCredential( + ?Credential $credential = null, + ?int $source = null, + ): self { + $this->credential = $credential; + $this->credentialSource = $source; - // Inform host application. - event(new \Auth0\Laravel\Event\Stateful\TokenExpired()); + return $this; + } - return null; + public function setImpersonating( + bool $impersonate = false, + ): self { + $this->impersonating = $impersonate; + + return $this; } - /** - * Return the current request's StateInstance singleton. - */ - private function getState(): StateInstance + public function setUser( + Authenticatable $user, + ): void { + $credential = $this->getCredential() ?? CredentialConcrete::create(); + $credential->setUser($user); + + $this->setCredential($credential); + $this->pushState($credential); + } + + public function user(): ?Authenticatable { - return app(ConcreteStateInstance::class); + return $this->getCredential()?->getUser(); } /** - * Return the current request's StateInstance singleton. + * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + * + * @param array $credentials */ - private function getProvider(): UserProvider - { - static $provider = null; - - if (null === $provider) { - /** - * @var string|null $configured - */ - $configured = config('auth.guards.auth0.provider') ?? \Auth0\Laravel\Auth\User\Provider::class; - $provider = app('auth')->createUserProvider($configured); - - if (! $provider instanceof UserProvider) { - throw new RuntimeException('Auth0: Unable to invoke UserProvider from application configuration.'); - } - } + public function validate( + array $credentials = [], + ): bool { + return false; + } - return $provider; + public function viaRemember(): bool + { + return false; } + private ?Credential $credential = null; + private ?int $credentialSource = null; + private bool $impersonating = false; + private ?UserProvider $provider = null; + private ?string $pushHash = null; } diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php index 487fd927..eadfe980 100644 --- a/src/Auth/User/Provider.php +++ b/src/Auth/User/Provider.php @@ -4,14 +4,25 @@ namespace Auth0\Laravel\Auth\User; +use Auth0\Laravel\Auth\Guard; +use Auth0\Laravel\Contract\Auth\User\Provider as ProviderContract; +use Auth0\Laravel\Contract\Auth\User\Repository as RepositoryContract; use Illuminate\Contracts\Auth\Authenticatable; +use Illuminate\Contracts\Container\BindingResolutionException; -final class Provider implements \Auth0\Laravel\Contract\Auth\User\Provider, \Illuminate\Contracts\Auth\UserProvider +final class Provider implements ProviderContract { + private ?RepositoryContract $repository = null; + private string $repositoryName = ''; + + public function __construct( + private array $config = [], + ) { + } + /** - * {@inheritdoc} - * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + * @codeCoverageIgnore */ public function retrieveById($identifier): ?Authenticatable { @@ -19,28 +30,44 @@ public function retrieveById($identifier): ?Authenticatable } /** - * {@inheritdoc} - * + * @psalm-suppress DocblockTypeContradiction * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ public function retrieveByToken($identifier, $token): ?Authenticatable { - return null; + // @phpstan-ignore-next-line + if (! is_string($token)) { + return null; + } + + $guard = auth()->guard(); + + if (! $guard instanceof Guard) { + return null; + } + + $user = $guard->processToken( + token: $token + ); + + if (null === $user) { + return null; + } + + return $this->getRepository()->fromAccessToken( + user: $user + ); } /** - * {@inheritdoc} - * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ public function retrieveByCredentials(array $credentials): ?Authenticatable { - return null; + return $this->getRepository()->fromSession($credentials); } /** - * {@inheritdoc} - * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ public function validateCredentials( @@ -51,29 +78,68 @@ public function validateCredentials( } /** - * {@inheritdoc} - * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + * @codeCoverageIgnore */ public function updateRememberToken(Authenticatable $user, $token): void { } - /** - * {@inheritdoc} - */ - public function getRepository(): \Auth0\Laravel\Contract\Auth\User\Repository + public function getRepository(): RepositoryContract + { + return $this->repository ?? $this->resolveRepository(); + } + + public function setRepository(string $repository): void { - static $repository = null; - - if (null === $repository) { - /** - * @var string|null $configured - */ - $configured = config('auth.providers.auth0.repository') ?? \Auth0\Laravel\Auth\User\Repository::class; - $repository = app($configured); + $this->resolveRepository($repository); + } + + private function resolveRepository( + ?string $repositoryName = null, + ): RepositoryContract { + $model = $repositoryName; + $model ??= $this->getConfiguration('model'); + $model ??= $this->getConfiguration('repository'); + $model ??= Repository::class; + + if ($model === $this->getRepositoryName()) { + return $this->getRepository(); + } + + if (! is_string($model) ) { + throw new BindingResolutionException('The configured Repository could not be loaded.'); } - return $repository; + if (! app()->bound($model)) { + throw new BindingResolutionException(sprintf('The configured Repository %s could not be loaded.', $model)); + } + + $this->setRepositoryName($model); + return $this->repository = app($model); + } + + private function getRepositoryName(): string + { + return $this->repositoryName; + } + + private function setRepositoryName(string $repositoryName): void + { + $this->setConfiguration('model', $repositoryName); + $this->repositoryName = $repositoryName; + } + + private function getConfiguration( + string $key, + ): array|string|null { + return $this->config[$key] ?? null; + } + + private function setConfiguration( + string $key, + mixed $value, + ): void { + $this->config[$key] = $value; } } diff --git a/src/Auth/User/Repository.php b/src/Auth/User/Repository.php index 5a9995a2..250bfec0 100644 --- a/src/Auth/User/Repository.php +++ b/src/Auth/User/Repository.php @@ -4,23 +4,20 @@ namespace Auth0\Laravel\Auth\User; +use Auth0\Laravel\Contract\Auth\User\Repository as RepositoryContract; +use Auth0\Laravel\Model\Stateful\User as StatefulUser; +use Auth0\Laravel\Model\Stateless\User as StatelessUser; use Illuminate\Contracts\Auth\Authenticatable; -final class Repository implements \Auth0\Laravel\Contract\Auth\User\Repository +final class Repository implements RepositoryContract { - /** - * {@inheritdoc} - */ - public function fromSession(array $user): ?Authenticatable + public function fromAccessToken(array $user): ?Authenticatable { - return new \Auth0\Laravel\Model\Stateful\User($user); + return new StatelessUser($user); } - /** - * {@inheritdoc} - */ - public function fromAccessToken(array $user): ?Authenticatable + public function fromSession(array $user): ?Authenticatable { - return new \Auth0\Laravel\Model\Stateless\User($user); + return new StatefulUser($user); } } diff --git a/src/Auth0.php b/src/Auth0.php index 160ec6a0..ccab64a5 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -5,61 +5,45 @@ namespace Auth0\Laravel; use Auth0\Laravel\Cache\LaravelCachePool; +use Auth0\Laravel\Contract\Auth0 as ServiceContract; +use Auth0\Laravel\Event\Configuration\{Building, Built}; use Auth0\Laravel\Store\LaravelSession; +use Auth0\SDK\Auth0 as SDK; use Auth0\SDK\Configuration\SdkConfiguration as Configuration; -use Auth0\SDK\Contract\Auth0Interface as SDK; +use Auth0\SDK\Contract\Auth0Interface as SDKContract; +use Auth0\SDK\Utility\HttpTelemetry; +use function in_array; /** * Service that provides access to the Auth0 SDK. */ -final class Auth0 implements \Auth0\Laravel\Contract\Auth0 +final class Auth0 implements ServiceContract { /** * The Laravel-Auth0 SDK version:. */ public const VERSION = '7.4.0'; - /** - * An instance of the Auth0-PHP SDK. - */ - private static ?SDK $sdk = null; - - /** - * An instance of the Auth0-PHP SDK's SdkConfiguration, which handles configuration state. - */ - private static ?Configuration $configuration = null; - - /** - * {@inheritdoc} - */ - public function getSdk(): SDK - { - if (null === self::$sdk) { - self::$sdk = new \Auth0\SDK\Auth0($this->getConfiguration()); - } - - $this->setSdkTelemetry(); - - return self::$sdk; + public function __construct( + private ?SDKContract $sdk = null, + private ?Configuration $configuration = null, + ) { } /** - * {@inheritdoc} + * Updates the Auth0 PHP SDK's telemetry to include the correct Laravel markers. */ - public function setSdk(SDK $sdk): self + private function setSdkTelemetry(): self { - self::$sdk = $sdk; - $this->setSdkTelemetry(); + HttpTelemetry::setEnvProperty('Laravel', app()->version()); + HttpTelemetry::setPackage('laravel-auth0', self::VERSION); return $this; } - /** - * {@inheritdoc} - */ public function getConfiguration(): Configuration { - if (null === self::$configuration) { + if (null === $this->configuration) { $config = config('auth0'); /** @@ -77,67 +61,85 @@ public function getConfiguration(): Configuration } } - $event = new \Auth0\Laravel\Event\Configuration\Building($config); + $event = new Building($config); event($event); $configuration = new Configuration($event->getConfiguration()); - if (! \in_array($configuration->getStrategy(), [Configuration::STRATEGY_API, Configuration::STRATEGY_MANAGEMENT_API], true)) { + if (! in_array($configuration->getStrategy(), [Configuration::STRATEGY_API, Configuration::STRATEGY_MANAGEMENT_API], true)) { // If no sessionStorage is defined, use an LaravelSession store instance. if (! isset($config['sessionStorage'])) { - $configuration->setSessionStorage( - sessionStorage: new LaravelSession( - prefix: $configuration->getSessionStorageId(), - ), - ); + $sessionStore = app(LaravelSession::class, [ + 'prefix' => $configuration->getSessionStorageId(), + ]); + + $configuration->setSessionStorage(sessionStorage: $sessionStore); } // If no transientStorage is defined, use an LaravelSession store instance. if (! isset($config['transientStorage'])) { - $configuration->setTransientStorage( - transientStorage: new LaravelSession( - prefix: $configuration->getTransientStorageId(), - ), - ); + $transientStore = app(LaravelSession::class, [ + 'prefix' => $configuration->getTransientStorageId(), + ]); + + $configuration->setTransientStorage(transientStorage: $transientStore); } } + $this->configuration = $configuration; + // Give apps an opportunity to mutate the configuration before applying it. - $event = new \Auth0\Laravel\Event\Configuration\Built($configuration); + $event = new Built($configuration); event($event); - self::$configuration = $event->getConfiguration(); + $this->configuration = $event->getConfiguration(); } - return self::$configuration; + return $this->configuration; } - /** - * {@inheritdoc} - */ - public function setConfiguration(Configuration $configuration): self + public function getCredentials(): ?object { - self::$configuration = $configuration; + return $this->getSdk()->getCredentials(); + } - return $this; + public function getSdk(): SDKContract + { + if (null !== $this->sdk) { + return $this->sdk; + } + + return $this->setSdk(new SDK($this->getConfiguration())); } - /** - * {@inheritdoc} - */ - public function getState(): Contract\StateInstance + public function reset(): self { - return app(StateInstance::class); + unset($this->sdk, $this->configuration); + + $this->sdk = null; + $this->configuration = null; + + return $this; } - /** - * Updates the Auth0 PHP SDK's telemetry to include the correct Laravel markers. - */ - private function setSdkTelemetry(): self + public function setConfiguration(Configuration $configuration): self { - \Auth0\SDK\Utility\HttpTelemetry::setEnvProperty('Laravel', app()->version()); - \Auth0\SDK\Utility\HttpTelemetry::setPackage('laravel-auth0', self::VERSION); + $this->configuration = $configuration; + + if (null !== $this->sdk) { + $this->sdk->setConfiguration($configuration); + } return $this; } + + public function setSdk(SDKContract $sdk): SDKContract + { + $this->configuration = $sdk->configuration(); + $this->sdk = $sdk; + + $this->setSdkTelemetry(); + + return $this->sdk; + } } diff --git a/src/Cache/LaravelCacheItem.php b/src/Cache/LaravelCacheItem.php index dd4158c2..e28db059 100644 --- a/src/Cache/LaravelCacheItem.php +++ b/src/Cache/LaravelCacheItem.php @@ -4,7 +4,12 @@ namespace Auth0\Laravel\Cache; +use DateInterval; +use DateTime; +use DateTimeImmutable; +use DateTimeInterface; use Psr\Cache\CacheItemInterface; +use function is_int; final class LaravelCacheItem implements CacheItemInterface { @@ -12,86 +17,70 @@ public function __construct( private string $key, private mixed $value, private bool $hit, - private ?\DateTimeInterface $expiration = null, + private ?DateTimeInterface $expiration = null, ) { } - /** - * {@inheritdoc} - */ - public function getKey(): string + public function expiresAfter(int | DateInterval | null $time): static { - return $this->key; - } + $this->expiration = match (true) { + null === $time => new DateTimeImmutable('now +1 year'), + is_int($time) => new DateTimeImmutable('now +' . (string) $time . ' seconds'), + $time instanceof DateInterval => (new DateTimeImmutable())->add($time), + }; - /** - * {@inheritdoc} - */ - public function get(): mixed - { - return $this->isHit() ? $this->value : null; + return $this; } - /** - * {@inheritdoc} - */ - public function set($value = null): static + public function expiresAt(?DateTimeInterface $expiration): static { - $this->value = $value; + $this->expiration = $expiration ?? new DateTimeImmutable('now +1 year'); return $this; } - /** - * {@inheritdoc} - */ - public function isHit(): bool + public function get(): mixed { - return $this->hit; + return $this->isHit() ? $this->value : null; } /** - * {@inheritdoc} + * Returns the expiration timestamp. */ - public function expiresAt(?\DateTimeInterface $expiration): static + public function getExpiration(): DateTimeInterface { - $this->expiration = $expiration ?? new \DateTimeImmutable('now +1 year'); + return $this->expiration ?? new DateTime('now +1 year'); + } - return $this; + public function getKey(): string + { + return $this->key; } /** - * {@inheritdoc} + * Returns the raw value, regardless of hit status. */ - public function expiresAfter(int|\DateInterval|null $time): static + public function getRawValue(): mixed { - $this->expiration = match (true) { - null === $time => new \DateTimeImmutable('now +1 year'), - \is_int($time) => new \DateTimeImmutable('now +' . $time . ' seconds'), - $time instanceof \DateInterval => (new \DateTimeImmutable())->add($time), /* @phpstan-ignore-line */ - }; - - return $this; + return $this->value; } - /** - * Returns the expiration timestamp. - */ - public function getExpiration(): \DateTimeInterface + public function isHit(): bool { - return $this->expiration ?? new \DateTime('now +1 year'); + return $this->hit; } - /** - * Returns the raw value, regardless of hit status. - */ - public function getRawValue(): mixed + public function set(mixed $value): static { - return $this->value; + $this->value = $value; + + return $this; } /** * Return a LaravelCacheItem instance flagged as missed. + * + * @param string $key */ public static function miss(string $key): self { diff --git a/src/Cache/LaravelCachePool.php b/src/Cache/LaravelCachePool.php index ce56e513..ef18dba9 100644 --- a/src/Cache/LaravelCachePool.php +++ b/src/Cache/LaravelCachePool.php @@ -4,8 +4,11 @@ namespace Auth0\Laravel\Cache; -use Psr\Cache\CacheItemInterface; -use Psr\Cache\CacheItemPoolInterface; +use DateTimeInterface; +use Illuminate\Cache\CacheManager; +use Illuminate\Contracts\Cache\Store; +use Psr\Cache\{CacheItemInterface, CacheItemPoolInterface}; +use function is_string; /** * Class LaravelCachePool @@ -13,69 +16,88 @@ */ final class LaravelCachePool implements CacheItemPoolInterface { - /** - * @var array - */ - private array $deferred = []; - - public function getItem(string $key): CacheItemInterface + private function createItem(string $key, mixed $value): CacheItemInterface { - $value = $this->getStore()-> - get($key); + if (! is_string($value)) { + return LaravelCacheItem::miss($key); + } + + $value = unserialize($value); if (false === $value) { return LaravelCacheItem::miss($key); } - return $this->createItem($key, $value); + return new LaravelCacheItem($key, $value, true); } /** - * @param string[] $keys - * @return CacheItemInterface[] + * @param string $key the key for which to return the corresponding Cache Item + * + * @codeCoverageIgnore */ - public function getItems(array $keys = []): iterable + private function getDeferred(string $key): ?CacheItemInterface { - if ([] === $keys) { - return []; + if (! isset($this->deferred[$key])) { + return null; } - $results = $this->getStore()-> - many($keys); - $items = []; + $deferred = $this->deferred[$key]; + $item = clone $deferred['item']; + $expires = $deferred['expiration']; - foreach ($results as $key => $value) { - $key = (string) $key; - $items[$key] = $this->createItem($key, $value); + if ($expires instanceof DateTimeInterface) { + $expires = $expires->getTimestamp(); } - return $items; + if (null !== $expires && $expires <= time()) { + unset($this->deferred[$key]); + + return null; + } + + return $item; } - /** - * @param string $key the key for which to return the corresponding Cache Item - */ - public function hasItem(mixed $key): bool + private function getStore(): Store { - return $this->getItem($key)-> - isHit(); + return app(CacheManager::class)->getStore(); } public function clear(): bool { $this->deferred = []; - return $this->getStore()-> - flush(); + return $this->getStore() + ->flush(); + } + + public function commit(): bool + { + $success = true; + + foreach (array_keys($this->deferred) as $singleDeferred) { + $item = $this->getDeferred((string) $singleDeferred); + + // @codeCoverageIgnoreStart + if (null !== $item && ! $this->save($item)) { + $success = false; + } + // @codeCoverageIgnoreEnd + } + + $this->deferred = []; + + return $success; } /** - * @param string $key the key for which to return the corresponding Cache Item + * @param string $key the key for which to return the corresponding Cache Item */ - public function deleteItem(mixed $key): bool + public function deleteItem(string $key): bool { - return $this->getStore()-> - forget($key); + return $this->getStore() + ->forget($key); } public function deleteItems(array $keys): bool @@ -91,14 +113,58 @@ public function deleteItems(array $keys): bool return $deleted; } + public function getItem(string $key): CacheItemInterface + { + $value = $this->getStore() + ->get($key); + + if (false === $value) { + return LaravelCacheItem::miss($key); + } + + return $this->createItem($key, $value); + } + + /** + * @param string[] $keys + * + * @return CacheItemInterface[] + */ + public function getItems(array $keys = []): iterable + { + if ([] === $keys) { + return []; + } + + $results = $this->getStore() + ->many($keys); + $items = []; + + foreach ($results as $key => $value) { + $key = (string) $key; + $items[$key] = $this->createItem($key, $value); + } + + return $items; + } + + /** + * @param string $key the key for which to return the corresponding Cache Item + */ + public function hasItem(string $key): bool + { + return $this->getItem($key) + ->isHit(); + } + public function save(CacheItemInterface $item): bool { if (! $item instanceof LaravelCacheItem) { return false; } - $value = serialize($item->get()); - $key = $item->getKey(); + $value = serialize($item->get()); + $key = $item->getKey(); $expires = $item->getExpiration(); if ($expires->getTimestamp() <= time()) { @@ -124,59 +190,8 @@ public function saveDeferred(CacheItemInterface $item): bool return true; } - public function commit(): bool - { - $success = true; - - foreach (array_keys($this->deferred) as $singleDeferred) { - $item = $this->getDeferred((string) $singleDeferred); - - if (null !== $item && ! $this->save($item)) { - $success = false; - } - } - - $this->deferred = []; - - return $success; - } - - private function getStore(): \Illuminate\Contracts\Cache\Store - { - return app(\Illuminate\Cache\CacheManager::class)->getStore(); - } - - private function createItem(string $key, mixed $value): CacheItemInterface - { - if (! \is_string($value)) { - return LaravelCacheItem::miss($key); - } - - $value = unserialize($value); - - if (false === $value) { - return LaravelCacheItem::miss($key); - } - - return new LaravelCacheItem($key, $value, true); - } - - private function getDeferred(string $key): ?CacheItemInterface - { - if (! isset($this->deferred[$key])) { - return null; - } - - $deferred = $this->deferred[$key]; - $item = clone $deferred['item']; - $expires = $deferred['expiration']; - - if (null !== $expires && $expires <= time()) { - unset($this->deferred[$key]); - - return null; - } - - return $item; - } + /** + * @var array + */ + private array $deferred = []; } diff --git a/src/Configuration.php b/src/Configuration.php index ffb32b96..a358604f 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -4,54 +4,55 @@ namespace Auth0\Laravel; +use Auth0\Laravel\Contract\Configuration as ConfigurationContract; +use function count; +use function is_string; + /** * Helpers to map configuration data stored as strings from .env files into formats consumable by the Auth0-PHP SDK. */ -final class Configuration implements \Auth0\Laravel\Contract\Configuration +final class Configuration implements ConfigurationContract { - /** - * {@inheritdoc} - */ - public static function stringToArrayOrNull(?string $config, string $delimiter = ' '): ?array + public static function stringToArray(?string $config, string $delimiter = ' '): array { - if (\is_string($config) && '' !== $config && '' !== $delimiter) { + if (is_string($config) && '' !== $config && '' !== $delimiter) { $response = explode($delimiter, $config); // @phpstan-ignore-next-line - if (\count($response) >= 1 && '' !== trim($response[0])) { + if (count($response) >= 1 && '' !== trim($response[0])) { return $response; } } - return null; + return []; } - /** - * {@inheritdoc} - */ - public static function stringToArray(?string $config, string $delimiter = ' '): array + public static function stringToArrayOrNull(?string $config, string $delimiter = ' '): ?array { - if (\is_string($config) && '' !== $config && '' !== $delimiter) { + if (is_string($config) && '' !== $config && '' !== $delimiter) { $response = explode($delimiter, $config); // @phpstan-ignore-next-line - if (\count($response) >= 1 && '' !== trim($response[0])) { + if (count($response) >= 1 && '' !== trim($response[0])) { return $response; } } - return []; + return null; } - /** - * {@inheritdoc} - */ public static function stringToBoolOrNull(?string $config, ?bool $default = null): ?bool { - if (\is_string($config) && '' !== $config) { + if (is_string($config) && '' !== $config) { $config = mb_strtolower(trim($config)); - return 'true' === $config; + if ('true' === $config) { + return true; + } + + if ('false' === $config) { + return false; + } } return $default; diff --git a/src/Contract/Auth/Guard.php b/src/Contract/Auth/Guard.php index 6bee220e..fa41415d 100644 --- a/src/Contract/Auth/Guard.php +++ b/src/Contract/Auth/Guard.php @@ -4,42 +4,157 @@ namespace Auth0\Laravel\Contract\Auth; -use Illuminate\Contracts\Auth\Authenticatable; +use Auth0\Laravel\Contract\Entities\Credential; +use Illuminate\Auth\AuthenticationException; +use Illuminate\Contracts\Auth\{Authenticatable, Guard as GuardContract, UserProvider}; +use Illuminate\Contracts\Session\Session; -interface Guard +interface Guard extends GuardContract { /** - * Set the current user. + * Returns the currently authenticated user for the guard. If none is set, throws an exception. + * + * @throws AuthenticationException If no user is currently authenticated. */ - public function login(Authenticatable $user): self; + public function authenticate(): Authenticatable; /** - * Clear the current user. + * Returns whether there is a currently authenticated user for the guard. */ - public function logout(): self; + public function check(): bool; + + /** + * Searches for an available credential from a specified source in the current request context. + * + * @param int $source The source to search for a credential in. One of the Guard::SOURCE_* constants. + */ + public function find( + int $source, + ): ?Credential; + + /** + * Clears the currently authenticated user for the guard. This will not clear a session, if one is set. + */ + public function forgetUser(): self; + + /** + * Returns the Guard's currently configured Credential, or null if no Credential is configured. + */ + public function getCredential(): ?Credential; + + /** + * Returns the Guard's currently configured credential source, or null if no source is configured. One of the Guard::SOURCE_* constants. + */ + public function getCredentialSource(): ?int; + + /** + * Returns the Guard's currently configured UserProvider. + */ + public function getProvider(): UserProvider; + + /** + * Returns a Laravel session store from the current Request context. Note that this will start a session if one is not already started. + */ + public function getSession(): Session; + + /** + * Returns whether there is no currently authenticated user for the guard. + */ + public function guest(): bool; + + /** + * Returns whether a provided credential has a specified scope. + * + * @param string $scope The scope to check for. + * @param Credential $credential The Credential to check. + */ + public function hasScope( + string $scope, + Credential $credential, + ): bool; /** - * Determine if the guard has a user instance. + * Returns whether there is a currently authenticated user for the guard. */ public function hasUser(): bool; /** - * Get the currently authenticated user. + * Returns the id of the currently authenticated user for the guard, if available. */ - public function user(): ?Authenticatable; + public function id(): int | string | null; /** - * Set the currently authenticated user. + * Sets the currently authenticated user for the guard. + * + * @param null|Credential $credential The Credential to set. + * @param null|int $source The source of the Credential. */ - public function setUser(Authenticatable $user): self; + public function login( + ?Credential $credential, + ?int $source = null, + ): self; /** - * Determine if an authenticated user is available. + * Clears the currently authenticated user for the guard. If a credential is set, it will be cleared. If a session is set, it will be cleared. */ - public function check(): bool; + public function logout(): self; + + /** + * Processes a JWT token and returns the decoded token, or null if the token is invalid. + * + * @param string $token The JWT token to process. + * + * @return null|array + */ + public function processToken( + string $token, + ): ?array; + + /** + * Sets the Guard's currently configured Credential and source. + * + * @param null|Credential $credential The Credential to set. + * @param null|int $source The source of the Credential. + */ + public function setCredential( + ?Credential $credential, + ?int $source = null, + ): self; + + /** + * Toggle the Guard's impersonation state. This should only be used by the Impersonate trait, and is not intended for use by end-users. It is public to allow for testing. + * + * @param bool $impersonate Whether or not the Guard should be impersonating. + */ + public function setImpersonating( + bool $impersonate = false, + ): self; + + /** + * Sets the currently authenticated user for the guard. This method will replace the current user of an existing credential, if one is set, or establish a new one. If an existing credential uses a session source, the session will be updated. + * + * @param Authenticatable $user The user to set as authenticated. + */ + public function setUser( + Authenticatable $user, + ): void; + + /** + * Returns the currently authenticated user for the guard, if available. + */ + public function user(): ?Authenticatable; + + /** + * This method is not currently implemented, but is required by Laravel's Guard contract. + * + * @param array $credentials + */ + public function validate( + array $credentials = [], + ): bool; /** - * Returns true if the given user has the specified scope. + * This method is not currently implemented, but is required by Laravel's Guard contract. */ - public function hasScope(string $scope): bool; + public function viaRemember(): bool; } diff --git a/src/Contract/Auth/User/Provider.php b/src/Contract/Auth/User/Provider.php index c7871944..ffa08313 100644 --- a/src/Contract/Auth/User/Provider.php +++ b/src/Contract/Auth/User/Provider.php @@ -4,7 +4,9 @@ namespace Auth0\Laravel\Contract\Auth\User; -interface Provider +use Illuminate\Contracts\Auth\UserProvider; + +interface Provider extends UserProvider { /** * Returns the assigned user provider. diff --git a/src/Contract/Auth/User/Repository.php b/src/Contract/Auth/User/Repository.php index 5f74e165..ed34195d 100644 --- a/src/Contract/Auth/User/Repository.php +++ b/src/Contract/Auth/User/Repository.php @@ -9,16 +9,16 @@ interface Repository { /** - * Generate a \Auth0\Laravel\Model\Stateful\User instance from an available Auth0-PHP user session. + * Generate a stateless User instance from a parsed Access Token. * - * @param array $user an array containing the raw Auth0 user data + * @param array $user an array containing the raw Auth0 user data */ - public function fromSession(array $user): ?Authenticatable; + public function fromAccessToken(array $user): ?Authenticatable; /** - * Generate a \Auth0\Laravel\Model\Stateful\User instance from a parsed Access Token. + * Generate a stateful User instance from an available Auth0-PHP user session. * - * @param array $user an array containing the raw Auth0 user data + * @param array $user an array containing the raw Auth0 user data */ - public function fromAccessToken(array $user): ?Authenticatable; + public function fromSession(array $user): ?Authenticatable; } diff --git a/src/Contract/Auth0.php b/src/Contract/Auth0.php index 5089fb7d..79c73271 100644 --- a/src/Contract/Auth0.php +++ b/src/Contract/Auth0.php @@ -10,27 +10,31 @@ interface Auth0 { /** - * Create/return instance of the Auth0-PHP SDK. + * Create/return instance of the Auth0-PHP SdkConfiguration. */ - public function getSdk(): SDK; + public function getConfiguration(): Configuration; /** * Create/return instance of the Auth0-PHP SDK. */ - public function setSdk(SDK $sdk): self; + public function getSdk(): SDK; /** - * Create/return instance of the Auth0-PHP SdkConfiguration. + * Resets and cleans up the internal state of the SDK. */ - public function getConfiguration(): Configuration; + public function reset(): self; /** * Assign the Auth0-PHP SdkConfiguration. + * + * @param Configuration $configuration */ public function setConfiguration(Configuration $configuration): self; /** - * Create/create a request state instance, a storage singleton containing authenticated user data. + * Create/return instance of the Auth0-PHP SDK. + * + * @param SDK $sdk */ - public function getState(): StateInstance; + public function setSdk(SDK $sdk): SDK; } diff --git a/src/Contract/Configuration.php b/src/Contract/Configuration.php index 1902f52f..3b1790e5 100644 --- a/src/Contract/Configuration.php +++ b/src/Contract/Configuration.php @@ -9,16 +9,16 @@ interface Configuration /** * Converts a delimited string into an array, or null, if nothing was provided. * - * @param string|null $config The string contents to convert, i.e. 'one two three'. - * @param string $delimiter the string delimiter to split the string contents with; defaults to space + * @param null|string $config The string contents to convert, i.e. 'one two three'. + * @param string $delimiter the string delimiter to split the string contents with; defaults to space */ public static function stringToArrayOrNull(?string $config, string $delimiter = ' '): ?array; /** * Converts a truthy string representation into a boolean. * - * @param string|null $config The string contents to convert, i.e. 'true' - * @param bool|null $default the default boolean value to return if a valid string wasn't provided + * @param null|string $config The string contents to convert, i.e. 'true' + * @param null|bool $default the default boolean value to return if a valid string wasn't provided */ public static function stringToBoolOrNull(?string $config, ?bool $default = null): ?bool; } diff --git a/src/Contract/Event/Configuration/Building.php b/src/Contract/Event/Configuration/Building.php index b459f109..0b3cc3ff 100644 --- a/src/Contract/Event/Configuration/Building.php +++ b/src/Contract/Event/Configuration/Building.php @@ -9,7 +9,7 @@ interface Building /** * AuthenticationFailed constructor. * - * @param array $configuration a configuration array for use with the Auth0-PHP SDK + * @param array $configuration a configuration array for use with the Auth0-PHP SDK */ public function __construct(array $configuration); @@ -21,7 +21,7 @@ public function getConfiguration(): array; /** * Determine whether the provided exception will be thrown by the SDK. * - * @param array $configuration an configuration array for use with the Auth0-PHP SDK + * @param array $configuration an configuration array for use with the Auth0-PHP SDK */ public function setConfiguration(array $configuration): self; } diff --git a/src/Contract/Event/Configuration/Built.php b/src/Contract/Event/Configuration/Built.php index 4444d712..f0cf4076 100644 --- a/src/Contract/Event/Configuration/Built.php +++ b/src/Contract/Event/Configuration/Built.php @@ -11,7 +11,7 @@ interface Built /** * AuthenticationFailed constructor. * - * @param SdkConfiguration $configuration an instance of Auth0\SDK\Configuration\SdkConfiguration for use with the Auth0-PHP SDK + * @param SdkConfiguration $configuration an instance of SdkConfiguration for use with the Auth0-PHP SDK */ public function __construct(SdkConfiguration $configuration); @@ -23,7 +23,7 @@ public function getConfiguration(): SdkConfiguration; /** * Determine whether the provided exception will be thrown by the SDK. * - * @param SdkConfiguration $configuration an instance of Auth0\SDK\Configuration\SdkConfiguration for use with the Auth0-PHP SDK + * @param SdkConfiguration $configuration an instance of SdkConfiguration for use with the Auth0-PHP SDK */ public function setConfiguration(SdkConfiguration $configuration): self; } diff --git a/src/Contract/Event/Stateful/AuthenticationFailed.php b/src/Contract/Event/Stateful/AuthenticationFailed.php index 427e3964..a35a7c42 100644 --- a/src/Contract/Event/Stateful/AuthenticationFailed.php +++ b/src/Contract/Event/Stateful/AuthenticationFailed.php @@ -4,37 +4,39 @@ namespace Auth0\Laravel\Contract\Event\Stateful; +use Throwable; + interface AuthenticationFailed { /** * AuthenticationFailed constructor. * - * @param \Throwable $exception an exception instance in which to throw for the authentication failure - * @param bool $throwException whether or not $exception will be thrown + * @param Throwable $exception an exception instance in which to throw for the authentication failure + * @param bool $throwException whether or not $exception will be thrown */ - public function __construct(\Throwable $exception, bool $throwException = true); + public function __construct(Throwable $exception, bool $throwException = true); /** - * Overwrite the exception to be thrown. - * - * @param \Throwable $exception an exception instance in which to throw for the authentication failure + * Returns the exception to be thrown. */ - public function setException(\Throwable $exception): self; + public function getException(): Throwable; /** - * Returns the exception to be thrown. + * Returns whether the provided exception will be thrown by the SDK. */ - public function getException(): \Throwable; + public function getThrowException(): bool; /** - * Determine whether the provided exception will be thrown by the SDK. + * Overwrite the exception to be thrown. * - * @param bool $throwException whether or not $exception will be thrown + * @param Throwable $exception an exception instance in which to throw for the authentication failure */ - public function setThrowException(bool $throwException): self; + public function setException(Throwable $exception): self; /** - * Returns whether the provided exception will be thrown by the SDK. + * Determine whether the provided exception will be thrown by the SDK. + * + * @param bool $throwException whether or not $exception will be thrown */ - public function getThrowException(): bool; + public function setThrowException(bool $throwException): self; } diff --git a/src/Contract/Event/Stateful/AuthenticationSucceeded.php b/src/Contract/Event/Stateful/AuthenticationSucceeded.php index 6b23708b..c62284a6 100644 --- a/src/Contract/Event/Stateful/AuthenticationSucceeded.php +++ b/src/Contract/Event/Stateful/AuthenticationSucceeded.php @@ -11,19 +11,19 @@ interface AuthenticationSucceeded /** * AuthenticationSucceeded constructor. * - * @param Authenticatable $user an instance of Authenticatable representing the authenticated user + * @param Authenticatable $user an instance of Authenticatable representing the authenticated user */ public function __construct(Authenticatable $user); /** - * Overwrite the authenticated user. - * - * @param Authenticatable $user an instance of Authenticatable representing the authenticated user + * Return the authenticated user. */ - public function setUser(Authenticatable $user): self; + public function getUser(): Authenticatable; /** - * Return the authenticated user. + * Overwrite the authenticated user. + * + * @param Authenticatable $user an instance of Authenticatable representing the authenticated user */ - public function getUser(): Authenticatable; + public function setUser(Authenticatable $user): self; } diff --git a/src/Contract/Event/Stateless/TokenVerificationAttempting.php b/src/Contract/Event/Stateless/TokenVerificationAttempting.php index e74ab00a..b032a925 100644 --- a/src/Contract/Event/Stateless/TokenVerificationAttempting.php +++ b/src/Contract/Event/Stateless/TokenVerificationAttempting.php @@ -9,19 +9,19 @@ interface TokenVerificationAttempting /** * AuthenticationSucceeded constructor. * - * @param string $token a bearer JSON web token + * @param string $token a bearer JSON web token */ public function __construct(string $token); /** - * Overwrite the bearer JSON web token. - * - * @param string $token a bearer JSON web token + * Return the bearer JSON web token. */ - public function setToken(string $token): self; + public function getToken(): string; /** - * Return the bearer JSON web token + * Overwrite the bearer JSON web token. + * + * @param string $token a bearer JSON web token */ - public function getToken(): string; + public function setToken(string $token): self; } diff --git a/src/Contract/Event/Stateless/TokenVerificationFailed.php b/src/Contract/Event/Stateless/TokenVerificationFailed.php index 05f13dc5..a40fe97a 100644 --- a/src/Contract/Event/Stateless/TokenVerificationFailed.php +++ b/src/Contract/Event/Stateless/TokenVerificationFailed.php @@ -11,21 +11,21 @@ interface TokenVerificationFailed /** * AuthenticationFailed constructor. * - * @param string $token an encoded bearer JSON web token - * @param Throwable $exception an exception instance in which to throw for the token verification failure + * @param string $token an encoded bearer JSON web token + * @param Throwable $exception an exception instance in which to throw for the token verification failure */ public function __construct( string $token, - Throwable $exception + Throwable $exception, ); /** - * Return the bearer JSON web token + * Returns the exception to be thrown. */ - public function getToken(): string; + public function getException(): Throwable; /** - * Returns the exception to be thrown. + * Return the bearer JSON web token. */ - public function getException(): Throwable; + public function getToken(): string; } diff --git a/src/Contract/Event/Stateless/TokenVerificationSucceeded.php b/src/Contract/Event/Stateless/TokenVerificationSucceeded.php index 6cca112d..9a114668 100644 --- a/src/Contract/Event/Stateless/TokenVerificationSucceeded.php +++ b/src/Contract/Event/Stateless/TokenVerificationSucceeded.php @@ -9,21 +9,21 @@ interface TokenVerificationSucceeded /** * AuthenticationSucceeded constructor. * - * @param string $token a bearer JSON web token - * @param array $payload the bearer JSON web token's decoded payload + * @param string $token a bearer JSON web token + * @param array $payload the bearer JSON web token's decoded payload */ public function __construct( string $token, - array $payload + array $payload, ); /** - * Return the bearer JSON web token + * Return the bearer JSON web token's decoded payload. */ - public function getToken(): string; + public function getPayload(): array; /** - * Return the bearer JSON web token's decoded payload. + * Return the bearer JSON web token. */ - public function getPayload(): array; + public function getToken(): string; } diff --git a/src/Contract/Exception/AuthenticationException.php b/src/Contract/Exception/AuthenticationException.php new file mode 100644 index 00000000..7bfd0fc7 --- /dev/null +++ b/src/Contract/Exception/AuthenticationException.php @@ -0,0 +1,12 @@ +mutated; } + + /** + * Tracks whether an event payload has been overwritten. + */ + protected bool $mutated = false; } diff --git a/src/Event/Configuration/Building.php b/src/Event/Configuration/Building.php index 4cc18341..678f383b 100644 --- a/src/Event/Configuration/Building.php +++ b/src/Event/Configuration/Building.php @@ -4,30 +4,24 @@ namespace Auth0\Laravel\Event\Configuration; -final class Building extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Configuration\Building +use Auth0\Laravel\Contract\Event\Configuration\Building as BuildingContract; +use Auth0\Laravel\Event\Auth0Event; + +final class Building extends Auth0Event implements BuildingContract { - /** - * {@inheritdoc} - */ public function __construct(private array $configuration) { } - /** - * {@inheritdoc} - */ + public function getConfiguration(): array + { + return $this->configuration; + } + public function setConfiguration(array $configuration): self { $this->configuration = $configuration; return $this; } - - /** - * {@inheritdoc} - */ - public function getConfiguration(): array - { - return $this->configuration; - } } diff --git a/src/Event/Configuration/Built.php b/src/Event/Configuration/Built.php index 5e851c93..b2c23dc2 100644 --- a/src/Event/Configuration/Built.php +++ b/src/Event/Configuration/Built.php @@ -4,32 +4,25 @@ namespace Auth0\Laravel\Event\Configuration; +use Auth0\Laravel\Contract\Event\Configuration\Built as BuiltContract; +use Auth0\Laravel\Event\Auth0Event; use Auth0\SDK\Configuration\SdkConfiguration as Configuration; -final class Built extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Configuration\Built +final class Built extends Auth0Event implements BuiltContract { - /** - * {@inheritdoc} - */ public function __construct(private Configuration $configuration) { } - /** - * {@inheritdoc} - */ + public function getConfiguration(): Configuration + { + return $this->configuration; + } + public function setConfiguration(Configuration $configuration): self { $this->configuration = $configuration; return $this; } - - /** - * {@inheritdoc} - */ - public function getConfiguration(): Configuration - { - return $this->configuration; - } } diff --git a/src/Event/Middleware/StatefulRequest.php b/src/Event/Middleware/StatefulRequest.php index 9b725226..39bcc6c1 100644 --- a/src/Event/Middleware/StatefulRequest.php +++ b/src/Event/Middleware/StatefulRequest.php @@ -4,9 +4,14 @@ namespace Auth0\Laravel\Event\Middleware; -final class StatefulRequest extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Middleware\StatefulRequest +use Auth0\Laravel\Contract\Event\Middleware\StatefulRequest as StatefulRequestContract; +use Auth0\Laravel\Event\Auth0Event; +use Illuminate\Contracts\Auth\Guard; +use Illuminate\Http\Request; + +final class StatefulRequest extends Auth0Event implements StatefulRequestContract { - public function __construct(public \Illuminate\Http\Request $request, public \Illuminate\Contracts\Auth\Guard $guard) + public function __construct(public Request $request, public Guard $guard) { } } diff --git a/src/Event/Middleware/StatelessRequest.php b/src/Event/Middleware/StatelessRequest.php index 7d0d4d42..000b7724 100644 --- a/src/Event/Middleware/StatelessRequest.php +++ b/src/Event/Middleware/StatelessRequest.php @@ -4,9 +4,14 @@ namespace Auth0\Laravel\Event\Middleware; -final class StatelessRequest extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Middleware\StatelessRequest +use Auth0\Laravel\Contract\Event\Middleware\StatelessRequest as StatelessRequestContract; +use Auth0\Laravel\Event\Auth0Event; +use Illuminate\Contracts\Auth\Guard; +use Illuminate\Http\Request; + +final class StatelessRequest extends Auth0Event implements StatelessRequestContract { - public function __construct(public \Illuminate\Http\Request $request, public \Illuminate\Contracts\Auth\Guard $guard) + public function __construct(public Request $request, public Guard $guard) { } } diff --git a/src/Event/Stateful/AuthenticationFailed.php b/src/Event/Stateful/AuthenticationFailed.php index 87c9064f..826bed1c 100644 --- a/src/Event/Stateful/AuthenticationFailed.php +++ b/src/Event/Stateful/AuthenticationFailed.php @@ -4,51 +4,40 @@ namespace Auth0\Laravel\Event\Stateful; -final class AuthenticationFailed extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Stateful\AuthenticationFailed +use Auth0\Laravel\Contract\Event\Stateful\AuthenticationFailed as AuthenticationFailedContract; +use Auth0\Laravel\Event\Auth0Event; +use Throwable; + +final class AuthenticationFailed extends Auth0Event implements AuthenticationFailedContract { - /** - * {@inheritdoc} - */ public function __construct( - private \Throwable $exception, + private Throwable $exception, private bool $throwException = true, ) { } - /** - * {@inheritdoc} - */ - public function setException(\Throwable $exception): self + public function getException(): Throwable { - $this->exception = $exception; - $this->mutated = true; - - return $this; + return $this->exception; } - /** - * {@inheritdoc} - */ - public function getException(): \Throwable + public function getThrowException(): bool { - return $this->exception; + return $this->throwException; } - /** - * {@inheritdoc} - */ - public function setThrowException(bool $throwException): self + public function setException(Throwable $exception): self { - $this->throwException = $throwException; + $this->exception = $exception; + $this->mutated = true; return $this; } - /** - * {@inheritdoc} - */ - public function getThrowException(): bool + public function setThrowException(bool $throwException): self { - return $this->throwException; + $this->throwException = $throwException; + + return $this; } } diff --git a/src/Event/Stateful/AuthenticationSucceeded.php b/src/Event/Stateful/AuthenticationSucceeded.php index 35d2eaac..a4e8c4c7 100644 --- a/src/Event/Stateful/AuthenticationSucceeded.php +++ b/src/Event/Stateful/AuthenticationSucceeded.php @@ -4,33 +4,26 @@ namespace Auth0\Laravel\Event\Stateful; +use Auth0\Laravel\Contract\Event\Stateful\AuthenticationSucceeded as AuthenticationSucceededContract; +use Auth0\Laravel\Event\Auth0Event; use Illuminate\Contracts\Auth\Authenticatable; -final class AuthenticationSucceeded extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Stateful\AuthenticationSucceeded +final class AuthenticationSucceeded extends Auth0Event implements AuthenticationSucceededContract { - /** - * {@inheritdoc} - */ public function __construct(private Authenticatable $user) { } - /** - * {@inheritdoc} - */ + public function getUser(): Authenticatable + { + return $this->user; + } + public function setUser(Authenticatable $user): self { - $this->user = $user; + $this->user = $user; $this->mutated = true; return $this; } - - /** - * {@inheritdoc} - */ - public function getUser(): Authenticatable - { - return $this->user; - } } diff --git a/src/Event/Stateful/TokenExpired.php b/src/Event/Stateful/TokenExpired.php index 337f4b74..0602fbc2 100644 --- a/src/Event/Stateful/TokenExpired.php +++ b/src/Event/Stateful/TokenExpired.php @@ -4,6 +4,9 @@ namespace Auth0\Laravel\Event\Stateful; -final class TokenExpired extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Stateful\TokenExpired +use Auth0\Laravel\Contract\Event\Stateful\TokenExpired as TokenExpiredContract; +use Auth0\Laravel\Event\Auth0Event; + +final class TokenExpired extends Auth0Event implements TokenExpiredContract { } diff --git a/src/Event/Stateful/TokenRefreshFailed.php b/src/Event/Stateful/TokenRefreshFailed.php index a430dc18..ef3dc9fe 100644 --- a/src/Event/Stateful/TokenRefreshFailed.php +++ b/src/Event/Stateful/TokenRefreshFailed.php @@ -4,6 +4,9 @@ namespace Auth0\Laravel\Event\Stateful; -final class TokenRefreshFailed extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Stateful\TokenRefreshFailed +use Auth0\Laravel\Contract\Event\Stateful\TokenRefreshFailed as TokenRefreshFailedContract; +use Auth0\Laravel\Event\Auth0Event; + +final class TokenRefreshFailed extends Auth0Event implements TokenRefreshFailedContract { } diff --git a/src/Event/Stateful/TokenRefreshSucceeded.php b/src/Event/Stateful/TokenRefreshSucceeded.php index 2708c856..320f0619 100644 --- a/src/Event/Stateful/TokenRefreshSucceeded.php +++ b/src/Event/Stateful/TokenRefreshSucceeded.php @@ -4,6 +4,9 @@ namespace Auth0\Laravel\Event\Stateful; -final class TokenRefreshSucceeded extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Stateful\TokenRefreshSucceeded +use Auth0\Laravel\Contract\Event\Stateful\TokenRefreshSucceeded as TokenRefreshSucceededContract; +use Auth0\Laravel\Event\Auth0Event; + +final class TokenRefreshSucceeded extends Auth0Event implements TokenRefreshSucceededContract { } diff --git a/src/Event/Stateless/TokenVerificationAttempting.php b/src/Event/Stateless/TokenVerificationAttempting.php index 08c795d1..beefe4c4 100644 --- a/src/Event/Stateless/TokenVerificationAttempting.php +++ b/src/Event/Stateless/TokenVerificationAttempting.php @@ -4,32 +4,26 @@ namespace Auth0\Laravel\Event\Stateless; -final class TokenVerificationAttempting extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Stateless\TokenVerificationAttempting +use Auth0\Laravel\Contract\Event\Stateless\TokenVerificationAttempting as TokenVerificationAttemptingContract; +use Auth0\Laravel\Event\Auth0Event; + +final class TokenVerificationAttempting extends Auth0Event implements TokenVerificationAttemptingContract { - /** - * {@inheritdoc} - */ public function __construct( - private string $token + private string $token, ) { } - /** - * {@inheritdoc} - */ + public function getToken(): string + { + return $this->token; + } + public function setToken(string $token): self { - $this->token = $token; + $this->token = $token; $this->mutated = true; return $this; } - - /** - * {@inheritdoc} - */ - public function getToken(): string - { - return $this->token; - } } diff --git a/src/Event/Stateless/TokenVerificationFailed.php b/src/Event/Stateless/TokenVerificationFailed.php index 5aa6fdac..72dc8993 100644 --- a/src/Event/Stateless/TokenVerificationFailed.php +++ b/src/Event/Stateless/TokenVerificationFailed.php @@ -4,32 +4,25 @@ namespace Auth0\Laravel\Event\Stateless; +use Auth0\Laravel\Contract\Event\Stateless\TokenVerificationFailed as TokenVerificationFailedContract; +use Auth0\Laravel\Event\Auth0Event; use Throwable; -final class TokenVerificationFailed extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Stateless\TokenVerificationFailed +final class TokenVerificationFailed extends Auth0Event implements TokenVerificationFailedContract { - /** - * {@inheritdoc} - */ public function __construct( private string $token, - private Throwable $exception + private Throwable $exception, ) { } - /** - * {@inheritdoc} - */ - public function getToken(): string + public function getException(): Throwable { - return $this->token; + return $this->exception; } - /** - * {@inheritdoc} - */ - public function getException(): Throwable + public function getToken(): string { - return $this->exception; + return $this->token; } } diff --git a/src/Event/Stateless/TokenVerificationSucceeded.php b/src/Event/Stateless/TokenVerificationSucceeded.php index eb650742..cf820645 100644 --- a/src/Event/Stateless/TokenVerificationSucceeded.php +++ b/src/Event/Stateless/TokenVerificationSucceeded.php @@ -4,30 +4,24 @@ namespace Auth0\Laravel\Event\Stateless; -final class TokenVerificationSucceeded extends \Auth0\Laravel\Event\Auth0Event implements \Auth0\Laravel\Contract\Event\Stateless\TokenVerificationSucceeded +use Auth0\Laravel\Contract\Event\Stateless\TokenVerificationSucceeded as TokenVerificationSucceededContract; +use Auth0\Laravel\Event\Auth0Event; + +final class TokenVerificationSucceeded extends Auth0Event implements TokenVerificationSucceededContract { - /** - * {@inheritdoc} - */ public function __construct( private string $token, - private array $payload + private array $payload, ) { } - /** - * {@inheritdoc} - */ - public function getToken(): string + public function getPayload(): array { - return $this->token; + return $this->payload; } - /** - * {@inheritdoc} - */ - public function getPayload(): array + public function getToken(): string { - return $this->payload; + return $this->token; } } diff --git a/src/Exception/AuthenticationException.php b/src/Exception/AuthenticationException.php new file mode 100644 index 00000000..ab018a37 --- /dev/null +++ b/src/Exception/AuthenticationException.php @@ -0,0 +1,16 @@ +getSdk(); + } + + // @phpstan-ignore-next-line + return Auth0::getSdk(); + } +} diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index 98213778..e112a84a 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -4,39 +4,41 @@ namespace Auth0\Laravel\Http\Controller\Stateful; -use Auth0\Laravel\Contract\Auth\Guard; - -final class Callback implements \Auth0\Laravel\Contract\Http\Controller\Stateful\Callback +use Auth0\Laravel\Auth\Guard; +use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Contract\Http\Controller\Stateful\Callback as CallbackContract; +use Auth0\Laravel\Event\Stateful\{AuthenticationFailed, AuthenticationSucceeded}; +use Auth0\Laravel\Exception\Stateful\CallbackException; +use Auth0\Laravel\Http\Controller\ControllerAbstract; +use Illuminate\Auth\Events\{Attempting, Authenticated, Failed, Validated}; +use Illuminate\Contracts\Auth\Authenticatable; +use Illuminate\Http\{RedirectResponse, Request}; +use Throwable; +use function is_string; + +final class Callback extends ControllerAbstract implements CallbackContract { - /** - * {@inheritdoc} - */ - public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse - { - /** - * @var \Illuminate\Contracts\Auth\Factory $auth - */ - $auth = auth(); - - /** - * @var Guard $guard - */ - $guard = $auth->guard('auth0'); + public function __invoke( + Request $request, + ): RedirectResponse { + $guard = auth()->guard(); - // Check if the user already has a session: - if ($guard->check()) { - // They do; redirect to homepage. - return redirect()->intended(config('auth0.routes.home', '/')); // @phpstan-ignore-line + if (! $guard instanceof GuardContract || $guard->check()) { + return redirect()->intended(config('auth0.routes.home', '/')); } - $code = $request->query('code'); - $state = $request->query('state'); + /** @var Guard $guard */ + $code = $request->query('code'); + $state = $request->query('state'); + $code = is_string($code) ? trim($code) : ''; + $state = is_string($state) ? trim($state) : ''; + $success = false; - if (! \is_string($code) || '' === $code) { + if ('' === $code) { $code = null; } - if (! \is_string($state) || '' === $state) { + if ('' === $state) { $state = null; } @@ -47,28 +49,28 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re try { if (null !== $code && null !== $state) { - event(new \Illuminate\Auth\Events\Attempting($guard::class, ['code' => $code, 'state' => $state], true)); + event(new Attempting($guard::class, ['code' => $code, 'state' => $state], true)); - app(\Auth0\Laravel\Auth0::class)->getSdk()->exchange( + $success = $this->getSdk()->exchange( code: $code, state: $state, ); } - } catch (\Throwable $exception) { - $credentials = app(\Auth0\Laravel\Auth0::class)->getSdk()->getUser() ?? []; - $credentials['code'] = $code; + } catch (Throwable $exception) { + $credentials = $this->getSdk()->getUser() ?? []; + $credentials['code'] = $code; $credentials['state'] = $state; $credentials['error'] = ['description' => $exception->getMessage()]; - event(new \Illuminate\Auth\Events\Failed($guard::class, $guard->user(), $credentials)); + event(new Failed($guard::class, $guard->user(), $credentials)); - app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); + $this->getSdk()->clear(); // Throw hookable $event to allow custom error handling scenarios. - $event = new \Auth0\Laravel\Event\Stateful\AuthenticationFailed($exception, true); + $event = new AuthenticationFailed($exception, true); event($event); - // If the event was not hooked by the host application, throw an exception: + // If the event was not hooked by the application, throw an exception: if ($event->getThrowException()) { throw $exception; } @@ -76,55 +78,62 @@ public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\Re if (null !== $request->query('error') && null !== $request->query('error_description')) { // Workaround to aid static analysis, due to the mixed formatting of the query() response: - $error = $request->query('error', ''); + $error = $request->query('error', ''); $errorDescription = $request->query('error_description', ''); - $error = \is_string($error) ? $error : ''; - $errorDescription = \is_string($errorDescription) ? $errorDescription : ''; + $error = is_string($error) ? $error : ''; + $errorDescription = is_string($errorDescription) ? $errorDescription : ''; + + event(new Attempting($guard::class, ['code' => $code, 'state' => $state], true)); - $credentials = [ - 'code' => $code, + event(new Failed($guard::class, $guard->user(), [ + 'code' => $code, 'state' => $state, 'error' => ['error' => $error, 'description' => $errorDescription] - ]; - - event(new \Illuminate\Auth\Events\Failed($guard::class, $guard->user(), $credentials)); + ])); // Clear the local session via the Auth0-PHP SDK: - app(\Auth0\Laravel\Auth0::class)->getSdk()->clear(); + $this->getSdk()->clear(); - // Create a dynamic exception to report the API error response: - $exception = \Auth0\Laravel\Exception\Stateful\CallbackException::apiException($error, $errorDescription); + // Create a dynamic exception to report the API error response + $exception = new CallbackException(sprintf(CallbackException::MSG_API_RESPONSE, $error, $errorDescription)); + + // Store the API exception in the session as a flash variable, in case the application wants to access it. + session()->flash('auth0.callback.error', sprintf(CallbackException::MSG_API_RESPONSE, $error, $errorDescription)); // Throw hookable $event to allow custom error handling scenarios: - $event = new \Auth0\Laravel\Event\Stateful\AuthenticationFailed($exception, true); + $event = new AuthenticationFailed($exception, true); event($event); - // If the event was not hooked by the host application, throw an exception: + // If the event was not hooked by the application, throw an exception: if ($event->getThrowException()) { throw $exception; } } - // Ensure we have a valid user: - $user = $guard->user(); + if (! $success) { + return redirect()->intended(config('auth0.routes.login', '/')); + } + + $credential = $guard->find(Guard::SOURCE_SESSION); + $user = $credential?->getUser(); - if (null !== $user) { - event(new \Illuminate\Auth\Events\Validated($guard::class, $user)); + if (null !== $credential && $user instanceof Authenticatable) { + event(new Validated($guard::class, $user)); + $guard->login($credential, Guard::SOURCE_SESSION); $request->session()->regenerate(); - // Throw hookable event to allow custom application logic for successful logins: - $event = new \Auth0\Laravel\Event\Stateful\AuthenticationSucceeded($user); + $event = new AuthenticationSucceeded($user); event($event); $user = $event->getUser(); - - // Apply any mutations to the user object: $guard->setUser($user); - event(new \Illuminate\Auth\Events\Login($guard::class, $user, true)); - event(new \Illuminate\Auth\Events\Authenticated($guard::class, $user)); + // @phpstan-ignore-next-line + if ($user instanceof Authenticatable) { + event(new Authenticated($guard::class, $user)); + } } - return redirect()->intended(config('auth0.routes.home', '/')); // @phpstan-ignore-line + return redirect()->intended(config('auth0.routes.home', '/')); } } diff --git a/src/Http/Controller/Stateful/Login.php b/src/Http/Controller/Stateful/Login.php index 2b8fca3f..f734c6f3 100644 --- a/src/Http/Controller/Stateful/Login.php +++ b/src/Http/Controller/Stateful/Login.php @@ -4,31 +4,36 @@ namespace Auth0\Laravel\Http\Controller\Stateful; -use Auth0\Laravel\Contract\Auth\Guard; +use Auth0\Laravel\Auth\Guard; +use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Contract\Http\Controller\Stateful\Login as LoginContract; +use Auth0\Laravel\Http\Controller\ControllerAbstract; +use Illuminate\Http\{RedirectResponse, Request}; -final class Login implements \Auth0\Laravel\Contract\Http\Controller\Stateful\Login +final class Login extends ControllerAbstract implements LoginContract { /** - * {@inheritdoc} - * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + * + * @param Request $request */ - public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse - { - $auth = auth(); - - /** - * @var \Illuminate\Contracts\Auth\Factory $auth - */ - $guard = $auth->guard('auth0'); - - /** - * @var Guard $guard - */ - if ($guard->check()) { - return redirect()->intended(config('auth0.routes.home', '/')); // @phpstan-ignore-line + public function __invoke( + Request $request, + ): RedirectResponse { + $guard = auth()->guard(); + + if (! $guard instanceof GuardContract) { + return redirect()->intended(config('auth0.routes.home', '/')); } - return redirect()->away(app(\Auth0\Laravel\Auth0::class)->getSdk()->login()); + $loggedIn = $guard->check() ? true : null !== $guard->find(Guard::SOURCE_SESSION); + + if ($loggedIn) { + return redirect()->intended(config('auth0.routes.home', '/')); + } + + $url = $this->getSdk()->login(); + + return redirect()->away($url); } } diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index 0b1eccf2..bf639f15 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -4,35 +4,43 @@ namespace Auth0\Laravel\Http\Controller\Stateful; -use Auth0\Laravel\Contract\Auth\Guard; - -final class Logout implements \Auth0\Laravel\Contract\Http\Controller\Stateful\Logout +use Auth0\Laravel\Auth\Guard; +use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Contract\Http\Controller\Stateful\Logout as LogoutContract; +use Auth0\Laravel\Http\Controller\ControllerAbstract; +use Illuminate\Http\{RedirectResponse, Request}; +use function is_string; + +final class Logout extends ControllerAbstract implements LogoutContract { /** - * {@inheritdoc} + * @psalm-suppress RedundantCastGivenDocblockType + * + * @param Request $request */ - public function __invoke(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse - { - $auth = auth(); + public function __invoke( + Request $request, + ): RedirectResponse { + $guard = auth()->guard(); - /** - * @var \Illuminate\Contracts\Auth\Factory $auth - */ - $guard = $auth->guard('auth0'); + if (! $guard instanceof GuardContract) { + return redirect()->intended(config('auth0.routes.home', '/')); + } - /** - * @var Guard $guard - */ - if ($guard->check()) { - $request->session()->invalidate(); + $loggedIn = $guard->check() ? true : null !== $guard->find(Guard::SOURCE_SESSION); + if ($loggedIn) { + session()->invalidate(); $guard->logout(); - return redirect()->away( - app(\Auth0\Laravel\Auth0::class)->getSdk()->authentication()->getLogoutLink(url(http://github.com/config('auth0.routes.home',%20'/'))), // @phpstan-ignore-line - ); + $route = config('auth0.routes.home'); + $route = is_string($route) ? $route : '/'; + $route = (string) url(http://github.com/$route); /** @phpstan-ignore-line */ + $url = $this->getSdk()->authentication()->getLogoutLink($route); + + return redirect()->away($url); } - return redirect()->intended(config('auth0.routes.home', '/')); // @phpstan-ignore-line + return redirect()->intended(config('auth0.routes.home', '/')); } } diff --git a/src/Http/Middleware/MiddlewareAbstract.php b/src/Http/Middleware/MiddlewareAbstract.php new file mode 100644 index 00000000..f2671f64 --- /dev/null +++ b/src/Http/Middleware/MiddlewareAbstract.php @@ -0,0 +1,12 @@ +guard(); + + if (! $guard instanceof GuardContract) { + abort(Response::HTTP_INTERNAL_SERVER_ERROR, 'Internal Server Error'); + } - /** - * @var \Illuminate\Contracts\Auth\Factory $auth - */ - $guard = $auth->guard('auth0'); + /** @var Guard $guard */ + event(new StatefulRequest($request, $guard)); - event(new \Auth0\Laravel\Event\Middleware\StatefulRequest($request, $guard)); + $credential = $guard->find(Guard::SOURCE_SESSION); - /** - * @var Guard $guard - */ - $user = $guard->user(); + if (null !== $credential) { + if ('' === $scope || $guard->hasScope($scope, $credential)) { + $guard->login($credential, Guard::SOURCE_SESSION); - if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { - $guard->login($user); + return $next($request); + } - return $next($request); + abort(Response::HTTP_FORBIDDEN, 'Forbidden'); } return redirect(config('auth0.routes.login', 'login')); // @phpstan-ignore-line diff --git a/src/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Http/Middleware/Stateful/AuthenticateOptional.php index 2e15dbbd..6c4363b9 100644 --- a/src/Http/Middleware/Stateful/AuthenticateOptional.php +++ b/src/Http/Middleware/Stateful/AuthenticateOptional.php @@ -4,36 +4,40 @@ namespace Auth0\Laravel\Http\Middleware\Stateful; -use Auth0\Laravel\Contract\Auth\Guard; +use Auth0\Laravel\Auth\Guard; +use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Contract\Http\Middleware\Stateful\AuthenticateOptional as AuthenticateOptionalContract; +use Auth0\Laravel\Event\Middleware\StatefulRequest; +use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; +use Closure; +use Illuminate\Http\{JsonResponse, Request, Response}; +use Illuminate\Routing\Redirector; /** * This middleware will configure the authenticated user for the session using a * previously established Auth0-PHP SDK session. If a session is not available, * the authenticated user will be set as null. */ -final class AuthenticateOptional implements \Auth0\Laravel\Contract\Http\Middleware\Stateful\AuthenticateOptional +final class AuthenticateOptional extends MiddlewareAbstract implements AuthenticateOptionalContract { - /** - * {@inheritdoc} - */ - public function handle(\Illuminate\Http\Request $request, \Closure $next) - { - $auth = auth(); - - /** - * @var \Illuminate\Contracts\Auth\Factory $auth - */ - $guard = $auth->guard('auth0'); - - event(new \Auth0\Laravel\Event\Middleware\StatefulRequest($request, $guard)); - - /** - * @var Guard $guard - */ - $user = $guard->user(); - - if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateful\User) { - $guard->login($user); + public function handle( + Request $request, + Closure $next, + string $scope = '', + ): Response | Redirector | JsonResponse { + $guard = auth()->guard(); + + if (! $guard instanceof GuardContract) { + abort(Response::HTTP_INTERNAL_SERVER_ERROR, 'Internal Server Error'); + } + + /** @var Guard $guard */ + event(new StatefulRequest($request, $guard)); + + $credential = $guard->find(Guard::SOURCE_SESSION); + + if (null !== $credential && ('' === $scope || $guard->hasScope($scope, $credential))) { + $guard->login($credential, Guard::SOURCE_SESSION); } return $next($request); diff --git a/src/Http/Middleware/Stateless/Authorize.php b/src/Http/Middleware/Stateless/Authorize.php index 2479732b..15a36999 100644 --- a/src/Http/Middleware/Stateless/Authorize.php +++ b/src/Http/Middleware/Stateless/Authorize.php @@ -4,43 +4,46 @@ namespace Auth0\Laravel\Http\Middleware\Stateless; -use Auth0\Laravel\Contract\Auth\Guard; +use Auth0\Laravel\Auth\Guard; +use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Contract\Http\Middleware\Stateless\Authorize as AuthorizeContract; +use Auth0\Laravel\Event\Middleware\StatelessRequest; +use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; +use Closure; +use Illuminate\Http\{JsonResponse, Request, Response}; /** * This middleware will configure the authenticated user using an available access token. * If a token is not available, it will raise an exception. */ -final class Authorize implements \Auth0\Laravel\Contract\Http\Middleware\Stateless\Authorize +final class Authorize extends MiddlewareAbstract implements AuthorizeContract { - /** - * {@inheritdoc} - */ - public function handle(\Illuminate\Http\Request $request, \Closure $next, string $scope = '') - { - $auth = auth(); - - /** - * @var \Illuminate\Contracts\Auth\Factory $auth - */ - $guard = $auth->guard('auth0'); - - event(new \Auth0\Laravel\Event\Middleware\StatelessRequest($request, $guard)); - - /** - * @var Guard $guard - */ - $user = $guard->user(); - - if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { - if ('' !== $scope && ! $guard->hasScope($scope)) { - abort(403, 'Forbidden'); - } + public function handle( + Request $request, + Closure $next, + string $scope = '', + ): Response | JsonResponse { + $guard = auth()->guard(); + + if (! $guard instanceof GuardContract) { + return $next($request); + } - $guard->login($user); + /** @var Guard $guard */ + event(new StatelessRequest($request, $guard)); - return $next($request); + $credential = $guard->find(Guard::SOURCE_TOKEN); + + if (null !== $credential) { + if ('' === $scope || $guard->hasScope($scope, $credential)) { + $guard->login($credential, Guard::SOURCE_TOKEN); + + return $next($request); + } + + abort(Response::HTTP_FORBIDDEN, 'Forbidden'); } - abort(401, 'Unauthorized'); + abort(Response::HTTP_UNAUTHORIZED, 'Unauthorized'); } } diff --git a/src/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Http/Middleware/Stateless/AuthorizeOptional.php index c97c2459..12f7389f 100644 --- a/src/Http/Middleware/Stateless/AuthorizeOptional.php +++ b/src/Http/Middleware/Stateless/AuthorizeOptional.php @@ -4,34 +4,39 @@ namespace Auth0\Laravel\Http\Middleware\Stateless; -use Auth0\Laravel\Contract\Auth\Guard; +use Auth0\Laravel\Auth\Guard; +use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Contract\Http\Middleware\Stateless\AuthorizeOptional as AuthorizeOptionalContract; +use Auth0\Laravel\Event\Middleware\StatelessRequest; +use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; +use Closure; +use Illuminate\Http\{JsonResponse, Request, Response}; /** * This middleware will configure the authenticated user using an available access token. */ -final class AuthorizeOptional implements \Auth0\Laravel\Contract\Http\Middleware\Stateless\AuthorizeOptional +final class AuthorizeOptional extends MiddlewareAbstract implements AuthorizeOptionalContract { - /** - * {@inheritdoc} - */ - public function handle(\Illuminate\Http\Request $request, \Closure $next) - { - $auth = auth(); - - /** - * @var \Illuminate\Contracts\Auth\Factory $auth - */ - $guard = $auth->guard('auth0'); - - event(new \Auth0\Laravel\Event\Middleware\StatelessRequest($request, $guard)); - - /** - * @var Guard $guard - */ - $user = $guard->user(); - - if (null !== $user && $user instanceof \Auth0\Laravel\Contract\Model\Stateless\User) { - $guard->login($user); + public function handle( + Request $request, + Closure $next, + string $scope = '', + ): Response | JsonResponse { + $guard = auth()->guard(); + + if (! $guard instanceof GuardContract) { + return $next($request); + } + + /** @var Guard $guard */ + event(new StatelessRequest($request, $guard)); + + $credential = $guard->find(Guard::SOURCE_TOKEN); + + if (null !== $credential && ('' === $scope || $guard->hasScope($scope, $credential))) { + $guard->login($credential, Guard::SOURCE_TOKEN); + + return $next($request); } return $next($request); diff --git a/src/Model/Imposter.php b/src/Model/Imposter.php new file mode 100644 index 00000000..8c7c02ed --- /dev/null +++ b/src/Model/Imposter.php @@ -0,0 +1,11 @@ +fill($attributes); } - /** - * {@inheritdoc} - */ - public function __get(string $key) + public function __get(string $key): mixed { return $this->getAttribute($key); } - /** - * {@inheritdoc} - */ public function __set(string $key, $value): void { $this->setAttribute($key, $value); } - /** - * {@inheritdoc} - */ final public function fill(array $attributes): self { foreach ($attributes as $key => $value) { @@ -42,70 +33,59 @@ final public function fill(array $attributes): self return $this; } - /** - * {@inheritdoc} - */ - final public function setAttribute(string $key, $value): self + final public function getAttribute(string $key, $default = null): mixed { - $this->attributes[$key] = $value; - - return $this; + return $this->attributes[$key] ?? $default; } - /** - * {@inheritdoc} - */ - final public function getAttribute(string $key, $default = null) + final public function getAttributes(): mixed { - return $this->attributes[$key] ?? $default; + return $this->attributes; } - /** - * {@inheritdoc} - */ - final public function getAuthIdentifier() + final public function getAuthIdentifier(): int | string | null { return $this->attributes['sub'] ?? $this->attributes['user_id'] ?? $this->attributes['email'] ?? null; } - /** - * {@inheritdoc} - */ - final public function getAuthIdentifierName() + final public function getAuthIdentifierName(): string { return 'id'; } - /** - * {@inheritdoc} - */ final public function getAuthPassword(): string { return ''; } - /** - * {@inheritdoc} - */ final public function getRememberToken(): string { return ''; } - /** - * {@inheritdoc} - * - * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter - */ - final public function setRememberToken($value): void + final public function getRememberTokenName(): string + { + return ''; + } + + final public function jsonSerialize(): mixed { + return $this->attributes; + } + + final public function setAttribute(string $key, mixed $value): self + { + $this->attributes[$key] = $value; + + return $this; } /** - * {@inheritdoc} + * @inheritdoc + * + * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ - final public function getRememberTokenName(): string + final public function setRememberToken($value): void { - return ''; } } diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index ca9e8315..4c05b0fb 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -5,60 +5,72 @@ namespace Auth0\Laravel; use Auth0\Laravel\Auth\Guard; -use Auth0\Laravel\Auth\User\Provider; -use Auth0\Laravel\Auth\User\Repository; -use Auth0\Laravel\Http\Controller\Stateful\Callback; -use Auth0\Laravel\Http\Controller\Stateful\Login; -use Auth0\Laravel\Http\Controller\Stateful\Logout; -use Auth0\Laravel\Http\Middleware\Stateful\Authenticate; -use Auth0\Laravel\Http\Middleware\Stateful\AuthenticateOptional; -use Auth0\Laravel\Http\Middleware\Stateless\Authorize; -use Auth0\Laravel\Http\Middleware\Stateless\AuthorizeOptional; +use Auth0\Laravel\Auth\User\{Provider, Repository}; +use Auth0\Laravel\Contract\ServiceProvider as ServiceProviderContract; +use Auth0\Laravel\Http\Controller\Stateful\{Callback, Login, Logout}; +use Auth0\Laravel\Http\Middleware\Stateful\{Authenticate, AuthenticateOptional}; +use Auth0\Laravel\Http\Middleware\Stateless\{Authorize, AuthorizeOptional}; +use Auth0\Laravel\Store\LaravelSession; +use Illuminate\Auth\AuthManager; +use Illuminate\Contracts\Foundation\Application; +use Illuminate\Routing\Router; +use Illuminate\Support\ServiceProvider as LaravelServiceProvider; -final class ServiceProvider extends \Illuminate\Support\ServiceProvider implements \Auth0\Laravel\Contract\ServiceProvider +final class ServiceProvider extends LaravelServiceProvider implements ServiceProviderContract { - public function provides() - { - return [Auth0::class, StateInstance::class, Repository::class, Guard::class, Provider::class, Authenticate::class, AuthenticateOptional::class, Authorize::class, AuthorizeOptional::class, Login::class, Logout::class, Callback::class]; - } - - public function register(): self - { + public function boot( + Router $router, + AuthManager $auth, + ): self { $this->mergeConfigFrom(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'config', 'auth0.php']), 'auth0'); + $this->publishes([implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'config', 'auth0.php']) => config_path('auth0.php')], 'auth0-config'); - app()->singleton(Auth0::class, static fn (): Auth0 => new Auth0()); - app()->singleton(StateInstance::class, static fn (): StateInstance => new StateInstance()); - app()->singleton(Repository::class, static fn (): Repository => new Repository()); - app()->singleton(Guard::class, static fn (): Guard => new Guard()); - app()->singleton(Provider::class, static fn (): Provider => new Provider()); - app()->singleton(Authenticate::class, static fn (): Authenticate => new Authenticate()); - app()->singleton(AuthenticateOptional::class, static fn (): AuthenticateOptional => new AuthenticateOptional()); - app()->singleton(Authorize::class, static fn (): Authorize => new Authorize()); - app()->singleton(AuthorizeOptional::class, static fn (): AuthorizeOptional => new AuthorizeOptional()); - app()->singleton(Login::class, static fn (): Login => new Login()); - app()->singleton(Logout::class, static fn (): Logout => new Logout()); - app()->singleton(Callback::class, static fn (): Callback => new Callback()); - - app()->singleton('auth0', static fn (): Auth0 => app(Auth0::class)); + $auth->extend('auth0.guard', static fn (Application $app, string $name, array $config): Guard => new Guard($name, $config)); + $auth->provider('auth0.provider', static fn (Application $app, array $config): Provider => new Provider($config)); - app()->terminating(static function (): void { - app()->instance(StateInstance::class, null); - }); + $router->aliasMiddleware('auth0.authenticate.optional', AuthenticateOptional::class); + $router->aliasMiddleware('auth0.authenticate', Authenticate::class); + $router->aliasMiddleware('auth0.authorize.optional', AuthorizeOptional::class); + $router->aliasMiddleware('auth0.authorize', Authorize::class); return $this; } - public function boot(\Illuminate\Routing\Router $router, \Illuminate\Auth\AuthManager $auth): self + public function provides() { - $this->publishes([implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'config', 'auth0.php']) => config_path('auth0.php')], 'auth0-config'); + return [ + Auth0::class, + Authenticate::class, + AuthenticateOptional::class, + Authorize::class, + AuthorizeOptional::class, + Callback::class, + Guard::class, + LaravelSession::class, + Login::class, + Logout::class, + Provider::class, + Repository::class + ]; + } - $auth->extend('auth0', static fn (): Guard => new Guard()); - $auth->provider('auth0', static fn (): Provider => new Provider()); + public function register(): self + { + $this->app->singleton(Auth0::class, static fn (): Auth0 => new Auth0()); + $this->app->singleton(Authenticate::class, static fn (): Authenticate => new Authenticate()); + $this->app->singleton(AuthenticateOptional::class, static fn (): AuthenticateOptional => new AuthenticateOptional()); + $this->app->singleton(Authorize::class, static fn (): Authorize => new Authorize()); + $this->app->singleton(AuthorizeOptional::class, static fn (): AuthorizeOptional => new AuthorizeOptional()); + $this->app->singleton(Callback::class, static fn (): Callback => new Callback()); + $this->app->singleton(Login::class, static fn (): Login => new Login()); + $this->app->singleton(Logout::class, static fn (): Logout => new Logout()); + $this->app->singleton(Provider::class, static fn (): Provider => new Provider()); + $this->app->singleton(Repository::class, static fn (): Repository => new Repository()); - $router->aliasMiddleware('auth0.authenticate', Authenticate::class); - $router->aliasMiddleware('auth0.authenticate.optional', AuthenticateOptional::class); - $router->aliasMiddleware('auth0.authorize', Authorize::class); - $router->aliasMiddleware('auth0.authorize.optional', AuthorizeOptional::class); + $this->app->singleton('auth0', static fn (): Auth0 => app(Auth0::class)); + $this->app->singleton('auth0.guard', static fn (): Guard => app(Guard::class)); + $this->app->singleton('auth0.provider', static fn (): Provider => app(Provider::class)); + $this->app->singleton('auth0.repository', static fn (): Repository => app(Repository::class)); return $this; } diff --git a/src/Store/LaravelSession.php b/src/Store/LaravelSession.php index 0dca8976..9cdc555b 100644 --- a/src/Store/LaravelSession.php +++ b/src/Store/LaravelSession.php @@ -4,8 +4,10 @@ namespace Auth0\Laravel\Store; +use Auth0\Laravel\Exception\SessionException; use Auth0\SDK\Contract\StoreInterface; -use Exception; +use Illuminate\Session\Store; +use InvalidArgumentException; /** * Class LaravelSession @@ -14,120 +16,153 @@ final class LaravelSession implements StoreInterface { public function __construct( - private string $prefix = 'auth0', - private bool $booted = false, + string $prefix = 'auth0', ) { + $this->setPrefix($prefix); } /** - * Dispatch event to toggle state deferrance. + * Prefixes a key with the SDK's configured namespace. * - * @param bool $deferring whether to defer persisting the storage state + * @param string $key */ - public function defer(bool $deferring): void + private function getPrefixedKey(string $key): string { + return $this->getPrefix() . '_' . trim($key); } /** - * Dispatch event to set the value of a key-value pair. + * Retrieves the Laravel session store. + * + * @throws SessionException If a Laravel session store is not available. * - * @param string $key session key to set - * @param mixed $value value to use + * @psalm-suppress RedundantConditionGivenDocblockType */ - public function set(string $key, $value): void + private function getStore(): Store { - $this->boot(); - $this->getStore()-> - put($this->getPrefixedKey($key), $value); + $store = app('session.store'); + + if (! request()->hasSession(true)) { + request()->setLaravelSession($store); + } + + if (! $store->isStarted()) { + $store->start(); + } + + return $store; } /** - * Dispatch event to retrieve the value of a key-value pair. + * This method is required by the interface but is not used by this SDK. * - * @param string $key session key to query - * @param mixed $default default to return if nothing was found - * @return mixed + * @param bool $deferring whether to defer persisting the storage state */ - public function get(string $key, $default = null) + public function defer(bool $deferring): void { - $this->boot(); - - return $this->getStore()-> - get($this->getPrefixedKey($key), $default); } /** - * Dispatch event to clear all key-value pairs. + * Delete a value from the Laravel session by key. (Key will be automatically prefixed with the SDK's configured namespace.). + * + * @param string $key session key to delete + * + * @throws SessionException If a Laravel session store is not available. */ - public function purge(): void + public function delete(string $key): void { - $this->boot(); + $this->getStore()->forget($this->getPrefixedKey($key)); + } - // It would be unwise for us to simply flush() a session here, as it is shared with the app ecosystem. - // Instead, iterate through the session data, and if they key is prefixed with our assigned string, delete it. + /** + * Retrieve a value from the Laravel session by key. (Key will be automatically prefixed with the SDK's configured namespace.). + * + * @param string $key session key to query + * @param mixed $default default to return if nothing was found + * + * @throws SessionException If a Laravel session store is not available. + */ + public function get(string $key, $default = null) + { + return $this->getStore()->get($this->getPrefixedKey($key), $default); + } - $pairs = $this->getStore()-> - all(); - $prefix = $this->prefix . '_'; + /** + * Get all values from the Laravel session that are prefixed with the SDK's configured namespace. + * + * @throws SessionException If a Laravel session store is not available. + */ + public function getAll(): array + { + $pairs = $this->getStore()->all(); + $prefix = $this->prefix . '_'; + $response = []; foreach (array_keys($pairs) as $key) { if (mb_substr($key, 0, mb_strlen($prefix)) === $prefix) { - $this->delete($key); + $response[$key] = $pairs[$key]; } } + + return $response; } /** - * Dispatch event to delete key-value pair. + * Get the prefix used for all session keys. * - * @param string $key session key to delete + * @return string Prefix used for all session keys. */ - public function delete(string $key): void + public function getPrefix(): string { - $this->boot(); - $this->getStore()-> - forget($this->getPrefixedKey($key)); + return $this->prefix; } /** - * Dispatch event to alert that a session should be prepared for an incoming request. + * Delete all values from the Laravel session that are prefixed with the SDK's configured namespace. + * + * @throws SessionException If a Laravel session store is not available. */ - private function boot(): void + public function purge(): void { - if (! $this->booted) { - if (! $this->getStore()->isStarted()) { - $this->getStore()-> - start(); - } + $entities = $this->getAll(); - $this->booted = true; + foreach (array_keys($entities) as $entity) { + $this->getStore()->forget($entity); } } /** - * {@inheritdoc} + * Store a value in the Laravel session. (Key will be automatically prefixed with the SDK's configured namespace.). * - * @psalm-suppress RedundantConditionGivenDocblockType + * @param string $key session key to set + * @param mixed $value value to use + * + * @throws SessionException If a Laravel session store is not available. */ - private function getStore(): \Illuminate\Session\Store + public function set(string $key, $value): void { - $request = request(); - - // @phpstan-ignore-next-line - if ($request instanceof \Illuminate\Http\Request) { - return $request->session(); - } - - // @phpstan-ignore-next-line - throw new Exception('A cache must be configured.'); + $this->getStore()->put($this->getPrefixedKey($key), $value); } - private function getPrefixedKey(string $key): string - { - if ('' !== $this->prefix) { - return $this->prefix . '_' . $key; + /** + * Set the prefix used for all session keys. + * + * @param string $prefix Prefix to use for all session keys. + * + * @return $this + */ + public function setPrefix( + string $prefix = 'auth0', + ): self { + $prefix = trim($prefix); + + if ('' === $prefix) { + throw new InvalidArgumentException('Prefix cannot be empty.'); } - return $key; + $this->prefix = $prefix; + + return $this; } + private string $prefix = 'auth0'; } From c74cfad64e423ffe5e1a146c6ad521f3887da119 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 15:58:49 -0500 Subject: [PATCH 207/525] Update CHANGELOG.md --- CHANGELOG.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00f0a12e..acf2a301 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,17 +2,37 @@ ## [Unreleased] +Most of these changes rely on upstream changes in the Auth0-PHP SDK that are waiting for release. +These changes will not function correctly until that release is made. + **Added** - Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) -- New `Auth0\Laravel\Traits\Imposter` trait to allow for easier testing. +- New `Auth0\Laravel\Traits\Imposter` trait to allow for easier testing. [Example usage](./tests/Unit/Traits/ImpersonateTest.php) +- New Exception types have been added for more precise error catching. **Changed** The following changes have no effect on the external API of this package, but may affect internal usage. +- `Guard` will now more reliably detect changes in the underlying Auth0-PHP SDK session state. +- `Guard` will now more reliably sync changes back to the underlying Auth0-PHP SDK session state. +- `Guard` now inherits the `DeferrableProvider` interface to better support Laravel's deferred provider loading. - `StateInstance` concept has been replaced by new `Credentials` entity. - `Guard` updated to use new `Credentials` entity as primary internal storage for user data. - `Auth0\Laravel\Traits\ActingAsAuth0User` was updated to use new`Credentials` entity. +- The HTTP middleware have been refactored to more clearly differentiate between token and session based identities. +- The `authenticate`, `authenticate.optional` and `authorize.optional` HTTP middleware now support scope filtering, as `authorize` already did. + +**Fixed** + +- A 'Session store not set on request' error could occur when downstream applications implemented unit testing that use the Guard. This should be resolved now. +- An issue wherein the `Guard` would not always honor the `provider` configuration value in `config/auth.php`. +- `Guard` is no longer defined as a Singleton to better support applications that need multi-guard configurations. + +**Maintenance** + +- Reworked test suite to use PEST framework. +- Restored test coverage to 100%. Thanks to our contributors for this release: [taida957789](https://github.com/taida957789) From be08c5cc2feefdbf0524d34d82c71a2bde55e621 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 16:01:40 -0500 Subject: [PATCH 208/525] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f57414d0..39bf73c6 100644 --- a/README.md +++ b/README.md @@ -241,7 +241,8 @@ Our support lifecycle mirrors the [Laravel release support](https://laravel.com/ | SDK Version | Laravel Version | PHP Version | Support Ends | | ----------- | --------------- | ----------- | ------------ | -| 7.5+ | 10 | 8.2 | Feb 2024 | +| 7.5+ | 10 | 8.2 | Feb 2025 | +| | | 8.1 | Nov 2024 | | 7.0+ | 9 | 8.2 | Feb 2024 | | | | 8.1 | Feb 2024 | | | | 8.0 | Nov 2023 | From f4591b3dda27b497ff7cf4264d03a606a59921a4 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 16:09:15 -0500 Subject: [PATCH 209/525] Update README.md --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 39bf73c6..70b7acd8 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. ## Documentation - Stateful Applications - - [Quickstart](https://auth0.com/docs/quickstart/webapp/laravel) — add login, logout and user information to a Laravel application using Auth0. + - [Quickstart](https://auth0.com/docs/quickstart/webapp/laravel) — add login, logout, and user information to a Laravel application using Auth0. - [Sample Application](https://github.com/auth0-samples/auth0-laravel-php-web-app) — a sample Laravel web application integrated with Auth0. - Stateless Applications - [Quickstart](https://auth0.com/docs/quickstart/backend/php) — add access token handling and route authorization to a backend Laravel application using Auth0. @@ -22,10 +22,8 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. ### Requirements -- PHP 8.0+ +- Laravel 10 (PHP 8.1+) or Laravel 9 (PHP 8.0+) - [Composer](https://getcomposer.org/) -- Laravel 9.0+, 10.0+ - - `Illuminate\Session\Middleware\StartSession` enabled in `app/Http/Kernel.php` - PHP Extensions: - [mbstring](https://www.php.net/manual/en/book.mbstring.php) - Dependencies: From d19df4a9449fe008ed6a7109320e95b511a0aed6 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 18:39:22 -0500 Subject: [PATCH 210/525] Remove obsolete script call --- composer.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/composer.json b/composer.json index a6a51864..edd4fd90 100644 --- a/composer.json +++ b/composer.json @@ -115,8 +115,6 @@ "phpcs:fix": "@php vendor/bin/php-cs-fixer fix src", "phpcs": "@php vendor/bin/php-cs-fixer fix src --dry-run --diff", "phpstan": "@php vendor/bin/phpstan analyse --debug", - "pint:fix": "@php vendor/bin/pint", - "pint": "@php vendor/bin/pint --test", "psalm:fix": "@php vendor/bin/psalter --issues=all", "psalm": "@php vendor/bin/psalm --no-cache", "rector:fix": "@php vendor/bin/rector process src", From a1e2401c7a7dddf41ef8f9a7d2858f1cc0017962 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 14 Mar 2023 18:39:34 -0500 Subject: [PATCH 211/525] README corrections --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 70b7acd8..caa83f2d 100644 --- a/README.md +++ b/README.md @@ -50,13 +50,13 @@ Create a **Regular Web Application** in the [Auth0 Dashboard](https://manage.aut Next, configure the callback and logout URLs for your application under the "Application URIs" section of the "Settings" page: - **Allowed Callback URLs**: The URL of your application where Auth0 will redirect to during authentication, e.g., `http://localhost:3000/callback`. -- **Allowed Logout URLs**: The URL of your application where Auth0 will redirect to after user logout, e.g., `http://localhost:3000/login`. +- **Allowed Logout URLs**: The URL of your application where Auth0 will redirect to after logout, e.g., `http://localhost:3000/login`. Note the **Domain**, **Client ID**, and **Client Secret**. These values will be used during configuration later. ### Publish SDK configuration -Use Laravel's CLI to generate an Auth0 configuration file within your project: +Use Laravels CLI to generate an Auth0 configuration file within your project: ``` php artisan vendor:publish --tag auth0-config @@ -64,7 +64,7 @@ php artisan vendor:publish --tag auth0-config A new file will appear within your project, `app/config/auth0.php`. You should avoid making changes to this file directly. -### Configure your `.env` file +### Configure `.env` file Open the `.env` file within your application's directory, and add the following lines appropriate for your application type: @@ -193,9 +193,9 @@ Route::get('/', function () {
Stateless Backend Applications -These are applications that accept an a Access Token through the 'Authorization' header of a request. +These are applications that accept an Access Token through the 'Authorization' header of a request. -The `auth0.authorize` middleware will resolve a Access Token and reject any request with an invalid token. +The `auth0.authorize` middleware will resolve an Access Token and reject any request with an invalid token. ```php Route::get('/api/private', function () { From 12eff1f258c929aee356ceeeb13ebed71f3d6f4c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 16 Mar 2023 00:54:28 -0500 Subject: [PATCH 212/525] Test fixes for upstream dependency changes --- tests/Unit/Auth/GuardStatefulTest.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/Unit/Auth/GuardStatefulTest.php b/tests/Unit/Auth/GuardStatefulTest.php index f65bfa59..36575e4d 100644 --- a/tests/Unit/Auth/GuardStatefulTest.php +++ b/tests/Unit/Auth/GuardStatefulTest.php @@ -234,18 +234,18 @@ $streamFactory = $this->config->getHttpStreamFactory(); $responseFactory = $this->config->getHttpResponseFactory(); - $http->queueResponse( - $responseFactory::create( - body: $streamFactory->createStream( - json_encode([ - 'access_token' => uniqid(), - 'expires_in' => 60, - 'scope' => 'openid profile', - 'token_type' => 'Bearer', - ], JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR) - ) - ) - ); + $response = $responseFactory->createResponse(); + + $response = $response->withBody($streamFactory->createStream( + json_encode([ + 'access_token' => uniqid(), + 'expires_in' => 60, + 'scope' => 'openid profile', + 'token_type' => 'Bearer', + ], JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR) + )); + + $http->addResponseWildcard($response); $found = $this->guard->find(Guard::SOURCE_SESSION); $this->guard->login($found, Guard::SOURCE_SESSION); From 62d2306370124a6dc06b7ddef106f8df93110b56 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 16 Mar 2023 00:57:41 -0500 Subject: [PATCH 213/525] Updates to workflows --- .github/workflows/checks.yml | 301 ------------------- .github/workflows/maintenance.yml | 22 -- .github/workflows/php_composer_normalize.yml | 17 ++ .github/workflows/php_composer_validate.yml | 17 ++ .github/workflows/php_pest.yml | 39 +++ .github/workflows/php_phpcsf.yml | 44 +++ .github/workflows/php_phpstan.yml | 34 +++ .github/workflows/php_psalm.yml | 34 +++ .github/workflows/php_rector.yml | 32 ++ .github/workflows/rep_cleanup.yml | 41 +++ .github/workflows/rep_opened.yml | 68 +++++ .github/workflows/rep_stale.yml | 19 ++ .github/workflows/sec_semgrep.yml | 43 +++ .github/workflows/sec_snyk.yml | 54 ++++ .github/workflows/security.yml | 84 ------ 15 files changed, 442 insertions(+), 407 deletions(-) delete mode 100644 .github/workflows/checks.yml delete mode 100644 .github/workflows/maintenance.yml create mode 100644 .github/workflows/php_composer_normalize.yml create mode 100644 .github/workflows/php_composer_validate.yml create mode 100644 .github/workflows/php_pest.yml create mode 100644 .github/workflows/php_phpcsf.yml create mode 100644 .github/workflows/php_phpstan.yml create mode 100644 .github/workflows/php_psalm.yml create mode 100644 .github/workflows/php_rector.yml create mode 100644 .github/workflows/rep_cleanup.yml create mode 100644 .github/workflows/rep_opened.yml create mode 100644 .github/workflows/rep_stale.yml create mode 100644 .github/workflows/sec_semgrep.yml create mode 100644 .github/workflows/sec_snyk.yml delete mode 100644 .github/workflows/security.yml diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml deleted file mode 100644 index 2d965938..00000000 --- a/.github/workflows/checks.yml +++ /dev/null @@ -1,301 +0,0 @@ -name: Checks - -on: - push: - branches: - - main - pull_request: - -jobs: - dependencies: - name: Dependencies - runs-on: ubuntu-latest - - strategy: - max-parallel: 10 - matrix: - php: ["8.0", "8.1", "8.2"] - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: mbstring - env: - update: true - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - - name: Install dependencies with composer - run: composer update --no-ansi --no-interaction --no-progress --prefer-dist --prefer-stable - - normalize: - name: Normalize - runs-on: ubuntu-latest - needs: ["dependencies"] - - strategy: - fail-fast: true - max-parallel: 10 - matrix: - php: ["8.0"] - - steps: - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: mbstring - env: - update: true - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - - name: Install dependencies - run: composer install --prefer-dist - - - name: Execute Normalize - run: composer normalize - - pest: - name: Pest - runs-on: ubuntu-latest - continue-on-error: true - needs: ["dependencies"] - - strategy: - max-parallel: 10 - matrix: - php: ["8.0", "8.1", "8.2"] - - steps: - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: pcov - extensions: mbstring - env: - update: true - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - - name: Install dependencies with composer - run: composer install --prefer-dist - - - name: Execute Pest - run: vendor/bin/pest --coverage-clover coverage/coverage.xml --no-interaction - - - if: (matrix.php == '8.1') - uses: codecov/codecov-action@v2 - with: - directory: coverage - - phpstan: - name: PHPStan - runs-on: ubuntu-latest - needs: ["dependencies"] - - strategy: - fail-fast: true - max-parallel: 10 - matrix: - php: ["8.0", "8.1", "8.2"] - - steps: - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: mbstring - env: - update: true - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - - name: Install dependencies - run: composer install --prefer-dist - - - name: Execute PHPStan - run: vendor/bin/phpstan analyze --no-progress - - psalm: - name: Psalm - runs-on: ubuntu-latest - needs: ["dependencies"] - - strategy: - fail-fast: true - max-parallel: 10 - matrix: - php: ["8.0", "8.1", "8.2"] - - steps: - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: mbstring - env: - update: true - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - - name: Install dependencies - run: composer install --prefer-dist - - - name: Execute Psalm - run: vendor/bin/psalm --no-progress - - pint: - name: Laravel Pint - runs-on: ubuntu-latest - needs: ["dependencies"] - - strategy: - fail-fast: true - max-parallel: 10 - matrix: - php: ["8.0", "8.1", "8.2"] - - steps: - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: mbstring - env: - update: true - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - - name: Install dependencies - run: composer install --prefer-dist - - - name: Execute Laravel Pint - run: vendor/bin/pint --test - - rector: - name: Rector - runs-on: ubuntu-latest - needs: ["dependencies"] - - strategy: - fail-fast: true - max-parallel: 10 - matrix: - php: ["8.0", "8.1", "8.2"] - - steps: - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: mbstring - env: - update: true - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - restore-keys: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ github.run_id }} - - - name: Install dependencies - run: composer install --prefer-dist - - - name: Execute Rector - run: vendor/bin/rector process src --dry-run diff --git a/.github/workflows/maintenance.yml b/.github/workflows/maintenance.yml deleted file mode 100644 index a862d87a..00000000 --- a/.github/workflows/maintenance.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: 'Repository Maintenance' - -on: - schedule: - - cron: '0 0 * * *' - workflow_dispatch: - -permissions: - issues: write - pull-requests: write - -concurrency: - group: lock - -jobs: - action: - runs-on: ubuntu-latest - steps: - - uses: dessant/lock-threads@v3 - with: - issue-inactive-days: '30' - pr-inactive-days: '30' diff --git a/.github/workflows/php_composer_normalize.yml b/.github/workflows/php_composer_normalize.yml new file mode 100644 index 00000000..fc025b42 --- /dev/null +++ b/.github/workflows/php_composer_normalize.yml @@ -0,0 +1,17 @@ +on: + pull_request_target: + types: + - labeled + push: + branches: + - main + +jobs: + normalize: + name: Composer Normalize + runs-on: ubuntu-latest + if: github.event.label.name == 'run' || github.ref_name == 'main' + + steps: + - uses: actions/checkout@v3 + - uses: docker://ergebnis/composer-normalize-action diff --git a/.github/workflows/php_composer_validate.yml b/.github/workflows/php_composer_validate.yml new file mode 100644 index 00000000..fc251f8a --- /dev/null +++ b/.github/workflows/php_composer_validate.yml @@ -0,0 +1,17 @@ +on: + pull_request_target: + types: + - labeled + push: + branches: + - main + +jobs: + validate: + name: Composer Validate + runs-on: ubuntu-latest + if: github.event.label.name == 'run' || github.ref_name == 'main' + + steps: + - uses: actions/checkout@v3 + - run: composer validate diff --git a/.github/workflows/php_pest.yml b/.github/workflows/php_pest.yml new file mode 100644 index 00000000..48ad08ad --- /dev/null +++ b/.github/workflows/php_pest.yml @@ -0,0 +1,39 @@ +on: + pull_request_target: + types: + - labeled + push: + branches: + - main + +jobs: + pest: + name: PEST + runs-on: ${{ matrix.operating-systems }} + if: github.event.label.name == 'run' || github.ref_name == 'main' + + strategy: + fail-fast: false + matrix: + operating-systems: + - ubuntu-latest + php-versions: + - 8.1 + - 8.2 + + steps: + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: pcov + extensions: mbstring, openssl + + - uses: actions/checkout@v3 + + - run: composer install --prefer-dist + - run: vendor/bin/pest --coverage-clover coverage/coverage.xml --no-interaction --order-by random + + - if: (matrix.php == '8.1') + uses: codecov/codecov-action@v2 + with: + directory: coverage diff --git a/.github/workflows/php_phpcsf.yml b/.github/workflows/php_phpcsf.yml new file mode 100644 index 00000000..8cdaf6f7 --- /dev/null +++ b/.github/workflows/php_phpcsf.yml @@ -0,0 +1,44 @@ +on: + pull_request_target: + types: + - labeled + push: + branches: + - main + +jobs: + pint: + name: Pint + runs-on: ${{ matrix.operating-systems }} + if: github.event.label.name == 'run' || github.ref_name == 'main' + + strategy: + fail-fast: false + matrix: + operating-systems: + - ubuntu-latest + php-versions: + - 8.0 + - 8.1 + - 8.2 + + steps: + - uses: actions/checkout@v3 + + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: pcov + + - id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - run: composer install --no-progress --prefer-dist --optimize-autoloader + + # - run: vendor/bin/php-cs-fixer fix src --dry-run --diff diff --git a/.github/workflows/php_phpstan.yml b/.github/workflows/php_phpstan.yml new file mode 100644 index 00000000..7b0c14ae --- /dev/null +++ b/.github/workflows/php_phpstan.yml @@ -0,0 +1,34 @@ +on: + pull_request_target: + types: + - labeled + push: + branches: + - main + +jobs: + phpstan: + name: PHPStan + runs-on: ${{ matrix.operating-systems }} + if: github.event.label.name == 'run' || github.ref_name == 'main' + + strategy: + fail-fast: false + matrix: + operating-systems: + - ubuntu-latest + php-versions: + - 8.0 + - 8.1 + - 8.2 + + steps: + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: pcov + extensions: mbstring, openssl + + - uses: actions/checkout@v3 + - run: composer update --no-ansi --no-interaction --no-progress --prefer-dist --prefer-stable + - run: vendor/bin/phpstan analyze --no-progress diff --git a/.github/workflows/php_psalm.yml b/.github/workflows/php_psalm.yml new file mode 100644 index 00000000..d521d313 --- /dev/null +++ b/.github/workflows/php_psalm.yml @@ -0,0 +1,34 @@ +on: + pull_request_target: + types: + - labeled + push: + branches: + - main + +jobs: + psalm: + name: Psalm + runs-on: ${{ matrix.operating-systems }} + if: github.event.label.name == 'run' || github.ref_name == 'main' + + strategy: + fail-fast: false + matrix: + operating-systems: + - ubuntu-latest + php-versions: + - 8.0 + - 8.1 + - 8.2 + + steps: + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: pcov + extensions: mbstring, openssl + + - uses: actions/checkout@v3 + - run: composer update --no-ansi --no-interaction --no-progress --prefer-dist --prefer-stable + - run: vendor/bin/psalm --no-progress diff --git a/.github/workflows/php_rector.yml b/.github/workflows/php_rector.yml new file mode 100644 index 00000000..2ee6e3e0 --- /dev/null +++ b/.github/workflows/php_rector.yml @@ -0,0 +1,32 @@ +on: + pull_request_target: + types: + - labeled + push: + branches: + - main + +jobs: + rector: + name: Rector + runs-on: ${{ matrix.operating-systems }} + if: github.event.label.name == 'run' || github.ref_name == 'main' + + strategy: + fail-fast: false + matrix: + operating-systems: + - ubuntu-latest + php-versions: + - 8.0 + + steps: + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: pcov + extensions: mbstring, openssl + + - uses: actions/checkout@v3 + - run: composer update --no-ansi --no-interaction --no-progress --prefer-dist --prefer-stable + - run: vendor/bin/rector process src --dry-run diff --git a/.github/workflows/rep_cleanup.yml b/.github/workflows/rep_cleanup.yml new file mode 100644 index 00000000..aa6a6991 --- /dev/null +++ b/.github/workflows/rep_cleanup.yml @@ -0,0 +1,41 @@ +on: + pull_request_target: + types: + - closed + - reopened + - converted_to_draft + - review_requested + - review_request_removed + - synchronize + +jobs: + rep-cleanup: + name: Issue/PR Cleanup + runs-on: ubuntu-latest + + permissions: + issues: write + pull-requests: write + + steps: + - uses: actions/github-script@v6 + with: + script: | + try { + labels = await github.rest.issues.listLabelsOnIssue({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo + }) + + if (labels.data.some(label => label.name === 'run')) { + github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + name: 'run' + }); + } + } catch (error) { + console.error(error); + } diff --git a/.github/workflows/rep_opened.yml b/.github/workflows/rep_opened.yml new file mode 100644 index 00000000..2062ee75 --- /dev/null +++ b/.github/workflows/rep_opened.yml @@ -0,0 +1,68 @@ +on: + pull_request_target: + types: + - opened + +permissions: + issues: write + pull-requests: write + +jobs: + rep-opened: + name: PR/Issue Setup + runs-on: ubuntu-latest + + steps: + - uses: actions/github-script@v6 + with: + script: | + const pattern = /^(\w*)(?:\(([\w]*)\))?: (.*)$/; + const title = context.payload.pull_request.title + const [type, scope, subject] = title.match(pattern).slice(1); + + console.log(`Type: ${type}`, `Scope: ${scope}`, `Subject: ${subject}`) + + if (type !== undefined) { + const labels = { + 'feat': 'type-improvement', + 'refactor': 'type-improvement', + 'perf': 'type-improvement', + 'build': 'type-chore', + 'cj': 'type-chore', + 'style': 'type-chore', + 'fix': 'type-bug', + 'security': 'type-security', + 'docs': 'type-documentation', + 'test': 'type-tests', + 'release': 'type-release', + } + + if (type in labels) { + github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: [labels[type]] + }) + } + } + + let isMember = false; + + try { + isMember = await github.rest.orgs.checkMembershipForUser({ + org: context.repo.owner, + username: context.payload.pull_request.user.login + }); + } catch (error) { + console.error(error); + } + + if (! isMember) { + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: '**👋 Thanks for contributing!** Please be patient while a maintainer reviews your PR. In the meantime, please make sure you\'ve read our [contributing guide](CONTRIBUTING.md).' + }) + } diff --git a/.github/workflows/rep_stale.yml b/.github/workflows/rep_stale.yml new file mode 100644 index 00000000..c7df6b16 --- /dev/null +++ b/.github/workflows/rep_stale.yml @@ -0,0 +1,19 @@ +on: + schedule: + - cron: "30 1 * * *" + +permissions: + issues: write + pull-requests: write + +jobs: + rep-stale: + name: Issue/PR Maintenance + runs-on: ubuntu-latest + + steps: + - uses: actions/stale@v6 + with: + days-before-stale: 7 + days-before-close: 14 + repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/sec_semgrep.yml b/.github/workflows/sec_semgrep.yml new file mode 100644 index 00000000..fba212c7 --- /dev/null +++ b/.github/workflows/sec_semgrep.yml @@ -0,0 +1,43 @@ +on: + pull_request_target: + types: + - labeled + push: + branches: + - main + +permissions: + security-events: write + +jobs: + semgrep: + name: Semgrep + runs-on: ubuntu-latest + if: github.event.label.name == 'run' || github.ref_name == 'main' + + container: + image: returntocorp/semgrep + + steps: + - uses: actions/checkout@v3 + + - run: semgrep scan --sarif --output=semgrep.sarif + env: + SEMGREP_RULES: >- + p/phpcs-security-audit + p/security-audit + p/secrets + p/owasp-top-ten + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} + SEMGREP_REPO_NAME: "auth0/auth0-PHP" + SEMGREP_REPO_URL: "https://github.com/auth0/auth0-PHP" + + - uses: andstor/file-existence-action@v1 + id: sarif_file_exists + with: + files: "semgrep.sarif" + + - uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: semgrep.sarif + if: always() diff --git a/.github/workflows/sec_snyk.yml b/.github/workflows/sec_snyk.yml new file mode 100644 index 00000000..8d7306d3 --- /dev/null +++ b/.github/workflows/sec_snyk.yml @@ -0,0 +1,54 @@ +on: + pull_request_target: + types: + - labeled + push: + branches: + - main + +permissions: + security-events: write + +jobs: + snyk: + name: Snyk + runs-on: ${{ matrix.operating-systems }} + if: github.event.label.name == 'run' || github.ref_name == 'main' + + strategy: + fail-fast: false + matrix: + operating-systems: + - ubuntu-latest + php-versions: + - 8.0 + + steps: + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: none + extensions: mbstring + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/checkout@v3 + + - run: composer update --no-interaction --no-progress + + - uses: snyk/actions/php@master + continue-on-error: true + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + with: + args: --severity-threshold=high --sarif-file-output=snyk.sarif + + - uses: andstor/file-existence-action@v1 + id: sarif_file_exists + with: + files: "snyk.sarif" + + - uses: github/codeql-action/upload-sarif@v2 + if: steps.sarif_file_exists.outputs.files_exists == 'true' + with: + sarif_file: snyk.sarif diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml deleted file mode 100644 index 10fd3096..00000000 --- a/.github/workflows/security.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: Security - -on: - push: - branches: - - main - pull_request: - -jobs: - snyk: - name: Snyk - runs-on: ubuntu-latest - strategy: - max-parallel: 10 - matrix: - php: ["8.0", "8.1", "8.2"] - - if: (github.actor != 'dependabot[bot]') - steps: - - name: Set up PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: mbstring - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Install dependencies - run: composer update --no-interaction --no-progress - - - name: Run Snyk to check for vulnerabilities - uses: snyk/actions/php@master - continue-on-error: true - env: - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} - with: - args: --severity-threshold=high --sarif-file-output=snyk.sarif - - - name: Check to see if the SARIF a was generated - id: sarif_file_exists - uses: andstor/file-existence-action@v1 - with: - files: "snyk.sarif" - - - name: Upload result to GitHub Code Scanning - uses: github/codeql-action/upload-sarif@v2 - if: steps.sarif_file_exists.outputs.files_exists == 'true' - with: - sarif_file: snyk.sarif - - semgrep: - name: Semgrep - runs-on: ubuntu-latest - container: - image: returntocorp/semgrep - - if: (github.actor != 'dependabot[bot]') - steps: - - uses: actions/checkout@v3 - - - run: semgrep scan --sarif --output=semgrep.sarif - env: - SEMGREP_RULES: >- - p/phpcs-security-audit - p/security-audit - p/secrets - p/owasp-top-ten - SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} - SEMGREP_REPO_NAME: "auth0/laravel-auth0" - SEMGREP_REPO_URL: "https://github.com/auth0/laravel-auth0" - - - name: Check to see if the SARIF a was generated - id: sarif_file_exists - uses: andstor/file-existence-action@v1 - with: - files: "semgrep.sarif" - - - name: Upload SARIF file for GitHub Advanced Security Dashboard - uses: github/codeql-action/upload-sarif@v2 - with: - sarif_file: semgrep.sarif - if: always() From e93f8f01070fe01d41611d53be6c54e9bdf4dc3d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 16 Mar 2023 01:02:28 -0500 Subject: [PATCH 214/525] Temporarily point to dev build of upstream SDK --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index edd4fd90..38a28785 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "php": "^8.0", "ext-json": "*", "ext-mbstring": "*", - "auth0/auth0-php": "^8.3.4", + "auth0/auth0-php": "dev-main", "illuminate/contracts": "^9.0 || ^10.0", "illuminate/http": "^9.0 || ^10.0", "illuminate/support": "^9.0 || ^10.0", From db789945809f95d26a7b7428471dcbc367aac002 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 16 Mar 2023 01:18:22 -0500 Subject: [PATCH 215/525] Update workflows --- .github/workflows/php_phpcsf.yml | 2 -- .github/workflows/php_phpstan.yml | 2 -- .github/workflows/php_psalm.yml | 4 +--- .github/workflows/php_rector.yml | 2 +- 4 files changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/php_phpcsf.yml b/.github/workflows/php_phpcsf.yml index 8cdaf6f7..4cdd007e 100644 --- a/.github/workflows/php_phpcsf.yml +++ b/.github/workflows/php_phpcsf.yml @@ -19,8 +19,6 @@ jobs: - ubuntu-latest php-versions: - 8.0 - - 8.1 - - 8.2 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/php_phpstan.yml b/.github/workflows/php_phpstan.yml index 7b0c14ae..48b49a35 100644 --- a/.github/workflows/php_phpstan.yml +++ b/.github/workflows/php_phpstan.yml @@ -19,8 +19,6 @@ jobs: - ubuntu-latest php-versions: - 8.0 - - 8.1 - - 8.2 steps: - uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/php_psalm.yml b/.github/workflows/php_psalm.yml index d521d313..e862196e 100644 --- a/.github/workflows/php_psalm.yml +++ b/.github/workflows/php_psalm.yml @@ -19,8 +19,6 @@ jobs: - ubuntu-latest php-versions: - 8.0 - - 8.1 - - 8.2 steps: - uses: shivammathur/setup-php@v2 @@ -31,4 +29,4 @@ jobs: - uses: actions/checkout@v3 - run: composer update --no-ansi --no-interaction --no-progress --prefer-dist --prefer-stable - - run: vendor/bin/psalm --no-progress + # - run: vendor/bin/psalm --no-progress diff --git a/.github/workflows/php_rector.yml b/.github/workflows/php_rector.yml index 2ee6e3e0..5ac776e6 100644 --- a/.github/workflows/php_rector.yml +++ b/.github/workflows/php_rector.yml @@ -29,4 +29,4 @@ jobs: - uses: actions/checkout@v3 - run: composer update --no-ansi --no-interaction --no-progress --prefer-dist --prefer-stable - - run: vendor/bin/rector process src --dry-run + # - run: vendor/bin/rector process src --dry-run From 924fdceeb1a6fc3354c44e1788c8e88cf0d963d4 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 16 Mar 2023 01:22:02 -0500 Subject: [PATCH 216/525] Update workflows --- .github/workflows/php_composer_normalize.yml | 3 ++- .github/workflows/php_composer_validate.yml | 3 ++- .github/workflows/php_pest.yml | 5 +++-- .github/workflows/php_phpcsf.yml | 5 +++-- .github/workflows/php_phpstan.yml | 3 ++- .github/workflows/php_psalm.yml | 3 ++- .github/workflows/php_rector.yml | 3 ++- .github/workflows/rep_cleanup.yml | 3 ++- .github/workflows/rep_opened.yml | 3 ++- .github/workflows/rep_stale.yml | 3 ++- .github/workflows/sec_semgrep.yml | 9 +++++---- .github/workflows/sec_snyk.yml | 13 +++++++------ 12 files changed, 34 insertions(+), 22 deletions(-) diff --git a/.github/workflows/php_composer_normalize.yml b/.github/workflows/php_composer_normalize.yml index fc025b42..d806197d 100644 --- a/.github/workflows/php_composer_normalize.yml +++ b/.github/workflows/php_composer_normalize.yml @@ -1,3 +1,5 @@ +name: Composer Normalize + on: pull_request_target: types: @@ -8,7 +10,6 @@ on: jobs: normalize: - name: Composer Normalize runs-on: ubuntu-latest if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/php_composer_validate.yml b/.github/workflows/php_composer_validate.yml index fc251f8a..38fdf69a 100644 --- a/.github/workflows/php_composer_validate.yml +++ b/.github/workflows/php_composer_validate.yml @@ -1,3 +1,5 @@ +name: Composer Validate + on: pull_request_target: types: @@ -8,7 +10,6 @@ on: jobs: validate: - name: Composer Validate runs-on: ubuntu-latest if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/php_pest.yml b/.github/workflows/php_pest.yml index 48ad08ad..2bf990ed 100644 --- a/.github/workflows/php_pest.yml +++ b/.github/workflows/php_pest.yml @@ -1,3 +1,5 @@ +name: PEST + on: pull_request_target: types: @@ -8,7 +10,6 @@ on: jobs: pest: - name: PEST runs-on: ${{ matrix.operating-systems }} if: github.event.label.name == 'run' || github.ref_name == 'main' @@ -33,7 +34,7 @@ jobs: - run: composer install --prefer-dist - run: vendor/bin/pest --coverage-clover coverage/coverage.xml --no-interaction --order-by random - - if: (matrix.php == '8.1') + - if: (matrix.php-versions == '8.1') uses: codecov/codecov-action@v2 with: directory: coverage diff --git a/.github/workflows/php_phpcsf.yml b/.github/workflows/php_phpcsf.yml index 4cdd007e..d1296fb7 100644 --- a/.github/workflows/php_phpcsf.yml +++ b/.github/workflows/php_phpcsf.yml @@ -1,3 +1,5 @@ +name: PHPCSF + on: pull_request_target: types: @@ -7,8 +9,7 @@ on: - main jobs: - pint: - name: Pint + phpcs: runs-on: ${{ matrix.operating-systems }} if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/php_phpstan.yml b/.github/workflows/php_phpstan.yml index 48b49a35..3e0acfbf 100644 --- a/.github/workflows/php_phpstan.yml +++ b/.github/workflows/php_phpstan.yml @@ -1,3 +1,5 @@ +name: PHPStan + on: pull_request_target: types: @@ -8,7 +10,6 @@ on: jobs: phpstan: - name: PHPStan runs-on: ${{ matrix.operating-systems }} if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/php_psalm.yml b/.github/workflows/php_psalm.yml index e862196e..8d967b50 100644 --- a/.github/workflows/php_psalm.yml +++ b/.github/workflows/php_psalm.yml @@ -1,3 +1,5 @@ +name: Psalm + on: pull_request_target: types: @@ -8,7 +10,6 @@ on: jobs: psalm: - name: Psalm runs-on: ${{ matrix.operating-systems }} if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/php_rector.yml b/.github/workflows/php_rector.yml index 5ac776e6..6d610c43 100644 --- a/.github/workflows/php_rector.yml +++ b/.github/workflows/php_rector.yml @@ -1,3 +1,5 @@ +name: Rector + on: pull_request_target: types: @@ -8,7 +10,6 @@ on: jobs: rector: - name: Rector runs-on: ${{ matrix.operating-systems }} if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/rep_cleanup.yml b/.github/workflows/rep_cleanup.yml index aa6a6991..1adb8e8a 100644 --- a/.github/workflows/rep_cleanup.yml +++ b/.github/workflows/rep_cleanup.yml @@ -1,3 +1,5 @@ +name: Issue/PR Cleanup + on: pull_request_target: types: @@ -10,7 +12,6 @@ on: jobs: rep-cleanup: - name: Issue/PR Cleanup runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/rep_opened.yml b/.github/workflows/rep_opened.yml index 2062ee75..4ad9e449 100644 --- a/.github/workflows/rep_opened.yml +++ b/.github/workflows/rep_opened.yml @@ -1,3 +1,5 @@ +name: PR/Issue Setup + on: pull_request_target: types: @@ -9,7 +11,6 @@ permissions: jobs: rep-opened: - name: PR/Issue Setup runs-on: ubuntu-latest steps: diff --git a/.github/workflows/rep_stale.yml b/.github/workflows/rep_stale.yml index c7df6b16..e10df733 100644 --- a/.github/workflows/rep_stale.yml +++ b/.github/workflows/rep_stale.yml @@ -1,3 +1,5 @@ +name: Issue/PR Maintenance + on: schedule: - cron: "30 1 * * *" @@ -8,7 +10,6 @@ permissions: jobs: rep-stale: - name: Issue/PR Maintenance runs-on: ubuntu-latest steps: diff --git a/.github/workflows/sec_semgrep.yml b/.github/workflows/sec_semgrep.yml index fba212c7..455d6e62 100644 --- a/.github/workflows/sec_semgrep.yml +++ b/.github/workflows/sec_semgrep.yml @@ -1,3 +1,5 @@ +name: Semgrep + on: pull_request_target: types: @@ -11,7 +13,6 @@ permissions: jobs: semgrep: - name: Semgrep runs-on: ubuntu-latest if: github.event.label.name == 'run' || github.ref_name == 'main' @@ -20,7 +21,7 @@ jobs: steps: - uses: actions/checkout@v3 - + - run: semgrep scan --sarif --output=semgrep.sarif env: SEMGREP_RULES: >- @@ -31,12 +32,12 @@ jobs: SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} SEMGREP_REPO_NAME: "auth0/auth0-PHP" SEMGREP_REPO_URL: "https://github.com/auth0/auth0-PHP" - + - uses: andstor/file-existence-action@v1 id: sarif_file_exists with: files: "semgrep.sarif" - + - uses: github/codeql-action/upload-sarif@v2 with: sarif_file: semgrep.sarif diff --git a/.github/workflows/sec_snyk.yml b/.github/workflows/sec_snyk.yml index 8d7306d3..6535b7f7 100644 --- a/.github/workflows/sec_snyk.yml +++ b/.github/workflows/sec_snyk.yml @@ -1,3 +1,5 @@ +name: Snyk + on: pull_request_target: types: @@ -11,7 +13,6 @@ permissions: jobs: snyk: - name: Snyk runs-on: ${{ matrix.operating-systems }} if: github.event.label.name == 'run' || github.ref_name == 'main' @@ -31,23 +32,23 @@ jobs: extensions: mbstring env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - + - uses: actions/checkout@v3 - + - run: composer update --no-interaction --no-progress - + - uses: snyk/actions/php@master continue-on-error: true env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: args: --severity-threshold=high --sarif-file-output=snyk.sarif - + - uses: andstor/file-existence-action@v1 id: sarif_file_exists with: files: "snyk.sarif" - + - uses: github/codeql-action/upload-sarif@v2 if: steps.sarif_file_exists.outputs.files_exists == 'true' with: From 41e6b0b6db0e51101952a86690e6b708e39afc3c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 16 Mar 2023 01:33:03 -0500 Subject: [PATCH 217/525] Update workflows --- .github/workflows/php_composer_normalize.yml | 3 ++- .github/workflows/php_composer_validate.yml | 3 ++- .github/workflows/php_pest.yml | 3 ++- .github/workflows/php_phpcsf.yml | 3 ++- .github/workflows/php_phpstan.yml | 3 ++- .github/workflows/php_psalm.yml | 3 ++- .github/workflows/php_rector.yml | 3 ++- .github/workflows/rep_cleanup.yml | 3 ++- .github/workflows/rep_opened.yml | 3 ++- .github/workflows/rep_stale.yml | 3 ++- .github/workflows/sec_semgrep.yml | 3 ++- .github/workflows/sec_snyk.yml | 3 ++- 12 files changed, 24 insertions(+), 12 deletions(-) diff --git a/.github/workflows/php_composer_normalize.yml b/.github/workflows/php_composer_normalize.yml index d806197d..edbba57b 100644 --- a/.github/workflows/php_composer_normalize.yml +++ b/.github/workflows/php_composer_normalize.yml @@ -1,4 +1,4 @@ -name: Composer Normalize +name: Composer on: pull_request_target: @@ -10,6 +10,7 @@ on: jobs: normalize: + name: Normalize runs-on: ubuntu-latest if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/php_composer_validate.yml b/.github/workflows/php_composer_validate.yml index 38fdf69a..c2e94216 100644 --- a/.github/workflows/php_composer_validate.yml +++ b/.github/workflows/php_composer_validate.yml @@ -1,4 +1,4 @@ -name: Composer Validate +name: Composer on: pull_request_target: @@ -10,6 +10,7 @@ on: jobs: validate: + name: Validate runs-on: ubuntu-latest if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/php_pest.yml b/.github/workflows/php_pest.yml index 2bf990ed..87fef96b 100644 --- a/.github/workflows/php_pest.yml +++ b/.github/workflows/php_pest.yml @@ -1,4 +1,4 @@ -name: PEST +name: Unit Tests on: pull_request_target: @@ -10,6 +10,7 @@ on: jobs: pest: + name: PEST runs-on: ${{ matrix.operating-systems }} if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/php_phpcsf.yml b/.github/workflows/php_phpcsf.yml index d1296fb7..f260c040 100644 --- a/.github/workflows/php_phpcsf.yml +++ b/.github/workflows/php_phpcsf.yml @@ -1,4 +1,4 @@ -name: PHPCSF +name: Code Style on: pull_request_target: @@ -10,6 +10,7 @@ on: jobs: phpcs: + name: PHPCSF runs-on: ${{ matrix.operating-systems }} if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/php_phpstan.yml b/.github/workflows/php_phpstan.yml index 3e0acfbf..fce24b8c 100644 --- a/.github/workflows/php_phpstan.yml +++ b/.github/workflows/php_phpstan.yml @@ -1,4 +1,4 @@ -name: PHPStan +name: Analysis on: pull_request_target: @@ -10,6 +10,7 @@ on: jobs: phpstan: + name: PHPStan runs-on: ${{ matrix.operating-systems }} if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/php_psalm.yml b/.github/workflows/php_psalm.yml index 8d967b50..5b464562 100644 --- a/.github/workflows/php_psalm.yml +++ b/.github/workflows/php_psalm.yml @@ -1,4 +1,4 @@ -name: Psalm +name: Analysis on: pull_request_target: @@ -10,6 +10,7 @@ on: jobs: psalm: + name: Psalm runs-on: ${{ matrix.operating-systems }} if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/php_rector.yml b/.github/workflows/php_rector.yml index 6d610c43..3b1f3626 100644 --- a/.github/workflows/php_rector.yml +++ b/.github/workflows/php_rector.yml @@ -1,4 +1,4 @@ -name: Rector +name: Analysis on: pull_request_target: @@ -10,6 +10,7 @@ on: jobs: rector: + name: Rector runs-on: ${{ matrix.operating-systems }} if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/rep_cleanup.yml b/.github/workflows/rep_cleanup.yml index 1adb8e8a..32ce79f5 100644 --- a/.github/workflows/rep_cleanup.yml +++ b/.github/workflows/rep_cleanup.yml @@ -1,4 +1,4 @@ -name: Issue/PR Cleanup +name: Repository on: pull_request_target: @@ -12,6 +12,7 @@ on: jobs: rep-cleanup: + name: Cleanup runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/rep_opened.yml b/.github/workflows/rep_opened.yml index 4ad9e449..714d03cc 100644 --- a/.github/workflows/rep_opened.yml +++ b/.github/workflows/rep_opened.yml @@ -1,4 +1,4 @@ -name: PR/Issue Setup +name: Repository on: pull_request_target: @@ -11,6 +11,7 @@ permissions: jobs: rep-opened: + name: PR/Issue Setup runs-on: ubuntu-latest steps: diff --git a/.github/workflows/rep_stale.yml b/.github/workflows/rep_stale.yml index e10df733..0c6f2548 100644 --- a/.github/workflows/rep_stale.yml +++ b/.github/workflows/rep_stale.yml @@ -1,4 +1,4 @@ -name: Issue/PR Maintenance +name: Repository on: schedule: @@ -10,6 +10,7 @@ permissions: jobs: rep-stale: + name: Maintenance runs-on: ubuntu-latest steps: diff --git a/.github/workflows/sec_semgrep.yml b/.github/workflows/sec_semgrep.yml index 455d6e62..2dfe7677 100644 --- a/.github/workflows/sec_semgrep.yml +++ b/.github/workflows/sec_semgrep.yml @@ -1,4 +1,4 @@ -name: Semgrep +name: Security on: pull_request_target: @@ -13,6 +13,7 @@ permissions: jobs: semgrep: + name: Semgrep runs-on: ubuntu-latest if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/sec_snyk.yml b/.github/workflows/sec_snyk.yml index 6535b7f7..d12faff4 100644 --- a/.github/workflows/sec_snyk.yml +++ b/.github/workflows/sec_snyk.yml @@ -1,4 +1,4 @@ -name: Snyk +name: Security on: pull_request_target: @@ -13,6 +13,7 @@ permissions: jobs: snyk: + name: Snyk runs-on: ${{ matrix.operating-systems }} if: github.event.label.name == 'run' || github.ref_name == 'main' From c49616d2cde8f12dff5529b6666f4ab9616514e7 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 16 Mar 2023 01:34:52 -0500 Subject: [PATCH 218/525] Update workflows --- .github/workflows/php_phpcsf.yml | 4 ++-- .github/workflows/php_rector.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/php_phpcsf.yml b/.github/workflows/php_phpcsf.yml index f260c040..593deac0 100644 --- a/.github/workflows/php_phpcsf.yml +++ b/.github/workflows/php_phpcsf.yml @@ -1,4 +1,4 @@ -name: Code Style +name: Standards on: pull_request_target: @@ -10,7 +10,7 @@ on: jobs: phpcs: - name: PHPCSF + name: PHP CS Fixer runs-on: ${{ matrix.operating-systems }} if: github.event.label.name == 'run' || github.ref_name == 'main' diff --git a/.github/workflows/php_rector.yml b/.github/workflows/php_rector.yml index 3b1f3626..6aecf8a1 100644 --- a/.github/workflows/php_rector.yml +++ b/.github/workflows/php_rector.yml @@ -1,4 +1,4 @@ -name: Analysis +name: Standards on: pull_request_target: From e97387845f92af9050eb0acf13bb9ddb288f1ab5 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 16 Mar 2023 01:41:47 -0500 Subject: [PATCH 219/525] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index caa83f2d..48d39659 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. [![Package](https://img.shields.io/packagist/dt/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) +![Build Status](https://img.shields.io/github/checks-status/auth0/laravel-auth0/main) +[![Coverage](https://img.shields.io/codecov/c/github/auth0/laravel-auth0/main)](https://codecov.io/gh/auth0/laravel-auth0) [![License](https://img.shields.io/packagist/l/auth0/login)](https://doge.mit-license.org/) :books: [Documentation](#documentation) - :rocket: [Getting Started](#getting-started) - :speech_balloon: [Feedback](#feedback) From 331e795d03f29033723447b9c065ef61aff1fdfd Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 16 Mar 2023 16:02:39 -0500 Subject: [PATCH 220/525] Style rules update --- .php-cs-fixer.dist.php | 2 +- composer.json | 15 +++++++++++---- src/Auth/Guard.php | 10 +++++----- src/Cache/LaravelCachePool.php | 10 +++++----- src/Event/Auth0Event.php | 10 +++++----- src/Store/LaravelSession.php | 3 ++- src/Traits/ActingAsAuth0User.php | 11 ++++++----- 7 files changed, 35 insertions(+), 26 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index e0b641b3..ce007ae7 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -141,7 +141,7 @@ 'object_operator_without_whitespace' => true, 'octal_notation' => true, 'operator_linebreak' => true, - 'ordered_class_elements' => ['sort_algorithm' => 'alpha', 'order' => ['case', 'constant', 'constant_private', 'constant_protected', 'constant_public', 'construct', 'destruct', 'magic', 'method', 'method_abstract', 'method_private', 'method_private_abstract', 'method_private_abstract_static', 'method_private_static', 'method_protected', 'method_protected_abstract', 'method_protected_abstract_static', 'method_protected_static', 'method_public', 'method_public_abstract', 'method_public_abstract_static', 'method_public_static', 'method_static', 'phpunit', 'private', 'property', 'property_private', 'property_private_readonly', 'property_private_static', 'property_protected', 'property_protected_readonly', 'property_protected_static', 'property_public', 'property_public_readonly', 'property_public_static', 'property_static', 'protected', 'public', 'use_trait']], + 'ordered_class_elements' => ['sort_algorithm' => 'alpha', 'order' => ['use_trait', 'case', 'constant', 'constant_private', 'constant_protected', 'constant_public', 'property_private', 'property_private_readonly', 'property_private_static', 'property_protected', 'property_protected_readonly', 'property_protected_static', 'property_public', 'property_public_readonly', 'property_public_static', 'property_static', 'protected', 'construct', 'destruct', 'magic', 'method', 'public', 'method_abstract', 'method_private', 'method_private_abstract', 'method_private_abstract_static', 'method_private_static', 'method_protected', 'method_protected_abstract', 'method_protected_abstract_static', 'method_protected_static', 'method_public', 'method_public_abstract', 'method_public_abstract_static', 'method_public_static', 'method_static', 'phpunit', 'private', 'property']], 'ordered_imports' => ['sort_algorithm' => 'alpha', 'imports_order' => ['const', 'class', 'function']], 'ordered_interfaces' => true, 'ordered_traits' => true, diff --git a/composer.json b/composer.json index 38a28785..6564ab53 100644 --- a/composer.json +++ b/composer.json @@ -112,14 +112,21 @@ }, "scripts": { "mutate": "@php ./vendor/bin/infection --test-framework=pest --show-mutations", + "pest:coverage": "@php vendor/bin/pest --order-by random --coverage", + "pest": "@php vendor/bin/pest --order-by random", "phpcs:fix": "@php vendor/bin/php-cs-fixer fix src", "phpcs": "@php vendor/bin/php-cs-fixer fix src --dry-run --diff", - "phpstan": "@php vendor/bin/phpstan analyse --debug", + "phpstan": "@php vendor/bin/phpstan analyze", "psalm:fix": "@php vendor/bin/psalter --issues=all", - "psalm": "@php vendor/bin/psalm --no-cache", + "psalm": "@php vendor/bin/psalm", "rector:fix": "@php vendor/bin/rector process src", "rector": "@php vendor/bin/rector process src --dry-run", - "test:coverage": "@php vendor/bin/pest --order-by random --coverage", - "test": "@php vendor/bin/pest --order-by random" + "test": [ + "@pest", + "@phpstan", + "@psalm", + "@rector", + "@phpcs" + ] } } diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 3507e1bf..6555e7a3 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -33,6 +33,11 @@ final class Guard implements GuardContract public const SOURCE_IMPERSONATE = 0; // Manually set, presumably through a test case's impersonate() method. public const SOURCE_SESSION = 2; // Assigned from a session. public const SOURCE_TOKEN = 1; // Assigned from a decoded token. + private ?Credential $credential = null; + private ?int $credentialSource = null; + private bool $impersonating = false; + private ?UserProvider $provider = null; + private ?string $pushHash = null; public function __construct( private string $name = '', @@ -560,9 +565,4 @@ public function viaRemember(): bool { return false; } - private ?Credential $credential = null; - private ?int $credentialSource = null; - private bool $impersonating = false; - private ?UserProvider $provider = null; - private ?string $pushHash = null; } diff --git a/src/Cache/LaravelCachePool.php b/src/Cache/LaravelCachePool.php index ef18dba9..4a5c9025 100644 --- a/src/Cache/LaravelCachePool.php +++ b/src/Cache/LaravelCachePool.php @@ -16,6 +16,11 @@ */ final class LaravelCachePool implements CacheItemPoolInterface { + /** + * @var array + */ + private array $deferred = []; + private function createItem(string $key, mixed $value): CacheItemInterface { if (! is_string($value)) { @@ -189,9 +194,4 @@ public function saveDeferred(CacheItemInterface $item): bool return true; } - - /** - * @var array - */ - private array $deferred = []; } diff --git a/src/Event/Auth0Event.php b/src/Event/Auth0Event.php index 6adbef5e..caf58650 100644 --- a/src/Event/Auth0Event.php +++ b/src/Event/Auth0Event.php @@ -11,6 +11,11 @@ */ abstract class Auth0Event implements EventAuth0Event { + /** + * Tracks whether an event payload has been overwritten. + */ + protected bool $mutated = false; + /** * Returns whether an event payload has been overwritten. */ @@ -18,9 +23,4 @@ final public function wasMutated(): bool { return $this->mutated; } - - /** - * Tracks whether an event payload has been overwritten. - */ - protected bool $mutated = false; } diff --git a/src/Store/LaravelSession.php b/src/Store/LaravelSession.php index 9cdc555b..6913d616 100644 --- a/src/Store/LaravelSession.php +++ b/src/Store/LaravelSession.php @@ -15,6 +15,8 @@ */ final class LaravelSession implements StoreInterface { + private string $prefix = 'auth0'; + public function __construct( string $prefix = 'auth0', ) { @@ -164,5 +166,4 @@ public function setPrefix( return $this; } - private string $prefix = 'auth0'; } diff --git a/src/Traits/ActingAsAuth0User.php b/src/Traits/ActingAsAuth0User.php index 3eac4064..cfbbf1f1 100644 --- a/src/Traits/ActingAsAuth0User.php +++ b/src/Traits/ActingAsAuth0User.php @@ -15,6 +15,12 @@ */ trait ActingAsAuth0User { + public array $defaultActingAsAttributes = [ + 'sub' => 'some-auth0-user-id', + 'azp' => 'some-auth0-application-client-id', + 'scope' => '', + ]; + /** * Set the currently logged in user for the application. * @@ -49,9 +55,4 @@ public function actingAsAuth0User( } abstract public function actingAs(Authenticatable $user, $guard = null); - public array $defaultActingAsAttributes = [ - 'sub' => 'some-auth0-user-id', - 'azp' => 'some-auth0-application-client-id', - 'scope' => '', - ]; } From 9e6a592763a9001f610f879950ab723433ac1a2c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 20 Mar 2023 18:50:02 -0500 Subject: [PATCH 221/525] Update to PEST 2.0 --- composer.json | 12 ++++------ tests/Unit/Auth/GuardStatelessTest.php | 29 ----------------------- tests/Unit/Cache/LaravelCacheItemTest.php | 24 +++++++++---------- tests/Unit/Cache/LaravelCachePoolTest.php | 2 +- 4 files changed, 18 insertions(+), 49 deletions(-) diff --git a/composer.json b/composer.json index 6564ab53..5fd6ffc6 100644 --- a/composer.json +++ b/composer.json @@ -47,15 +47,13 @@ "require-dev": { "friendsofphp/php-cs-fixer": "^3.14", "infection/infection": "^0.26", - "nunomaduro/collision": "^6.1", + "mockery/mockery": "^1.5", "nunomaduro/larastan": "^2.5", "orchestra/testbench": "^7.19 || ^8.0", - "pestphp/pest": "^1.22", - "pestphp/pest-plugin-laravel": "^1.4", - "pestphp/pest-plugin-mock": "^1.0", - "phpstan/phpstan": "^1.10", + "pestphp/pest-plugin-laravel": "^2.0", + "pestphp/pest": "^2.0", "phpstan/phpstan-strict-rules": "^1.5", - "phpunit/phpunit": "^9.6", + "phpstan/phpstan": "^1.10", "psalm/plugin-laravel": "^2.8", "psr-mock/http-client-implementation": "1.x-dev", "psr-mock/http-factory-implementation": "1.x-dev", @@ -113,7 +111,7 @@ "scripts": { "mutate": "@php ./vendor/bin/infection --test-framework=pest --show-mutations", "pest:coverage": "@php vendor/bin/pest --order-by random --coverage", - "pest": "@php vendor/bin/pest --order-by random", + "pest": "@php vendor/bin/pest --order-by random --compact", "phpcs:fix": "@php vendor/bin/php-cs-fixer fix src", "phpcs": "@php vendor/bin/php-cs-fixer fix src --dry-run --diff", "phpstan": "@php vendor/bin/phpstan analyze", diff --git a/tests/Unit/Auth/GuardStatelessTest.php b/tests/Unit/Auth/GuardStatelessTest.php index bb17764f..18c41c0b 100644 --- a/tests/Unit/Auth/GuardStatelessTest.php +++ b/tests/Unit/Auth/GuardStatelessTest.php @@ -7,7 +7,6 @@ use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\SDK\Token; use Auth0\SDK\Token\Generator; -use Illuminate\Foundation\Auth\User; use Illuminate\Http\Response; use Illuminate\Support\Facades\Route; @@ -75,34 +74,6 @@ ->user()->toBeNull(); }); -it('does not accept a user when a repository returns null from a token lookup', function (): void { - $repo = mock(Repository::class)->expect( - fromAccessToken: fn (array $user) => null - ); - - app()->singleton('auth0.repository', fn () => $repo); - - getJson($this->route, $this->bearerToken) - ->assertStatus(Response::HTTP_UNAUTHORIZED); - - expect($this->guard) - ->user()->toBeNull(); -}); - -it('does not accept a user when a repository returns an invalid user class from a token lookup', function (): void { - $repo = mock(Repository::class)->expect( - fromAccessToken: fn (array $user) => new User([]) - ); - - app()->singleton('auth0.repository', fn () => $repo); - - getJson($this->route, $this->bearerToken) - ->assertStatus(Response::HTTP_UNAUTHORIZED); - - expect($this->guard) - ->user()->toBeNull(); -}); - it('does not get a user from a bad token', function (): void { $this->config->setAudience(['BAD_AUDIENCE']); diff --git a/tests/Unit/Cache/LaravelCacheItemTest.php b/tests/Unit/Cache/LaravelCacheItemTest.php index 7466d86b..d3549ced 100644 --- a/tests/Unit/Cache/LaravelCacheItemTest.php +++ b/tests/Unit/Cache/LaravelCacheItemTest.php @@ -60,29 +60,29 @@ test('expiresAt() defaults to +1 year and accepts changes to its value', function (): void { $cacheItem = new LaravelCacheItem('testing', 42, true); - expect($cacheItem->getExpiration()) - ->toBeGreaterThan(new DateTime('now +1 year -1 minute')) - ->toBeLessThan(new DateTime('now +1 year +1 minute')); + expect($cacheItem->getExpiration()->getTimestamp()) + ->toBeGreaterThan((new DateTime('now +1 year -1 minute'))->getTimestamp()) + ->toBeLessThan((new DateTime('now +1 year +1 minute'))->getTimestamp()); $cacheItem->expiresAt(new DateTime('now +1 day')); - expect($cacheItem->getExpiration()) - ->toBeGreaterThan(new DateTime('now +1 day -1 minute')) - ->toBeLessThan(new DateTime('now +1 day +1 minute')); + expect($cacheItem->getExpiration()->getTimestamp()) + ->toBeGreaterThan((new DateTime('now +1 day -1 minute'))->getTimestamp()) + ->toBeLessThan((new DateTime('now +1 day +1 minute'))->getTimestamp()); }); test('expiresAfter() defaults to +1 year and accepts changes to its value', function (): void { $cacheItem = new LaravelCacheItem('testing', 42, true); - expect($cacheItem->getExpiration()) - ->toBeGreaterThan(new DateTime('now +1 year -1 minute')) - ->toBeLessThan(new DateTime('now +1 year +1 minute')); + expect($cacheItem->getExpiration()->getTimestamp()) + ->toBeGreaterThan((new DateTime('now +1 year -1 minute'))->getTimestamp()) + ->toBeLessThan((new DateTime('now +1 year +1 minute'))->getTimestamp()); $cacheItem->expiresAfter(300); - expect($cacheItem->getExpiration()) - ->toBeGreaterThan(new DateTime('now +250 seconds')) - ->toBeLessThan(new DateTime('now +350 seconds')); + expect($cacheItem->getExpiration()->getTimestamp()) + ->toBeGreaterThan((new DateTime('now +250 seconds'))->getTimestamp()) + ->toBeLessThan((new DateTime('now +350 seconds'))->getTimestamp()); }); test('miss() returns a configured instance', function (): void { diff --git a/tests/Unit/Cache/LaravelCachePoolTest.php b/tests/Unit/Cache/LaravelCachePoolTest.php index 07a49838..12989b30 100644 --- a/tests/Unit/Cache/LaravelCachePoolTest.php +++ b/tests/Unit/Cache/LaravelCachePoolTest.php @@ -67,7 +67,7 @@ ->get()->toBeNull() ->isHit()->toBeFalse(); - $cacheMock = $this->mock(CacheItemInterface::class); + $cacheMock = Mockery::mock(CacheItemInterface::class); expect($pool) ->save($cacheMock)->toBeFalse(); From a6a9de29366ea785f2b7c8041fde1a25e8ec4be8 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 20 Mar 2023 18:50:18 -0500 Subject: [PATCH 222/525] Update Rector ruleset --- rector.php | 578 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 562 insertions(+), 16 deletions(-) diff --git a/rector.php b/rector.php index 3c49b81a..6ed59291 100644 --- a/rector.php +++ b/rector.php @@ -2,9 +2,234 @@ declare(strict_types=1); -use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector; +use Rector\Arguments\Rector\ClassMethod\ArgumentAdderRector; +use Rector\Arguments\Rector\FuncCall\FunctionArgumentDefaultValueReplacerRector; +use Rector\Arguments\ValueObject\{ArgumentAdder, + ReplaceFuncCallArgumentDefaultValue}; +use Rector\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector; +use Rector\CodeQuality\Rector\Assign\{CombinedAssignRector, + SplitListAssignToSeparateLineRector}; +use Rector\CodeQuality\Rector\BooleanAnd\SimplifyEmptyArrayCheckRector; +use Rector\CodeQuality\Rector\BooleanNot\{ReplaceMultipleBooleanNotRector, + SimplifyDeMorganBinaryRector}; +use Rector\CodeQuality\Rector\Catch_\ThrowWithPreviousExceptionRector; +use Rector\CodeQuality\Rector\Class_\{CompleteDynamicPropertiesRector, + InlineConstructorDefaultToPropertyRector}; +use Rector\CodeQuality\Rector\ClassMethod\{InlineArrayReturnAssignRector, + NarrowUnionTypeDocRector, + OptionalParametersAfterRequiredRector, + ReturnTypeFromStrictScalarReturnExprRector}; +use Rector\CodeQuality\Rector\Concat\JoinStringConcatRector; +use Rector\CodeQuality\Rector\Empty_\SimplifyEmptyCheckOnEmptyArrayRector; +use Rector\CodeQuality\Rector\Equal\UseIdenticalOverEqualWithSameTypeRector; +use Rector\CodeQuality\Rector\Expression\{InlineIfToExplicitIfRector, + TernaryFalseExpressionToIfRector}; +use Rector\CodeQuality\Rector\For_\{ForRepeatedCountToOwnVariableRector, + ForToForeachRector}; +use Rector\CodeQuality\Rector\Foreach_\{ForeachItemsAssignToEmptyArrayToAssignRector, + ForeachToInArrayRector, + SimplifyForeachToArrayFilterRector, + SimplifyForeachToCoalescingRector, + UnusedForeachValueToArrayKeysRector}; +use Rector\CodeQuality\Rector\FuncCall\{AddPregQuoteDelimiterRector, + ArrayKeysAndInArrayToArrayKeyExistsRector, + ArrayMergeOfNonArraysToSimpleArrayRector, + BoolvalToTypeCastRector, + CallUserFuncWithArrowFunctionToInlineRector, + ChangeArrayPushToArrayAssignRector, + CompactToVariablesRector, + FloatvalToTypeCastRector, + InlineIsAInstanceOfRector, + IntvalToTypeCastRector, + IsAWithStringWithThirdArgumentRector, + RemoveSoleValueSprintfRector, + SetTypeToCastRector, + SimplifyFuncGetArgsCountRector, + SimplifyInArrayValuesRector, + SimplifyRegexPatternRector, + SimplifyStrposLowerRector, + SingleInArrayToCompareRector, + StrvalToTypeCastRector, + UnwrapSprintfOneArgumentRector}; +use Rector\CodeQuality\Rector\FunctionLike\{RemoveAlwaysTrueConditionSetInConstructorRector, + SimplifyUselessLastVariableAssignRector, + SimplifyUselessVariableRector}; +use Rector\CodeQuality\Rector\Identical\{BooleanNotIdenticalToNotIdenticalRector, + FlipTypeControlToUseExclusiveTypeRector, + GetClassToInstanceOfRector, + SimplifyArraySearchRector, + SimplifyBoolIdenticalTrueRector, + SimplifyConditionsRector, + StrlenZeroToIdenticalEmptyStringRector}; +use Rector\CodeQuality\Rector\If_\{CombineIfRector, + ConsecutiveNullCompareReturnsToNullCoalesceQueueRector, + ExplicitBoolCompareRector, + ShortenElseIfRector, + SimplifyIfElseToTernaryRector, + SimplifyIfExactValueReturnValueRector, + SimplifyIfNotNullReturnRector, + SimplifyIfNullableReturnRector, + SimplifyIfReturnBoolRector}; +use Rector\CodeQuality\Rector\Include_\AbsolutizeRequireAndIncludePathRector; +use Rector\CodeQuality\Rector\Isset_\IssetOnPropertyObjectToPropertyExistsRector; +use Rector\CodeQuality\Rector\LogicalAnd\{AndAssignsToSeparateLinesRector, + LogicalToBooleanRector}; +use Rector\CodeQuality\Rector\New_\NewStaticToNewSelfRector; +use Rector\CodeQuality\Rector\NotEqual\CommonNotEqualRector; +use Rector\CodeQuality\Rector\PropertyFetch\ExplicitMethodCallOverMagicGetSetRector; +use Rector\CodeQuality\Rector\Switch_\SingularSwitchToIfRector; +use Rector\CodeQuality\Rector\Ternary\{ArrayKeyExistsTernaryThenValueToCoalescingRector, + SimplifyTautologyTernaryRector, + SwitchNegatedTernaryRector, + TernaryEmptyArrayArrayDimFetchToCoalesceRector, + UnnecessaryTernaryExpressionRector}; +use Rector\CodingStyle\Rector\ArrowFunction\StaticArrowFunctionRector; +use Rector\CodingStyle\Rector\Assign\SplitDoubleAssignRector; +use Rector\CodingStyle\Rector\Catch_\CatchExceptionNameMatchingTypeRector; +use Rector\CodingStyle\Rector\Class_\AddArrayDefaultToArrayPropertyRector; +use Rector\CodingStyle\Rector\ClassConst\{RemoveFinalFromConstRector, SplitGroupedClassConstantsRector, VarConstantCommentRector}; +use Rector\CodingStyle\Rector\ClassMethod\{FuncGetArgsToVariadicParamRector, MakeInheritedMethodVisibilitySameAsParentRector, NewlineBeforeNewAssignSetRector, RemoveDoubleUnderscoreInMethodNameRector, UnSpreadOperatorRector}; +use Rector\CodingStyle\Rector\Closure\StaticClosureRector; +use Rector\CodingStyle\Rector\Encapsed\{EncapsedStringsToSprintfRector, WrapEncapsedVariableInCurlyBracesRector}; +use Rector\CodingStyle\Rector\FuncCall\{CallUserFuncArrayToVariadicRector, CallUserFuncToMethodCallRector, ConsistentImplodeRector, ConsistentPregDelimiterRector, CountArrayToEmptyArrayComparisonRector, StrictArraySearchRector, VersionCompareFuncCallToConstantRector}; +use Rector\CodingStyle\Rector\If_\NullableCompareToNullRector; +use Rector\CodingStyle\Rector\Plus\UseIncrementAssignRector; +use Rector\CodingStyle\Rector\PostInc\PostIncDecToPreIncDecRector; +use Rector\CodingStyle\Rector\Property\{AddFalseDefaultToBoolPropertyRector, SplitGroupedPropertiesRector}; +use Rector\CodingStyle\Rector\Stmt\NewlineAfterStatementRector; +use Rector\CodingStyle\Rector\String_\{SymplifyQuoteEscapeRector, UseClassKeywordForClassNameResolutionRector}; +use Rector\CodingStyle\Rector\Switch_\BinarySwitchToIfElseRector; +use Rector\CodingStyle\Rector\Ternary\TernaryConditionVariableAssignmentRector; +use Rector\CodingStyle\Rector\Use_\SeparateMultiUseImportsRector; use Rector\Config\RectorConfig; -use Rector\Set\ValueObject\SetList; +use Rector\DeadCode\Rector\Array_\RemoveDuplicatedArrayKeyRector; +use Rector\DeadCode\Rector\Assign\{RemoveDoubleAssignRector, + RemoveUnusedVariableAssignRector}; +use Rector\DeadCode\Rector\BinaryOp\RemoveDuplicatedInstanceOfRector; +use Rector\DeadCode\Rector\BooleanAnd\RemoveAndTrueRector; +use Rector\DeadCode\Rector\Cast\RecastingRemovalRector; +use Rector\DeadCode\Rector\ClassConst\RemoveUnusedPrivateClassConstantRector; +use Rector\DeadCode\Rector\ClassMethod\{RemoveDelegatingParentCallRector, + RemoveEmptyClassMethodRector, + RemoveLastReturnRector, + RemoveUnusedConstructorParamRector, + RemoveUnusedPrivateMethodParameterRector, + RemoveUnusedPrivateMethodRector, + RemoveUnusedPromotedPropertyRector, + RemoveUselessParamTagRector, + RemoveUselessReturnTagRector}; +use Rector\DeadCode\Rector\Concat\RemoveConcatAutocastRector; +use Rector\DeadCode\Rector\Expression\{RemoveDeadStmtRector, + SimplifyMirrorAssignRector}; +use Rector\DeadCode\Rector\For_\{RemoveDeadContinueRector, + RemoveDeadIfForeachForRector, + RemoveDeadLoopRector}; +use Rector\DeadCode\Rector\Foreach_\RemoveUnusedForeachKeyRector; +use Rector\DeadCode\Rector\FunctionLike\{RemoveDeadReturnRector, + RemoveDuplicatedIfReturnRector}; +use Rector\DeadCode\Rector\If_\{RemoveAlwaysTrueIfConditionRector, + RemoveDeadInstanceOfRector, + RemoveUnusedNonEmptyArrayBeforeForeachRector, + SimplifyIfElseWithSameContentRector, + UnwrapFutureCompatibleIfPhpVersionRector}; +use Rector\DeadCode\Rector\MethodCall\RemoveEmptyMethodCallRector; +use Rector\DeadCode\Rector\Node\RemoveNonExistingVarAnnotationRector; +use Rector\DeadCode\Rector\Plus\RemoveDeadZeroAndOneOperationRector; +use Rector\DeadCode\Rector\Property\{RemoveUnusedPrivatePropertyRector, + RemoveUselessVarTagRector}; +use Rector\DeadCode\Rector\PropertyProperty\RemoveNullPropertyInitializationRector; +use Rector\DeadCode\Rector\Return_\RemoveDeadConditionAboveReturnRector; +use Rector\DeadCode\Rector\StaticCall\RemoveParentCallWithoutParentRector; +use Rector\DeadCode\Rector\Stmt\RemoveUnreachableStatementRector; +use Rector\DeadCode\Rector\StmtsAwareInterface\{RemoveJustPropertyFetchForAssignRector, + RemoveJustVariableAssignRector}; +use Rector\DeadCode\Rector\Switch_\RemoveDuplicatedCaseInSwitchRector; +use Rector\DeadCode\Rector\Ternary\TernaryToBooleanOrFalseToBooleanAndRector; +use Rector\DeadCode\Rector\TryCatch\RemoveDeadTryCatchRector; +use Rector\DependencyInjection\Rector\Class_\ActionInjectionToConstructorInjectionRector; +use Rector\EarlyReturn\Rector\Foreach_\ChangeNestedForeachIfsToEarlyContinueRector; +use Rector\EarlyReturn\Rector\If_\{ChangeAndIfToEarlyReturnRector, + ChangeIfElseValueAssignToEarlyReturnRector, + ChangeNestedIfsToEarlyReturnRector, + ChangeOrIfContinueToMultiContinueRector, + ChangeOrIfReturnToEarlyReturnRector, + RemoveAlwaysElseRector}; +use Rector\EarlyReturn\Rector\Return_\{PreparedValueToEarlyReturnRector, + ReturnBinaryAndToEarlyReturnRector, + ReturnBinaryOrToEarlyReturnRector}; +use Rector\EarlyReturn\Rector\StmtsAwareInterface\ReturnEarlyIfVariableRector; +use Rector\Naming\Rector\Assign\RenameVariableToMatchMethodCallReturnTypeRector; +use Rector\Naming\Rector\Class_\RenamePropertyToMatchTypeRector; +use Rector\Naming\Rector\ClassMethod\{RenameParamToMatchTypeRector, + RenameVariableToMatchNewTypeRector}; +use Rector\Naming\Rector\Foreach_\{RenameForeachValueVariableToMatchExprVariableRector, + RenameForeachValueVariableToMatchMethodCallReturnTypeRector}; +use Rector\Php52\Rector\Property\VarToPublicPropertyRector; +use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; +use Rector\Php71\Rector\FuncCall\RemoveExtraParametersRector; +use Rector\Php80\Rector\Catch_\RemoveUnusedVariableInCatchRector; +use Rector\Php80\Rector\Class_\{ClassPropertyAssignToConstructorPromotionRector, + StringableForToStringRector}; +use Rector\Php80\Rector\ClassConstFetch\ClassOnThisVariableObjectRector; +use Rector\Php80\Rector\ClassMethod\{AddParamBasedOnParentClassMethodRector, + FinalPrivateToPrivateVisibilityRector, + SetStateToStaticRector}; +use Rector\Php80\Rector\FuncCall\{ClassOnObjectRector, + Php8ResourceReturnToObjectRector, + TokenGetAllToObjectRector}; +use Rector\Php80\Rector\FunctionLike\{MixedTypeRector, + UnionTypesRector}; +use Rector\Php80\Rector\Identical\{StrEndsWithRector, + StrStartsWithRector}; +use Rector\Php80\Rector\NotIdentical\StrContainsRector; +use Rector\Php80\Rector\Switch_\ChangeSwitchToMatchRector; +use Rector\Php80\Rector\Ternary\GetDebugTypeRector; +use Rector\PHPUnit\Rector\ClassMethod\RemoveEmptyTestMethodRector; +use Rector\Privatization\Rector\Class_\{ChangeGlobalVariablesToPropertiesRector, + ChangeReadOnlyVariableWithDefaultValueToConstantRector, + FinalizeClassesWithoutChildrenRector}; +use Rector\Privatization\Rector\ClassMethod\PrivatizeFinalClassMethodRector; +use Rector\Privatization\Rector\MethodCall\PrivatizeLocalGetterToPropertyRector; +use Rector\Privatization\Rector\Property\{ChangeReadOnlyPropertyWithDefaultValueToConstantRector, + PrivatizeFinalClassPropertyRector}; +use Rector\PSR4\Rector\FileWithoutNamespace\NormalizeNamespaceByPSR4ComposerAutoloadRector; +use Rector\PSR4\Rector\Namespace_\MultipleClassFileToPsr4ClassesRector; +use Rector\Renaming\Rector\FuncCall\RenameFunctionRector; +use Rector\Transform\Rector\FuncCall\FuncCallToConstFetchRector; +use Rector\Transform\Rector\StaticCall\StaticCallToFuncCallRector; +use Rector\Transform\ValueObject\StaticCallToFuncCall; +use Rector\TypeDeclaration\Rector\ArrowFunction\AddArrowFunctionReturnTypeRector; +use Rector\TypeDeclaration\Rector\Class_\{PropertyTypeFromStrictSetterGetterRector, + ReturnTypeFromStrictTernaryRector}; +use Rector\TypeDeclaration\Rector\ClassMethod\{AddMethodCallBasedStrictParamTypeRector, + AddParamTypeBasedOnPHPUnitDataProviderRector, + AddParamTypeFromPropertyTypeRector, + AddReturnTypeDeclarationBasedOnParentClassMethodRector, + AddVoidReturnTypeWhereNoReturnRector, + ArrayShapeFromConstantArrayReturnRector, + ParamAnnotationIncorrectNullableRector, + ParamTypeByMethodCallTypeRector, + ParamTypeByParentCallTypeRector, + ReturnAnnotationIncorrectNullableRector, + ReturnNeverTypeRector, + ReturnTypeFromReturnDirectArrayRector, + ReturnTypeFromReturnNewRector, + ReturnTypeFromStrictBoolReturnExprRector, + ReturnTypeFromStrictConstantReturnRector, + ReturnTypeFromStrictNativeCallRector, + ReturnTypeFromStrictNewArrayRector, + ReturnTypeFromStrictTypedCallRector, + ReturnTypeFromStrictTypedPropertyRector}; +use Rector\TypeDeclaration\Rector\Closure\AddClosureReturnTypeRector; +use Rector\TypeDeclaration\Rector\Empty_\EmptyOnNullableObjectToInstanceOfRector; +use Rector\TypeDeclaration\Rector\FunctionLike\{AddParamTypeSplFixedArrayRector, + AddReturnTypeDeclarationFromYieldsRector}; +use Rector\TypeDeclaration\Rector\Param\ParamTypeFromStrictTypedPropertyRector; +use Rector\TypeDeclaration\Rector\Property\{TypedPropertyFromAssignsRector, + TypedPropertyFromStrictConstructorRector, + TypedPropertyFromStrictGetterMethodReturnTypeRector, + TypedPropertyFromStrictSetUpRector, + VarAnnotationIncorrectNullableRector}; return static function (RectorConfig $rectorConfig): void { $rectorConfig->paths([ @@ -12,19 +237,340 @@ __DIR__ . '/src', ]); - // register a single rule - $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class); - - // define sets of rules - $rectorConfig->sets([ - SetList::CODE_QUALITY, - SetList::PHP_80, - SetList::ACTION_INJECTION_TO_CONSTRUCTOR_INJECTION, - SetList::DEAD_CODE, - SetList::NAMING, - SetList::PRIVATIZATION, - SetList::PSR_4, - SetList::TYPE_DECLARATION, - SetList::EARLY_RETURN, + $rectorConfig->ruleWithConfiguration( + RenameFunctionRector::class, + [ + 'chop' => 'rtrim', + 'doubleval' => 'floatval', + 'fputs' => 'fwrite', + 'gzputs' => 'gzwrites', + 'ini_alter' => 'ini_set', + 'is_double' => 'is_float', + 'is_integer' => 'is_int', + 'is_long' => 'is_int', + 'is_real' => 'is_float', + 'is_writeable' => 'is_writable', + 'join' => 'implode', + 'key_exists' => 'array_key_exists', + 'mbstrcut' => 'mb_strcut', + 'mbstrlen' => 'mb_strlen', + 'mbstrpos' => 'mb_strpos', + 'mbstrrpos' => 'mb_strrpos', + 'mbsubstr' => 'mb_substr', + 'pos' => 'current', + 'sizeof' => 'count', + 'split' => 'explode', + 'strchr' => 'strstr', + ], + ); + + $rectorConfig->ruleWithConfiguration( + StaticCallToFuncCallRector::class, + [ + new StaticCallToFuncCall('Nette\\Utils\\Strings', 'contains', 'str_contains'), + new StaticCallToFuncCall('Nette\\Utils\\Strings', 'endsWith', 'str_ends_with'), + new StaticCallToFuncCall('Nette\\Utils\\Strings', 'startsWith', 'str_starts_with'), + ], + ); + + $rectorConfig->ruleWithConfiguration( + ArgumentAdderRector::class, + [new ArgumentAdder('Nette\\Utils\\Strings', 'replace', 2, 'replacement', '')], + ); + + $rectorConfig->ruleWithConfiguration( + RenameFunctionRector::class, + [ + 'pg_clientencoding' => 'pg_client_encoding', + 'pg_cmdtuples' => 'pg_affected_rows', + 'pg_errormessage' => 'pg_last_error', + 'pg_fieldisnull' => 'pg_field_is_null', + 'pg_fieldname' => 'pg_field_name', + 'pg_fieldnum' => 'pg_field_num', + 'pg_fieldprtlen' => 'pg_field_prtlen', + 'pg_fieldsize' => 'pg_field_size', + 'pg_fieldtype' => 'pg_field_type', + 'pg_freeresult' => 'pg_free_result', + 'pg_getlastoid' => 'pg_last_oid', + 'pg_loclose' => 'pg_lo_close', + 'pg_locreate' => 'pg_lo_create', + 'pg_loexport' => 'pg_lo_export', + 'pg_loimport' => 'pg_lo_import', + 'pg_loopen' => 'pg_lo_open', + 'pg_loread' => 'pg_lo_read', + 'pg_loreadall' => 'pg_lo_read_all', + 'pg_lounlink' => 'pg_lo_unlink', + 'pg_lowrite' => 'pg_lo_write', + 'pg_numfields' => 'pg_num_fields', + 'pg_numrows' => 'pg_num_rows', + 'pg_result' => 'pg_fetch_result', + 'pg_setclientencoding' => 'pg_set_client_encoding' + ], + ); + + $rectorConfig->ruleWithConfiguration( + FunctionArgumentDefaultValueReplacerRector::class, + [ + new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'gte', 'ge'), + new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'lte', 'le'), + new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, '', '!='), + new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, '!', '!='), + new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'g', 'gt'), + new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'l', 'lt'), + new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'gte', 'ge'), + new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'lte', 'le'), + new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'n', 'ne') + ], + ); + + $rectorConfig->ruleWithConfiguration( + FuncCallToConstFetchRector::class, + [ + 'php_sapi_name' => 'PHP_SAPI', + 'pi' => 'M_PI' + ], + ); + + $rectorConfig->rules([ + // AddParamTypeFromPropertyTypeRector::class, + // ChangeOrIfReturnToEarlyReturnRector::class, + // RemoveAlwaysTrueIfConditionRector::class, + // RenameParamToMatchTypeRector::class, + AbsolutizeRequireAndIncludePathRector::class, + ActionInjectionToConstructorInjectionRector::class, + AddArrayDefaultToArrayPropertyRector::class, + AddArrowFunctionReturnTypeRector::class, + AddClosureReturnTypeRector::class, + AddFalseDefaultToBoolPropertyRector::class, + AddMethodCallBasedStrictParamTypeRector::class, + AddParamBasedOnParentClassMethodRector::class, + AddParamTypeBasedOnPHPUnitDataProviderRector::class, + AddParamTypeSplFixedArrayRector::class, + AddPregQuoteDelimiterRector::class, + AddReturnTypeDeclarationBasedOnParentClassMethodRector::class, + AddReturnTypeDeclarationFromYieldsRector::class, + AddVoidReturnTypeWhereNoReturnRector::class, + AndAssignsToSeparateLinesRector::class, + ArrayKeyExistsTernaryThenValueToCoalescingRector::class, + ArrayKeysAndInArrayToArrayKeyExistsRector::class, + ArrayMergeOfNonArraysToSimpleArrayRector::class, + ArrayShapeFromConstantArrayReturnRector::class, + BinarySwitchToIfElseRector::class, + BooleanNotIdenticalToNotIdenticalRector::class, + BoolvalToTypeCastRector::class, + CallableThisArrayToAnonymousFunctionRector::class, + CallUserFuncArrayToVariadicRector::class, + CallUserFuncToMethodCallRector::class, + CallUserFuncToMethodCallRector::class, + CallUserFuncWithArrowFunctionToInlineRector::class, + CatchExceptionNameMatchingTypeRector::class, + // ChangeAndIfToEarlyReturnRector::class, + ChangeArrayPushToArrayAssignRector::class, + ChangeGlobalVariablesToPropertiesRector::class, + ChangeIfElseValueAssignToEarlyReturnRector::class, + ChangeNestedForeachIfsToEarlyContinueRector::class, + ChangeNestedIfsToEarlyReturnRector::class, + ChangeOrIfContinueToMultiContinueRector::class, + ChangeReadOnlyPropertyWithDefaultValueToConstantRector::class, + ChangeReadOnlyVariableWithDefaultValueToConstantRector::class, + ChangeSwitchToMatchRector::class, + ClassOnObjectRector::class, + ClassOnThisVariableObjectRector::class, + ClassPropertyAssignToConstructorPromotionRector::class, + CombinedAssignRector::class, + CombineIfRector::class, + CommonNotEqualRector::class, + CompactToVariablesRector::class, + CompleteDynamicPropertiesRector::class, + ConsecutiveNullCompareReturnsToNullCoalesceQueueRector::class, + ConsistentImplodeRector::class, + ConsistentPregDelimiterRector::class, + CountArrayToEmptyArrayComparisonRector::class, + CountArrayToEmptyArrayComparisonRector::class, + EmptyOnNullableObjectToInstanceOfRector::class, + EncapsedStringsToSprintfRector::class, + ExplicitBoolCompareRector::class, + ExplicitMethodCallOverMagicGetSetRector::class, + FinalizeClassesWithoutChildrenRector::class, + FinalPrivateToPrivateVisibilityRector::class, + FlipTypeControlToUseExclusiveTypeRector::class, + FloatvalToTypeCastRector::class, + ForeachItemsAssignToEmptyArrayToAssignRector::class, + ForeachToInArrayRector::class, + ForRepeatedCountToOwnVariableRector::class, + ForToForeachRector::class, + FuncGetArgsToVariadicParamRector::class, + FuncGetArgsToVariadicParamRector::class, + GetClassToInstanceOfRector::class, + GetDebugTypeRector::class, + InlineArrayReturnAssignRector::class, + InlineConstructorDefaultToPropertyRector::class, + InlineIfToExplicitIfRector::class, + InlineIsAInstanceOfRector::class, + IntvalToTypeCastRector::class, + IsAWithStringWithThirdArgumentRector::class, + IssetOnPropertyObjectToPropertyExistsRector::class, + JoinStringConcatRector::class, + LogicalToBooleanRector::class, + MakeInheritedMethodVisibilitySameAsParentRector::class, + // MixedTypeRector::class, + MultipleClassFileToPsr4ClassesRector::class, + NarrowUnionTypeDocRector::class, + // NewlineAfterStatementRector::class, + NewlineBeforeNewAssignSetRector::class, + NewStaticToNewSelfRector::class, + NormalizeNamespaceByPSR4ComposerAutoloadRector::class, + NullableCompareToNullRector::class, + OptionalParametersAfterRequiredRector::class, + OptionalParametersAfterRequiredRector::class, + ParamAnnotationIncorrectNullableRector::class, + ParamTypeByMethodCallTypeRector::class, + ParamTypeByParentCallTypeRector::class, + ParamTypeFromStrictTypedPropertyRector::class, + Php8ResourceReturnToObjectRector::class, + PostIncDecToPreIncDecRector::class, + PreparedValueToEarlyReturnRector::class, + PrivatizeFinalClassMethodRector::class, + PrivatizeFinalClassPropertyRector::class, + // PrivatizeLocalGetterToPropertyRector::class, + PropertyTypeFromStrictSetterGetterRector::class, + // RecastingRemovalRector::class, + RemoveAlwaysElseRector::class, + RemoveAlwaysTrueConditionSetInConstructorRector::class, + RemoveAndTrueRector::class, + // RemoveConcatAutocastRector::class, + RemoveDeadConditionAboveReturnRector::class, + RemoveDeadContinueRector::class, + RemoveDeadIfForeachForRector::class, + // RemoveDeadInstanceOfRector::class, + RemoveDeadLoopRector::class, + RemoveDeadReturnRector::class, + RemoveDeadStmtRector::class, + RemoveDeadTryCatchRector::class, + RemoveDeadZeroAndOneOperationRector::class, + RemoveDelegatingParentCallRector::class, + RemoveDoubleAssignRector::class, + RemoveDoubleUnderscoreInMethodNameRector::class, + RemoveDuplicatedArrayKeyRector::class, + RemoveDuplicatedCaseInSwitchRector::class, + RemoveDuplicatedIfReturnRector::class, + RemoveDuplicatedInstanceOfRector::class, + RemoveEmptyClassMethodRector::class, + RemoveEmptyMethodCallRector::class, + RemoveEmptyTestMethodRector::class, + RemoveExtraParametersRector::class, + RemoveFinalFromConstRector::class, + RemoveJustPropertyFetchForAssignRector::class, + RemoveJustVariableAssignRector::class, + RemoveLastReturnRector::class, + RemoveNonExistingVarAnnotationRector::class, + RemoveNullPropertyInitializationRector::class, + RemoveParentCallWithoutParentRector::class, + RemoveParentCallWithoutParentRector::class, + RemoveSoleValueSprintfRector::class, + RemoveUnreachableStatementRector::class, + RemoveUnusedConstructorParamRector::class, + RemoveUnusedForeachKeyRector::class, + RemoveUnusedNonEmptyArrayBeforeForeachRector::class, + RemoveUnusedPrivateClassConstantRector::class, + RemoveUnusedPrivateMethodParameterRector::class, + RemoveUnusedPrivateMethodRector::class, + RemoveUnusedPrivatePropertyRector::class, + RemoveUnusedPromotedPropertyRector::class, + RemoveUnusedVariableAssignRector::class, + RemoveUnusedVariableInCatchRector::class, + // RemoveUselessParamTagRector::class, + RemoveUselessReturnTagRector::class, + RemoveUselessVarTagRector::class, + RenameForeachValueVariableToMatchExprVariableRector::class, + RenameForeachValueVariableToMatchMethodCallReturnTypeRector::class, + // RenamePropertyToMatchTypeRector::class, + // RenameVariableToMatchMethodCallReturnTypeRector::class, + // RenameVariableToMatchNewTypeRector::class, + ReplaceMultipleBooleanNotRector::class, + ReturnAnnotationIncorrectNullableRector::class, + ReturnBinaryAndToEarlyReturnRector::class, + ReturnBinaryOrToEarlyReturnRector::class, + ReturnEarlyIfVariableRector::class, + ReturnNeverTypeRector::class, + ReturnTypeFromReturnDirectArrayRector::class, + ReturnTypeFromReturnNewRector::class, + ReturnTypeFromStrictBoolReturnExprRector::class, + ReturnTypeFromStrictConstantReturnRector::class, + ReturnTypeFromStrictNativeCallRector::class, + ReturnTypeFromStrictNewArrayRector::class, + ReturnTypeFromStrictScalarReturnExprRector::class, + ReturnTypeFromStrictScalarReturnExprRector::class, + ReturnTypeFromStrictTernaryRector::class, + ReturnTypeFromStrictTypedCallRector::class, + ReturnTypeFromStrictTypedPropertyRector::class, + SeparateMultiUseImportsRector::class, + SetStateToStaticRector::class, + SetTypeToCastRector::class, + ShortenElseIfRector::class, + SimplifyArraySearchRector::class, + SimplifyBoolIdenticalTrueRector::class, + SimplifyConditionsRector::class, + SimplifyDeMorganBinaryRector::class, + SimplifyEmptyArrayCheckRector::class, + SimplifyEmptyCheckOnEmptyArrayRector::class, + SimplifyForeachToArrayFilterRector::class, + SimplifyForeachToCoalescingRector::class, + SimplifyFuncGetArgsCountRector::class, + SimplifyIfElseToTernaryRector::class, + SimplifyIfElseWithSameContentRector::class, + SimplifyIfExactValueReturnValueRector::class, + SimplifyIfNotNullReturnRector::class, + SimplifyIfNullableReturnRector::class, + SimplifyIfReturnBoolRector::class, + SimplifyInArrayValuesRector::class, + SimplifyMirrorAssignRector::class, + SimplifyRegexPatternRector::class, + SimplifyStrposLowerRector::class, + SimplifyTautologyTernaryRector::class, + SimplifyUselessLastVariableAssignRector::class, + SimplifyUselessVariableRector::class, + SingleInArrayToCompareRector::class, + SingularSwitchToIfRector::class, + SplitDoubleAssignRector::class, + SplitGroupedClassConstantsRector::class, + SplitGroupedPropertiesRector::class, + SplitListAssignToSeparateLineRector::class, + StaticArrowFunctionRector::class, + StaticClosureRector::class, + StrContainsRector::class, + StrEndsWithRector::class, + StrictArraySearchRector::class, + StringableForToStringRector::class, + // StringClassNameToClassConstantRector::class, + StrlenZeroToIdenticalEmptyStringRector::class, + StrStartsWithRector::class, + StrvalToTypeCastRector::class, + SwitchNegatedTernaryRector::class, + SymplifyQuoteEscapeRector::class, + TernaryConditionVariableAssignmentRector::class, + TernaryEmptyArrayArrayDimFetchToCoalesceRector::class, + TernaryFalseExpressionToIfRector::class, + TernaryToBooleanOrFalseToBooleanAndRector::class, + ThrowWithPreviousExceptionRector::class, + TokenGetAllToObjectRector::class, + TypedPropertyFromAssignsRector::class, + TypedPropertyFromStrictConstructorRector::class, + TypedPropertyFromStrictGetterMethodReturnTypeRector::class, + TypedPropertyFromStrictSetUpRector::class, + // UnionTypesRector::class, + UnnecessaryTernaryExpressionRector::class, + UnSpreadOperatorRector::class, + UnusedForeachValueToArrayKeysRector::class, + UnwrapFutureCompatibleIfPhpVersionRector::class, + UnwrapSprintfOneArgumentRector::class, + UseClassKeywordForClassNameResolutionRector::class, + UseIdenticalOverEqualWithSameTypeRector::class, + UseIncrementAssignRector::class, + VarAnnotationIncorrectNullableRector::class, + VarConstantCommentRector::class, + VarToPublicPropertyRector::class, + VersionCompareFuncCallToConstantRector::class, + WrapEncapsedVariableInCurlyBracesRector::class, ]); }; From f64cbe19fe2c740daae6c3ecf2ee41361aed56dc Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 20 Mar 2023 18:59:52 -0500 Subject: [PATCH 223/525] Apply updated Rector rules --- src/Auth/Guard.php | 16 ++++++++++++++-- src/Auth0.php | 2 ++ src/Entities/Credential.php | 3 +++ src/Http/Controller/Stateful/Callback.php | 12 +++++++----- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 6555e7a3..ad008800 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -30,8 +30,19 @@ final class Guard implements GuardContract { + /** + * @var int + */ public const SOURCE_IMPERSONATE = 0; // Manually set, presumably through a test case's impersonate() method. + + /** + * @var int + */ public const SOURCE_SESSION = 2; // Assigned from a session. + + /** + * @var int + */ public const SOURCE_TOKEN = 1; // Assigned from a decoded token. private ?Credential $credential = null; private ?int $credentialSource = null; @@ -192,6 +203,7 @@ private function pullState(): ?Credential { $sdk = $this->getSdk(); $sdk->refreshState(); + $credentials = $sdk->getCredentials(); /** @var mixed $credentials */ @@ -510,8 +522,8 @@ public function processToken( event(new TokenVerificationSucceeded($token, $data)); return $data; - } catch (InvalidTokenException $invalidToken) { - event(new TokenVerificationFailed($token, $invalidToken)); + } catch (InvalidTokenException $invalidTokenException) { + event(new TokenVerificationFailed($token, $invalidTokenException)); return null; } diff --git a/src/Auth0.php b/src/Auth0.php index ccab64a5..aa18821d 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -21,6 +21,8 @@ final class Auth0 implements ServiceContract { /** * The Laravel-Auth0 SDK version:. + * + * @var string */ public const VERSION = '7.4.0'; diff --git a/src/Entities/Credential.php b/src/Entities/Credential.php index b95c98fd..483f3a28 100644 --- a/src/Entities/Credential.php +++ b/src/Entities/Credential.php @@ -83,6 +83,9 @@ public function getUser(): ?Authenticatable return $this->user; } + /** + * @return array{user: false|string, idToken: null|string, accessToken: null|string, accessTokenScope: null|string[], accessTokenExpiration: null|int, accessTokenExpired: null|bool, refreshToken: null|string} + */ public function jsonSerialize(): mixed { return [ diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index e112a84a..f57f62de 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -18,6 +18,9 @@ final class Callback extends ControllerAbstract implements CallbackContract { + /** + * @psalm-suppress InvalidArgument + */ public function __invoke( Request $request, ): RedirectResponse { @@ -27,7 +30,6 @@ public function __invoke( return redirect()->intended(config('auth0.routes.home', '/')); } - /** @var Guard $guard */ $code = $request->query('code'); $state = $request->query('state'); $code = is_string($code) ? trim($code) : ''; @@ -56,23 +58,23 @@ public function __invoke( state: $state, ); } - } catch (Throwable $exception) { + } catch (Throwable $throwable) { $credentials = $this->getSdk()->getUser() ?? []; $credentials['code'] = $code; $credentials['state'] = $state; - $credentials['error'] = ['description' => $exception->getMessage()]; + $credentials['error'] = ['description' => $throwable->getMessage()]; event(new Failed($guard::class, $guard->user(), $credentials)); $this->getSdk()->clear(); // Throw hookable $event to allow custom error handling scenarios. - $event = new AuthenticationFailed($exception, true); + $event = new AuthenticationFailed($throwable, true); event($event); // If the event was not hooked by the application, throw an exception: if ($event->getThrowException()) { - throw $exception; + throw $throwable; } } From bb00eadecec7ad7018972804f72a9c980c77a0c1 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 20 Mar 2023 19:00:04 -0500 Subject: [PATCH 224/525] Use new PEST 2.0 --compact command --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5fd6ffc6..b0abc356 100644 --- a/composer.json +++ b/composer.json @@ -110,7 +110,7 @@ }, "scripts": { "mutate": "@php ./vendor/bin/infection --test-framework=pest --show-mutations", - "pest:coverage": "@php vendor/bin/pest --order-by random --coverage", + "pest:coverage": "@php vendor/bin/pest --order-by random --compact --coverage", "pest": "@php vendor/bin/pest --order-by random --compact", "phpcs:fix": "@php vendor/bin/php-cs-fixer fix src", "phpcs": "@php vendor/bin/php-cs-fixer fix src --dry-run --diff", From 9e70a8677bd2e39b3fa498bcead65a615537139e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 20 Mar 2023 19:02:06 -0500 Subject: [PATCH 225/525] Update Callback.php --- src/Http/Controller/Stateful/Callback.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index f57f62de..acd533b9 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -20,6 +20,8 @@ final class Callback extends ControllerAbstract implements CallbackContract { /** * @psalm-suppress InvalidArgument + * + * @param Request $request */ public function __invoke( Request $request, From 05ab7ff6da273e4bc421495356639c37f1433a3f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 20 Mar 2023 19:04:25 -0500 Subject: [PATCH 226/525] Update workflows to use PHP 8.1 for PEST 2.0 compatibility --- .github/workflows/php_phpcsf.yml | 2 +- .github/workflows/php_phpstan.yml | 2 +- .github/workflows/php_psalm.yml | 2 +- .github/workflows/php_rector.yml | 2 +- .github/workflows/sec_snyk.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/php_phpcsf.yml b/.github/workflows/php_phpcsf.yml index 593deac0..80cf3daa 100644 --- a/.github/workflows/php_phpcsf.yml +++ b/.github/workflows/php_phpcsf.yml @@ -20,7 +20,7 @@ jobs: operating-systems: - ubuntu-latest php-versions: - - 8.0 + - 8.1 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/php_phpstan.yml b/.github/workflows/php_phpstan.yml index fce24b8c..3c19afe9 100644 --- a/.github/workflows/php_phpstan.yml +++ b/.github/workflows/php_phpstan.yml @@ -20,7 +20,7 @@ jobs: operating-systems: - ubuntu-latest php-versions: - - 8.0 + - 8.1 steps: - uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/php_psalm.yml b/.github/workflows/php_psalm.yml index 5b464562..1c4fee06 100644 --- a/.github/workflows/php_psalm.yml +++ b/.github/workflows/php_psalm.yml @@ -20,7 +20,7 @@ jobs: operating-systems: - ubuntu-latest php-versions: - - 8.0 + - 8.1 steps: - uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/php_rector.yml b/.github/workflows/php_rector.yml index 6aecf8a1..a4814ff3 100644 --- a/.github/workflows/php_rector.yml +++ b/.github/workflows/php_rector.yml @@ -20,7 +20,7 @@ jobs: operating-systems: - ubuntu-latest php-versions: - - 8.0 + - 8.1 steps: - uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/sec_snyk.yml b/.github/workflows/sec_snyk.yml index d12faff4..2dcde887 100644 --- a/.github/workflows/sec_snyk.yml +++ b/.github/workflows/sec_snyk.yml @@ -23,7 +23,7 @@ jobs: operating-systems: - ubuntu-latest php-versions: - - 8.0 + - 8.1 steps: - uses: shivammathur/setup-php@v2 From 5ecd99fbd8d1d6671454cb9f02262248b240980d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 20 Mar 2023 19:07:22 -0500 Subject: [PATCH 227/525] PEST 2.0 syntax --- .github/workflows/php_pest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php_pest.yml b/.github/workflows/php_pest.yml index 87fef96b..5e27673b 100644 --- a/.github/workflows/php_pest.yml +++ b/.github/workflows/php_pest.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@v3 - run: composer install --prefer-dist - - run: vendor/bin/pest --coverage-clover coverage/coverage.xml --no-interaction --order-by random + - run: vendor/bin/pest --coverage-clover coverage/coverage.xml --order-by random - if: (matrix.php-versions == '8.1') uses: codecov/codecov-action@v2 From e539de4094dee62cb7598a21a0716f4a71dff273 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 20 Mar 2023 19:12:11 -0500 Subject: [PATCH 228/525] Update php_pest.yml --- .github/workflows/php_pest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php_pest.yml b/.github/workflows/php_pest.yml index 5e27673b..220bded9 100644 --- a/.github/workflows/php_pest.yml +++ b/.github/workflows/php_pest.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@v3 - run: composer install --prefer-dist - - run: vendor/bin/pest --coverage-clover coverage/coverage.xml --order-by random + - run: vendor/bin/pest --coverage coverage/coverage.xml --min 100 --order-by random - if: (matrix.php-versions == '8.1') uses: codecov/codecov-action@v2 From d92f430b6e8b0b3f23646cd1a9aa684c433a4f1d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 20 Mar 2023 19:14:15 -0500 Subject: [PATCH 229/525] Update php_pest.yml --- .github/workflows/php_pest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php_pest.yml b/.github/workflows/php_pest.yml index 220bded9..3a8ba503 100644 --- a/.github/workflows/php_pest.yml +++ b/.github/workflows/php_pest.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@v3 - run: composer install --prefer-dist - - run: vendor/bin/pest --coverage coverage/coverage.xml --min 100 --order-by random + - run: vendor/bin/pest --coverage coverage/coverage.xml --order-by random - if: (matrix.php-versions == '8.1') uses: codecov/codecov-action@v2 From 86d3f452f8dc475e748f2fed91cd3886b7e4d852 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 20 Mar 2023 19:19:21 -0500 Subject: [PATCH 230/525] Update php_pest.yml --- .github/workflows/php_pest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php_pest.yml b/.github/workflows/php_pest.yml index 3a8ba503..5e27673b 100644 --- a/.github/workflows/php_pest.yml +++ b/.github/workflows/php_pest.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@v3 - run: composer install --prefer-dist - - run: vendor/bin/pest --coverage coverage/coverage.xml --order-by random + - run: vendor/bin/pest --coverage-clover coverage/coverage.xml --order-by random - if: (matrix.php-versions == '8.1') uses: codecov/codecov-action@v2 From a0b9ab262bc470f8f9ce3d941aa1c286feab6e7e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 21 Mar 2023 00:43:26 -0500 Subject: [PATCH 231/525] Fix linter warnings --- .php-cs-fixer.dist.php | 2 - src/Auth/User/Provider.php | 164 ++++++++++++---------- src/Auth0.php | 1 + src/Cache/LaravelCacheItem.php | 1 + src/Cache/LaravelCachePool.php | 1 + src/Configuration.php | 1 + src/Http/Controller/Stateful/Callback.php | 1 + src/Http/Controller/Stateful/Logout.php | 1 + 8 files changed, 97 insertions(+), 75 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index ce007ae7..2dc96809 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -114,8 +114,6 @@ 'no_spaces_around_offset' => true, 'no_spaces_inside_parenthesis' => true, 'no_superfluous_elseif' => true, - 'no_trailing_comma_in_singleline_array' => true, - 'no_trailing_comma_in_singleline_function_call' => true, 'no_trailing_comma_in_singleline' => true, 'no_trailing_whitespace_in_comment' => true, 'no_trailing_whitespace_in_string' => true, diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php index eadfe980..7280cb9d 100644 --- a/src/Auth/User/Provider.php +++ b/src/Auth/User/Provider.php @@ -5,24 +5,92 @@ namespace Auth0\Laravel\Auth\User; use Auth0\Laravel\Auth\Guard; -use Auth0\Laravel\Contract\Auth\User\Provider as ProviderContract; -use Auth0\Laravel\Contract\Auth\User\Repository as RepositoryContract; +use Auth0\Laravel\Contract\Auth\User\{Provider as ProviderContract, Repository as RepositoryContract}; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Container\BindingResolutionException; +use function is_string; + final class Provider implements ProviderContract { private ?RepositoryContract $repository = null; - private string $repositoryName = ''; + private string $repositoryName = ''; public function __construct( private array $config = [], ) { } + private function getConfiguration( + string $key, + ): array | string | null { + return $this->config[$key] ?? null; + } + + private function getRepositoryName(): string + { + return $this->repositoryName; + } + + private function resolveRepository( + ?string $repositoryName = null, + ): RepositoryContract { + $model = $repositoryName; + $model ??= $this->getConfiguration('model'); + $model ??= $this->getConfiguration('repository'); + $model ??= Repository::class; + + if ($model === $this->getRepositoryName()) { + return $this->getRepository(); + } + + if (! is_string($model)) { + throw new BindingResolutionException('The configured Repository could not be loaded.'); + } + + if (! app()->bound($model)) { + throw new BindingResolutionException(sprintf('The configured Repository %s could not be loaded.', $model)); + } + + $this->setRepositoryName($model); + + return $this->repository = app($model); + } + + private function setConfiguration( + string $key, + mixed $value, + ): void { + $this->config[$key] = $value; + } + + private function setRepositoryName(string $repositoryName): void + { + $this->setConfiguration('model', $repositoryName); + $this->repositoryName = $repositoryName; + } + + public function getRepository(): RepositoryContract + { + return $this->repository ?? $this->resolveRepository(); + } + + /** + * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + * + * @param array $credentials + */ + public function retrieveByCredentials(array $credentials): ?Authenticatable + { + return $this->getRepository()->fromSession($credentials); + } + /** * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + * * @codeCoverageIgnore + * + * @param mixed $identifier */ public function retrieveById($identifier): ?Authenticatable { @@ -31,7 +99,11 @@ public function retrieveById($identifier): ?Authenticatable /** * @psalm-suppress DocblockTypeContradiction + * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + * + * @param mixed $identifier + * @param mixed $token */ public function retrieveByToken($identifier, $token): ?Authenticatable { @@ -47,7 +119,7 @@ public function retrieveByToken($identifier, $token): ?Authenticatable } $user = $guard->processToken( - token: $token + token: $token, ); if (null === $user) { @@ -55,20 +127,32 @@ public function retrieveByToken($identifier, $token): ?Authenticatable } return $this->getRepository()->fromAccessToken( - user: $user + user: $user, ); } + public function setRepository(string $repository): void + { + $this->resolveRepository($repository); + } + /** * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + * + * @codeCoverageIgnore + * + * @param Authenticatable $user + * @param mixed $token */ - public function retrieveByCredentials(array $credentials): ?Authenticatable + public function updateRememberToken(Authenticatable $user, $token): void { - return $this->getRepository()->fromSession($credentials); } /** * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + * + * @param Authenticatable $user + * @param array $credentials */ public function validateCredentials( Authenticatable $user, @@ -76,70 +160,4 @@ public function validateCredentials( ): bool { return false; } - - /** - * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter - * @codeCoverageIgnore - */ - public function updateRememberToken(Authenticatable $user, $token): void - { - } - - public function getRepository(): RepositoryContract - { - return $this->repository ?? $this->resolveRepository(); - } - - public function setRepository(string $repository): void - { - $this->resolveRepository($repository); - } - - private function resolveRepository( - ?string $repositoryName = null, - ): RepositoryContract { - $model = $repositoryName; - $model ??= $this->getConfiguration('model'); - $model ??= $this->getConfiguration('repository'); - $model ??= Repository::class; - - if ($model === $this->getRepositoryName()) { - return $this->getRepository(); - } - - if (! is_string($model) ) { - throw new BindingResolutionException('The configured Repository could not be loaded.'); - } - - if (! app()->bound($model)) { - throw new BindingResolutionException(sprintf('The configured Repository %s could not be loaded.', $model)); - } - - $this->setRepositoryName($model); - return $this->repository = app($model); - } - - private function getRepositoryName(): string - { - return $this->repositoryName; - } - - private function setRepositoryName(string $repositoryName): void - { - $this->setConfiguration('model', $repositoryName); - $this->repositoryName = $repositoryName; - } - - private function getConfiguration( - string $key, - ): array|string|null { - return $this->config[$key] ?? null; - } - - private function setConfiguration( - string $key, - mixed $value, - ): void { - $this->config[$key] = $value; - } } diff --git a/src/Auth0.php b/src/Auth0.php index aa18821d..19effe9c 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -12,6 +12,7 @@ use Auth0\SDK\Configuration\SdkConfiguration as Configuration; use Auth0\SDK\Contract\Auth0Interface as SDKContract; use Auth0\SDK\Utility\HttpTelemetry; + use function in_array; /** diff --git a/src/Cache/LaravelCacheItem.php b/src/Cache/LaravelCacheItem.php index e28db059..b0986b6c 100644 --- a/src/Cache/LaravelCacheItem.php +++ b/src/Cache/LaravelCacheItem.php @@ -9,6 +9,7 @@ use DateTimeImmutable; use DateTimeInterface; use Psr\Cache\CacheItemInterface; + use function is_int; final class LaravelCacheItem implements CacheItemInterface diff --git a/src/Cache/LaravelCachePool.php b/src/Cache/LaravelCachePool.php index 4a5c9025..ab2246b2 100644 --- a/src/Cache/LaravelCachePool.php +++ b/src/Cache/LaravelCachePool.php @@ -8,6 +8,7 @@ use Illuminate\Cache\CacheManager; use Illuminate\Contracts\Cache\Store; use Psr\Cache\{CacheItemInterface, CacheItemPoolInterface}; + use function is_string; /** diff --git a/src/Configuration.php b/src/Configuration.php index a358604f..ccc8fbbd 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -5,6 +5,7 @@ namespace Auth0\Laravel; use Auth0\Laravel\Contract\Configuration as ConfigurationContract; + use function count; use function is_string; diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index acd533b9..ba81f093 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -14,6 +14,7 @@ use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Http\{RedirectResponse, Request}; use Throwable; + use function is_string; final class Callback extends ControllerAbstract implements CallbackContract diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index bf639f15..70c6face 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -9,6 +9,7 @@ use Auth0\Laravel\Contract\Http\Controller\Stateful\Logout as LogoutContract; use Auth0\Laravel\Http\Controller\ControllerAbstract; use Illuminate\Http\{RedirectResponse, Request}; + use function is_string; final class Logout extends ControllerAbstract implements LogoutContract From 932f29407188c632b13943a90dd9741dc0379ec6 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 21 Mar 2023 00:45:48 -0500 Subject: [PATCH 232/525] Add auth0.behavior.autoLogin to restore previous behavior. --- config/auth0.php | 5 +++++ src/Auth/Guard.php | 28 +++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/config/auth0.php b/config/auth0.php index bc6cd129..79e34fdd 100644 --- a/config/auth0.php +++ b/config/auth0.php @@ -59,4 +59,9 @@ 'home' => env('AUTH0_ROUTE_HOME', '/'), 'login' => env('AUTH0_ROUTE_LOGIN', 'login'), ], + + 'behavior' => [ + // Defaults to false. If true, the SDK will attempt to automatically log in a user when Guard::user() is called. + 'autoLogin' => Configuration::stringToBoolOrNull(env('AUTH0_BEHAVIOR_AUTO_LOGIN'), false), + ] ]; diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index ad008800..1a54381e 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -22,6 +22,7 @@ use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Contracts\Session\Session; use Psr\Container\{ContainerExceptionInterface, NotFoundExceptionInterface}; + use function in_array; use function is_array; use function is_int; @@ -559,7 +560,32 @@ public function setUser( public function user(): ?Authenticatable { - return $this->getCredential()?->getUser(); + $autoLogin = config('auth0.behavior.autoLogin', true); + $currentUser = $this->getCredential()?->getUser(); + + if (null !== $currentUser) { + return $currentUser; + } + + if (true === $autoLogin) { + $token = $this->find(self::SOURCE_TOKEN); + + if (null !== $token) { + $this->login($token, self::SOURCE_TOKEN); + + return $this->getCredential()?->getUser(); + } + + $session = $this->find(self::SOURCE_SESSION); + + if (null !== $session) { + $this->login($token, self::SOURCE_SESSION); + + return $this->getCredential()?->getUser(); + } + } + + return null; } /** From 6f701042df623021731a0f595446077fcd1b9d5b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 21 Mar 2023 00:55:19 -0500 Subject: [PATCH 233/525] Update phpstan.neon.dist --- phpstan.neon.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index cc6df64a..613517aa 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -16,3 +16,4 @@ parameters: - '#no value type specified in iterable type array.#' reportUnmatchedIgnoredErrors: false + treatPhpDocTypesAsCertain: false From 0a42f758e1a14c1ff5b2dfcdfc3d990ee29d034e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 21 Mar 2023 16:12:44 -0500 Subject: [PATCH 234/525] Applied updated styling rules --- src/Contract/Exception/AuthenticationException.php | 3 +++ src/Contract/Exception/GuardException.php | 11 +++++++++++ src/Exception/SessionException.php | 3 +++ src/Exception/Stateful/CallbackException.php | 3 +++ 4 files changed, 20 insertions(+) diff --git a/src/Contract/Exception/AuthenticationException.php b/src/Contract/Exception/AuthenticationException.php index 7bfd0fc7..9a3fd8cf 100644 --- a/src/Contract/Exception/AuthenticationException.php +++ b/src/Contract/Exception/AuthenticationException.php @@ -8,5 +8,8 @@ interface AuthenticationException extends Auth0Exception { + /** + * @var string + */ public const UNAUTHENTICATED = 'Unauthenticated.'; } diff --git a/src/Contract/Exception/GuardException.php b/src/Contract/Exception/GuardException.php index b844aa4d..1d842389 100644 --- a/src/Contract/Exception/GuardException.php +++ b/src/Contract/Exception/GuardException.php @@ -8,7 +8,18 @@ interface GuardException extends Auth0Exception { + /** + * @var string + */ public const USER_MODEL_NORMALIZATION_FAILURE = 'Unable to convert user to array. Class should implement JsonSerializable, Arrayable or Jsonable.'; + + /** + * @var string + */ public const USER_PROVIDER_UNAVAILABLE = 'Unable to create User Provider %s from configuration.'; + + /** + * @var string + */ public const USER_PROVIDER_UNCONFIGURED = 'There is no User Provider configured. Please ensure the `provider` key is set in the Guard configuration, and points to a valid entry in the `providers` configuration.'; } diff --git a/src/Exception/SessionException.php b/src/Exception/SessionException.php index 252bf3a0..dec9c113 100644 --- a/src/Exception/SessionException.php +++ b/src/Exception/SessionException.php @@ -13,5 +13,8 @@ */ final class SessionException extends Exception implements Auth0Exception, SessionExceptionContract { + /** + * @var string + */ public const LARAVEL_SESSION_INACCESSIBLE = 'The Laravel session store is inaccessible.'; } diff --git a/src/Exception/Stateful/CallbackException.php b/src/Exception/Stateful/CallbackException.php index 0e4ab87e..63213111 100644 --- a/src/Exception/Stateful/CallbackException.php +++ b/src/Exception/Stateful/CallbackException.php @@ -13,5 +13,8 @@ */ final class CallbackException extends Exception implements Auth0Exception, CallbackExceptionContract { + /** + * @var string + */ public const MSG_API_RESPONSE = '%s: %s'; } From 71574e018ee141f4ff8848f9ce52172671719469 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 27 Mar 2023 12:59:57 -0500 Subject: [PATCH 235/525] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ca94a6ac..1e1e2c20 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ composer.phar composer.local.json composer.local.json_ .php-cs-fixer.cache +composer.local.old From 55fdcfd974bc540defd5b2e63268462500cfbf15 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 27 Mar 2023 14:36:02 -0500 Subject: [PATCH 236/525] Create .gitattributes --- .gitattributes | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..3a4048b8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,20 @@ +.editorconfig export-ignore +.gitattributes export-ignore +.github/ export-ignore +.gitignore export-ignore +.semgrepignore export-ignore +.shiprc export-ignore +CHANGELOG.md export-ignore +docs/ export-ignore +EXAMPLES.md export-ignore +examples/ export-ignore +opslevel.yml export-ignore +phpdoc.dist.xml export-ignore +phpstan.neon.dist export-ignore +phpunit.xml.dist export-ignore +psalm.xml.dist export-ignore +rector.php export-ignore +tests/ export-ignore +UPGRADE.md export-ignore +vendor/ export-ignore +CHANGELOG.ARCHIVE.md export-ignore From 13f57366c34604b43e5daa3a106099a840a46745 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 27 Mar 2023 14:36:05 -0500 Subject: [PATCH 237/525] Create .semgrepignore --- .semgrepignore | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .semgrepignore diff --git a/.semgrepignore b/.semgrepignore new file mode 100644 index 00000000..37dc6e8d --- /dev/null +++ b/.semgrepignore @@ -0,0 +1,5 @@ +.github/ +docs/ +examples/ +tests/ +\*.md From 7c0e8d34cbcba611c82cb54f31547cc0f3bc9aa9 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 27 Mar 2023 14:36:19 -0500 Subject: [PATCH 238/525] Move CHANGELOG notes for < 7.0 to seperate file. --- CHANGELOG.ARCHIVE.md | 475 ++++++++++++++++++++++++++++++++++++++++ CHANGELOG.md | 507 +------------------------------------------ 2 files changed, 476 insertions(+), 506 deletions(-) create mode 100644 CHANGELOG.ARCHIVE.md diff --git a/CHANGELOG.ARCHIVE.md b/CHANGELOG.ARCHIVE.md new file mode 100644 index 00000000..6091cedc --- /dev/null +++ b/CHANGELOG.ARCHIVE.md @@ -0,0 +1,475 @@ +# Changelog < 7.0.0 + +## [6.5.0](https://github.com/auth0/laravel-auth0/tree/6.5.0) (2021-10-15) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.4.1...6.5.0) + +**Added** + +- Add SDK alias methods for passwordless endpoints [\#228](https://github.com/auth0/laravel-auth0/pull/228) ([evansims](https://github.com/evansims)) + +## [6.4.1](https://github.com/auth0/laravel-auth0/tree/6.4.0) (2021-08-02) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.4.0...6.4.1) + +**Fixed** + +- Use the fully qualified facade class names [\#215](https://github.com/auth0/laravel-auth0/pull/215) ([Rezouce](https://github.com/Rezouce)) +- Update auth0-PHP dependency [\#222](https://github.com/auth0/laravel-auth0/pull/222) ([evansims](https://github.com/evansims)) +- Pass api_identifier config as audience to Auth0\SDK\Auth0 [\#214](https://github.com/auth0/laravel-auth0/pull/214) ([iSerter](https://github.com/iSerter)) + +## [6.4.0](https://github.com/auth0/laravel-auth0/tree/6.4.0) (2021-03-25) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.3.0...6.4.0) + +**Changed** + +- Add support for Auth0 Organizations [\#209](https://github.com/auth0/laravel-auth0/pull/209) ([evansims](https://github.com/evansims)) + +## [6.3.0](https://github.com/auth0/laravel-auth0/tree/6.3.0) (2020-02-18) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.2.0...6.3.0) + +**Changed** + +- Store changes made to the user object during the onLogin event hook [\#206](https://github.com/auth0/laravel-auth0/pull/206) ([evansims](https://github.com/evansims)) + +**Fixed** + +- Avoid throwing an error when calling getUserByUserInfo() during login callback event when the supplied profile is empty/null [\#207](https://github.com/auth0/laravel-auth0/pull/207) ([evansims](https://github.com/evansims)) + +## [6.2.0](https://github.com/auth0/laravel-auth0/tree/6.2.0) (2020-01-15) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.1.0...6.2.0) + +**Added** + +- Support PHP 8.0 [\#200](https://github.com/auth0/laravel-auth0/pull/200) ([evansims](https://github.com/evansims)) + +**Fixed** + +- Fix the missing `return null;` in `getUserByIdentifier` [\#201](https://github.com/auth0/laravel-auth0/pull/201) ([sebwas](https://github.com/sebwas)) + +## [6.1.0](https://github.com/auth0/laravel-auth0/tree/6.1.0) (2020-09-17) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.0.1...6.1.0) + +**Added** + +- Support Laravel 8 [\#190](https://github.com/auth0/laravel-auth0/pull/190) ([giannidhooge](https://github.com/giannidhooge)) + +**Fixed** + +- Fix composer.json whitespace issue [\#192](https://github.com/auth0/laravel-auth0/pull/192) ([jimmyjames](https://github.com/jimmyjames)) + +## [6.0.1](https://github.com/auth0/laravel-auth0/tree/6.0.1) (2020-04-28) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.0.0...6.0.1) + +**Fixed** + +- Fix access token decoding and validation [\#183](https://github.com/auth0/laravel-auth0/pull/183) ([jimmyjames](https://github.com/jimmyjames)) + +## [6.0.0](https://github.com/auth0/laravel-auth0/tree/6.0.0) (2020-04-09) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.4.0...6.0.0) + +**This is a major release and includes breaking changes!** This release also includes a major version change for the PHP SDK that it relies on. Please see the [migration guide](https://github.com/auth0/auth0-PHP/blob/master/MIGRATE-v5-TO-v7.md) for the PHP SDK for more information. + +**Closed issues** + +- auth0-PHP 7.0 - State and nonce handling [\#163](https://github.com/auth0/laravel-auth0/issues/163) +- Cannot use actingAs unit tests functionality [\#161](https://github.com/auth0/laravel-auth0/issues/161) + +**Added** + +- Implement auth0 guard [\#166](https://github.com/auth0/laravel-auth0/pull/166) ([Tamrael](https://github.com/Tamrael)) + +**Changed** + +- Use array for Auth0JWTUser and add repo return types [\#176](https://github.com/auth0/laravel-auth0/pull/176) ([joshcanhelp](https://github.com/joshcanhelp)) +- Update PHP SDK to v7.0.0 [\#162](https://github.com/auth0/laravel-auth0/pull/162) ([joshcanhelp](https://github.com/joshcanhelp)) +- Bind SessionState handler interface in container [\#147](https://github.com/auth0/laravel-auth0/pull/147) ([nstapelbroek](https://github.com/nstapelbroek)) + +**Fixed** + +- Fix Laravel session management [\#174](https://github.com/auth0/laravel-auth0/pull/174) ([joshcanhelp](https://github.com/joshcanhelp)) + +## [5.4.0](https://github.com/auth0/laravel-auth0/tree/5.4.0) (2020-03-27) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.3.1...5.4.0) + +**Closed issues** + +- Laravel 7.0 supported release. [\#171](https://github.com/auth0/laravel-auth0/issues/171) + +**Fixed** + +- Fixed PHPDocs [\#170](https://github.com/auth0/laravel-auth0/pull/170) ([YAhiru](https://github.com/YAhiru)) + +**Added** + +- Laravel 7 support [\#167](https://github.com/auth0/laravel-auth0/pull/167) ([giannidhooge](https://github.com/giannidhooge)) + +## [5.3.1](https://github.com/auth0/laravel-auth0/tree/5.3.1) (2019-11-14) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.3.0...5.3.1) + +**Closed issues** + +- Setting of state_handler in Auth0Service causes "Invalid state" error [\#154](https://github.com/auth0/laravel-auth0/issues/154) + +**Fixed** + +- Allow store and state_handler to be passed in from config [\#156](https://github.com/auth0/laravel-auth0/pull/156) ([joshcanhelp](https://github.com/joshcanhelp)) +- Add 'persist_refresh_token' key to laravel-auth0 configuration file. [\#152](https://github.com/auth0/laravel-auth0/pull/152) ([tpenaranda](https://github.com/tpenaranda)) +- Replace `setEnvironment` with `setEnvProperty` [\#145](https://github.com/auth0/laravel-auth0/pull/145) ([nstapelbroek](https://github.com/nstapelbroek)) + +## [5.3.0](https://github.com/auth0/laravel-auth0/tree/5.3.0) (2019-09-26) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.2.0...5.3.0) + +**Closed issues** + +- Feature request: Add Laravel 6 support [\#138](https://github.com/auth0/laravel-auth0/issues/138) +- SessionStateHandler should use LaravelSessionStore not SessionStore [\#125](https://github.com/auth0/laravel-auth0/issues/125) + +**Added** + +- Support Laravel 6 [\#139](https://github.com/auth0/laravel-auth0/pull/139) ([FreekVR](https://github.com/FreekVR)) + +**Fixed** + +- Use LaravelSessionStore in the SessionStateHandler. [\#135](https://github.com/auth0/laravel-auth0/pull/135) ([nstapelbroek](https://github.com/nstapelbroek)) + +## [5.2.0](https://github.com/auth0/laravel-auth0/tree/5.2.0) (2019-06-27) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.1.0...5.2.0) + +**Closed issues** + +- Authenticate as a Laravel API user using the Auth0 token [\#129](https://github.com/auth0/laravel-auth0/issues/129) +- Redirect to previous page after login [\#122](https://github.com/auth0/laravel-auth0/issues/122) +- Auth0User uses private variables so they cannot be accessed or overridden in child class [\#120](https://github.com/auth0/laravel-auth0/issues/120) +- API routes broken in auth0-laravel-php-web-app (and in general)? [\#117](https://github.com/auth0/laravel-auth0/issues/117) +- API returning "token algorithm not supported" [\#116](https://github.com/auth0/laravel-auth0/issues/116) +- Changing name of user identifier [\#115](https://github.com/auth0/laravel-auth0/issues/115) +- Possible to use User object functions? [\#114](https://github.com/auth0/laravel-auth0/issues/114) +- Auth0-PHP@5.3.1 breaks Laravel-Auth0 [\#108](https://github.com/auth0/laravel-auth0/issues/108) +- Extend Illuminate\Foundation\Auth\User [\#104](https://github.com/auth0/laravel-auth0/issues/104) +- [Bug] Inconsistencies with the singleton Auth0Service [\#103](https://github.com/auth0/laravel-auth0/issues/103) +- How do you combine Auth0 Lock with Laravel Auth0? [\#102](https://github.com/auth0/laravel-auth0/issues/102) +- OnLogin callback question [\#97](https://github.com/auth0/laravel-auth0/issues/97) + +**Added** + +- Add composer.lock file [\#123](https://github.com/auth0/laravel-auth0/pull/123) ([lbalmaceda](https://github.com/lbalmaceda)) + +**Changed** + +- Change private properties to protected [\#132](https://github.com/auth0/laravel-auth0/pull/132) ([joshcanhelp](https://github.com/joshcanhelp)) +- Return null instead of false in Auth0UserProvider. [\#128](https://github.com/auth0/laravel-auth0/pull/128) ([afreakk](https://github.com/afreakk)) +- Change the visibility of the getter method from private to public [\#121](https://github.com/auth0/laravel-auth0/pull/121) ([irieznykov](https://github.com/irieznykov)) +- Updated required PHP version to 5.4 in composer [\#118](https://github.com/auth0/laravel-auth0/pull/118) ([dmyers](https://github.com/dmyers)) +- Changed arrays to use short array syntax [\#110](https://github.com/auth0/laravel-auth0/pull/110) ([dmyers](https://github.com/dmyers)) + +**Fixed** + +- Fix cachehandler resolving issues [\#131](https://github.com/auth0/laravel-auth0/pull/131) ([deviouspk](https://github.com/deviouspk)) +- Added the Auth0Service as a singleton through the classname [\#107](https://github.com/auth0/laravel-auth0/pull/107) ([JCombee](https://github.com/JCombee)) +- Fixed typo [\#106](https://github.com/auth0/laravel-auth0/pull/106) ([IvanArjona](https://github.com/IvanArjona)) + +## [5.1.0](https://github.com/auth0/laravel-auth0/tree/5.1.0) (2018-03-20) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.0.2...5.1.0) + +**Closed issues** + +- pls change config arg name [\#95](https://github.com/auth0/laravel-auth0/issues/95) + +**Added** + +- AutoDiscovery [\#91](https://github.com/auth0/laravel-auth0/pull/91) ([m1guelpf](https://github.com/m1guelpf)) +- Added guzzle options to config to allow for connection options [\#88](https://github.com/auth0/laravel-auth0/pull/88) ([mjmgooch](https://github.com/mjmgooch)) + +**Changed** + +- Change default settings file [\#96](https://github.com/auth0/laravel-auth0/pull/96) ([joshcanhelp](https://github.com/joshcanhelp)) +- Utilise Auth0->Login to ensure state validation [\#90](https://github.com/auth0/laravel-auth0/pull/90) ([cocojoe](https://github.com/cocojoe)) + +**Fixed** + +- Make code comments gender neutral [\#98](https://github.com/auth0/laravel-auth0/pull/98) ([devjack](https://github.com/devjack)) +- Fix README and CHANGELOG [\#99](https://github.com/auth0/laravel-auth0/pull/99) ([joshcanhelp](https://github.com/joshcanhelp)) + +## [5.0.2](https://github.com/auth0/laravel-auth0/tree/5.0.2) (2017-08-30) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.0.1...5.0.2) + +**Merged pull requests:** + +- Use instead of to identify the Auth0 user [\#80](https://github.com/auth0/laravel-auth0/pull/80) ([glena](https://github.com/glena)) + +## [5.0.1](https://github.com/auth0/laravel-auth0/tree/5.0.1) (2017-02-23) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.0.0...5.0.1) + +Fixed `supported_algs` configuration name + +## [5.0.0](https://github.com/auth0/laravel-auth0/tree/5.0.0) (2017-02-22) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.8...5.0.0) + +**Merged pull requests:** + +- V5: update to auth0 sdk v5 [\#69](https://github.com/auth0/laravel-auth0/pull/69) ([glena](https://github.com/glena)) + +## [4.0.8](https://github.com/auth0/laravel-auth0/tree/4.0.8) (2017-01-27) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.7...4.0.8) + +**Closed issues** + +- Allow use of RS256 Protocol [\#63](https://github.com/auth0/wp-auth0/issues/63) +- Add RS256 to the list of supported algorithms [\#62](https://github.com/auth0/wp-auth0/issues/62) + +**Merged pull requests:** + +- allow to configure the algorithm supported for token verification [\#65](https://github.com/auth0/laravel-auth0/pull/65) ([glena](https://github.com/glena)) + +## [4.0.7](https://github.com/auth0/laravel-auth0/tree/4.0.7) (2017-01-02) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.6...4.0.7) + +**Merged pull requests:** + +- it should pass all the configs to the oauth client [\#64](https://github.com/auth0/laravel-auth0/pull/64) ([glena](https://github.com/glena)) + +## [4.0.6](https://github.com/auth0/laravel-auth0/tree/4.0.6) (2016-11-29) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.5...4.0.6) + +**Merged pull requests:** + +- Code style & docblocks [\#56](https://github.com/auth0/laravel-auth0/pull/56) ([seanmangar](https://github.com/seanmangar)) +- Adding accessor to retrieve JWT from Auth0Service [\#58](https://github.com/auth0/laravel-auth0/pull/58) ([ryantology](https://github.com/ryantology)) + +## [4.0.5](https://github.com/auth0/laravel-auth0/tree/4.0.5) (2016-11-29) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.4...4.0.5) + +**Merged pull requests:** + +- Added flag for not encoded tokens + removed example [\#57](https://github.com/auth0/laravel-auth0/pull/57) ([glena](https://github.com/glena)) + +## [4.0.4](https://github.com/auth0/laravel-auth0/tree/4.0.4) (2016-11-25) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.2...4.0.4) + +**Merged pull requests:** + +- Fixing config type [\#55](https://github.com/auth0/laravel-auth0/pull/55) ([adamgoose](https://github.com/adamgoose)) + +## [4.0.2](https://github.com/auth0/laravel-auth0/tree/4.0.2) (2016-10-03) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.1...4.0.2) + +**Merged pull requests:** + +- Fixing JWTVerifier [\#54](https://github.com/auth0/laravel-auth0/pull/54) ([adamgoose](https://github.com/adamgoose)) + +## [4.0.1](https://github.com/auth0/laravel-auth0/tree/4.0.1) (2016-09-19) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.0...4.0.1) + +**Merged pull requests:** + +- fix error becuase of contract and class with the same name [\#52](https://github.com/auth0/laravel-auth0/pull/52) ([glena](https://github.com/glena)) + +## [4.0.0](https://github.com/auth0/laravel-auth0/tree/4.0.0) (2016-09-15) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.2.1...4.0.0) + +Better support for Laravel 5.3: Support for Laravel Passport for token verification +Support of auth0 PHP sdk v4 with JWKs cache + +**Merged pull requests:** + +- Merge pull request #50 from auth0/4.x.x-dev [\#50](https://github.com/auth0/laravel-auth0/pull/50) ([glena](https://github.com/glena)) + +## [3.2.1](https://github.com/auth0/laravel-auth0/tree/3.2.1) (2016-09-12) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.2.0...3.2.1) + +**Merged pull requests:** + +- Fix for Laravel 5.2 [\#49](https://github.com/auth0/laravel-auth0/pull/49) ([dscafati](https://github.com/dscafati)) + +## [3.2.0](https://github.com/auth0/laravel-auth0/tree/3.2.0) (2016-07-11) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.1.0...3.2.0) + +**Merged pull requests:** + +- New optional jwt middleware [\#40](https://github.com/auth0/laravel-auth0/pull/40) ([glena](https://github.com/glena)) + +## [3.1.0](https://github.com/auth0/laravel-auth0/tree/3.1.0) (2016-05-02) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.3...3.1.0) + +**Merged pull requests:** + +- 3.1.0 [\#36](https://github.com/auth0/laravel-auth0/pull/36) ([glena](https://github.com/glena)) + +## [3.0.3](https://github.com/auth0/laravel-auth0/tree/3.0.3) (2016-01-28) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.2...3.0.3) + +**Closed issues:** + +- Tag 2.2.2 breaks on Laravel 5.1 [\#30](https://github.com/auth0/laravel-auth0/issues/30) + +**Merged pull requests:** + +- Conform to 5.2's Authenticatable contract [\#31](https://github.com/auth0/laravel-auth0/pull/31) ([ryannjohnson](https://github.com/ryannjohnson)) + +## [3.0.2](https://github.com/auth0/laravel-auth0/tree/3.0.2) (2016-01-25) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.2.1...3.0.2) + +**Merged pull requests:** + +- Added optional persistence configuration values [\#29](https://github.com/auth0/laravel-auth0/pull/29) ([carnevalle](https://github.com/carnevalle)) + +## [2.2.1](https://github.com/auth0/laravel-auth0/tree/2.2.1) (2016-01-22) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.1...2.2.1) + +**Closed issues:** + +- Create a logout route [\#25](https://github.com/auth0/laravel-auth0/issues/25) + +**Merged pull requests:** + +- Auth0 SDK checks for null values instead of false [\#27](https://github.com/auth0/laravel-auth0/pull/27) ([thijsvdanker](https://github.com/thijsvdanker)) + +## [3.0.1](https://github.com/auth0/laravel-auth0/tree/3.0.1) (2016-01-18) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.0...3.0.1) + +**Merged pull requests:** + +- updated auth0-php dependency [\#24](https://github.com/auth0/laravel-auth0/pull/24) ([glena](https://github.com/glena)) + +## [3.0.0](https://github.com/auth0/laravel-auth0/tree/3.0.0) (2016-01-06) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.2.0...3.0.0) + +**Closed issues:** + +- auth0/auth0-php ~1.0 requirement doesn't support latest GuzzleHttp [\#21](https://github.com/auth0/laravel-auth0/issues/21) + +**Merged pull requests:** + +- updated to be compatible with laravel 5.2 [\#23](https://github.com/auth0/laravel-auth0/pull/23) ([glena](https://github.com/glena)) + +## [2.2.0](https://github.com/auth0/laravel-auth0/tree/2.2.0) (2015-11-30) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.4...2.2.0) + +**Merged pull requests:** + +- updated auth0-php dependency version [\#22](https://github.com/auth0/laravel-auth0/pull/22) ([glena](https://github.com/glena)) +- Update login.blade.php [\#20](https://github.com/auth0/laravel-auth0/pull/20) ([Annyv2](https://github.com/Annyv2)) + +## [2.1.4](https://github.com/auth0/laravel-auth0/tree/2.1.4) (2015-10-27) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.3...2.1.4) + +**Merged pull requests:** + +- Middleware contract has been deprecated in 5.1 [\#19](https://github.com/auth0/laravel-auth0/pull/19) ([thijsvdanker](https://github.com/thijsvdanker)) +- Fixed some typo's in the comments. [\#18](https://github.com/auth0/laravel-auth0/pull/18) ([thijsvdanker](https://github.com/thijsvdanker)) +- Removed note about unstable dependency from README [\#17](https://github.com/auth0/laravel-auth0/pull/17) ([thijsvdanker](https://github.com/thijsvdanker)) +- Update composer instructions [\#16](https://github.com/auth0/laravel-auth0/pull/16) ([iWader](https://github.com/iWader)) +- Use a tagged release of adoy/oauth2 [\#15](https://github.com/auth0/laravel-auth0/pull/15) ([thijsvdanker](https://github.com/thijsvdanker)) + +## [2.1.3](https://github.com/auth0/laravel-auth0/tree/2.1.3) (2015-07-17) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.2...2.1.3) + +**Merged pull requests:** + +- updated jwt dependency [\#14](https://github.com/auth0/laravel-auth0/pull/14) ([glena](https://github.com/glena)) + +## [2.1.2](https://github.com/auth0/laravel-auth0/tree/2.1.2) (2015-05-15) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.1...2.1.2) + +**Merged pull requests:** + +- Added override of info headers [\#13](https://github.com/auth0/laravel-auth0/pull/13) ([glena](https://github.com/glena)) + +## [2.1.1](https://github.com/auth0/laravel-auth0/tree/2.1.1) (2015-05-12) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.0...2.1.1) + +**Closed issues:** + +- SDK Client headers spec compliant [\#11](https://github.com/auth0/laravel-auth0/issues/11) +- Support for Laravel 5? [\#6](https://github.com/auth0/laravel-auth0/issues/6) + +**Merged pull requests:** + +- SDK Client headers spec compliant \#11 [\#12](https://github.com/auth0/laravel-auth0/pull/12) ([glena](https://github.com/glena)) + +## [2.1.0](https://github.com/auth0/laravel-auth0/tree/2.1.0) (2015-05-07) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.0.0...2.1.0) + +**Merged pull requests:** + +- Upgrade to auth-php 1.0.0: Added support to API V2 [\#10](https://github.com/auth0/laravel-auth0/pull/10) ([glena](https://github.com/glena)) + +## [2.0.0](https://github.com/auth0/laravel-auth0/tree/2.0.0) (2015-04-20) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.8...2.0.0) + +**Merged pull requests:** + +- Package V2 for Laravel5 [\#9](https://github.com/auth0/laravel-auth0/pull/9) ([glena](https://github.com/glena)) + +## [1.0.8](https://github.com/auth0/laravel-auth0/tree/1.0.8) (2015-04-14) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.7...1.0.8) + +## [1.0.7](https://github.com/auth0/laravel-auth0/tree/1.0.7) (2015-04-13) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.6...1.0.7) + +**Merged pull requests:** + +- Fixed the way the access token is pased to the A0User [\#7](https://github.com/auth0/laravel-auth0/pull/7) ([glena](https://github.com/glena)) +- Update README.md [\#5](https://github.com/auth0/laravel-auth0/pull/5) ([pose](https://github.com/pose)) + +## [1.0.6](https://github.com/auth0/laravel-auth0/tree/1.0.6) (2014-08-01) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.5...1.0.6) + +## [1.0.5](https://github.com/auth0/laravel-auth0/tree/1.0.5) (2014-08-01) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.4...1.0.5) + +**Closed issues:** + +- Problem with normal laravel user table [\#4](https://github.com/auth0/laravel-auth0/issues/4) + +**Merged pull requests:** + +- Update README.md [\#3](https://github.com/auth0/laravel-auth0/pull/3) ([patekuru](https://github.com/patekuru)) + +## [1.0.4](https://github.com/auth0/laravel-auth0/tree/1.0.4) (2014-05-07) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.3...1.0.4) + +## [1.0.3](https://github.com/auth0/laravel-auth0/tree/1.0.3) (2014-04-21) diff --git a/CHANGELOG.md b/CHANGELOG.md index acf2a301..44b33aec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -139,509 +139,4 @@ As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes - SDK now self-registers its services and middleware - New UserProvider API -## [7.0.0-BETA2](https://github.com/auth0/laravel-auth0/tree/7.0.0-BETA2) (2022-03-09) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.5.0...7.0.0-BETA2) - -Please review the [BETA1 changelog notes below](#700-beta1-2022-02-08) before upgrading your application from 6.x, as 7.0 is a new major containing breaking changes. As with all beta releases, this should not be considered stable or suitable for production use, but your experimentation with and feedback around it is greatly appreciated. - -**Changes** - -- Update Middleware interface checks for custom user model types [\#263](https://github.com/auth0/laravel-auth0/pull/263) ([sheggi](https://github.com/sheggi)) -- Updated UserProvider API [\#264](https://github.com/auth0/laravel-auth0/pull/264) ([evansims](https://github.com/evansims)) -- Add Rector to test suite [\#265](https://github.com/auth0/laravel-auth0/pull/265) ([evansims](https://github.com/evansims)) - -## [7.0.0-BETA1](https://github.com/auth0/laravel-auth0/tree/7.0.0-BETA1) (2022-02-08) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.5.0...7.0.0-BETA1) - -Auth0 Laravel SDK v7 includes many significant changes over previous versions: - -- Support for Laravel 9. -- Support for Auth0-PHP SDK 8. -- New authentication route controllers for plug-and-play login support. -- Improved authentication middleware for regular web applications. -- New authorization middleware for token-based backend API applications. - -As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes. Please review the [upgrade guide](UPGRADE.md) thoroughly to understand the changes required to migrate your application to v7. - -**Breaking Changes Summary** - -- Namespace has been updated from `Auth0\Login` to `Auth0\Laravel` -- Auth0-PHP SDK dependency updated to V8 -- New configuration format -- SDK now self-registers its services and middleware - -## [6.5.0](https://github.com/auth0/laravel-auth0/tree/6.5.0) (2021-10-15) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.4.1...6.5.0) - -**Added** - -- Add SDK alias methods for passwordless endpoints [\#228](https://github.com/auth0/laravel-auth0/pull/228) ([evansims](https://github.com/evansims)) - -## [6.4.1](https://github.com/auth0/laravel-auth0/tree/6.4.0) (2021-08-02) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.4.0...6.4.1) - -**Fixed** - -- Use the fully qualified facade class names [\#215](https://github.com/auth0/laravel-auth0/pull/215) ([Rezouce](https://github.com/Rezouce)) -- Update auth0-PHP dependency [\#222](https://github.com/auth0/laravel-auth0/pull/222) ([evansims](https://github.com/evansims)) -- Pass api_identifier config as audience to Auth0\SDK\Auth0 [\#214](https://github.com/auth0/laravel-auth0/pull/214) ([iSerter](https://github.com/iSerter)) - -## [6.4.0](https://github.com/auth0/laravel-auth0/tree/6.4.0) (2021-03-25) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.3.0...6.4.0) - -**Changed** - -- Add support for Auth0 Organizations [\#209](https://github.com/auth0/laravel-auth0/pull/209) ([evansims](https://github.com/evansims)) - -## [6.3.0](https://github.com/auth0/laravel-auth0/tree/6.3.0) (2020-02-18) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.2.0...6.3.0) - -**Changed** - -- Store changes made to the user object during the onLogin event hook [\#206](https://github.com/auth0/laravel-auth0/pull/206) ([evansims](https://github.com/evansims)) - -**Fixed** - -- Avoid throwing an error when calling getUserByUserInfo() during login callback event when the supplied profile is empty/null [\#207](https://github.com/auth0/laravel-auth0/pull/207) ([evansims](https://github.com/evansims)) - -## [6.2.0](https://github.com/auth0/laravel-auth0/tree/6.2.0) (2020-01-15) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.1.0...6.2.0) - -**Added** - -- Support PHP 8.0 [\#200](https://github.com/auth0/laravel-auth0/pull/200) ([evansims](https://github.com/evansims)) - -**Fixed** - -- Fix the missing `return null;` in `getUserByIdentifier` [\#201](https://github.com/auth0/laravel-auth0/pull/201) ([sebwas](https://github.com/sebwas)) - -## [6.1.0](https://github.com/auth0/laravel-auth0/tree/6.1.0) (2020-09-17) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.0.1...6.1.0) - -**Added** - -- Support Laravel 8 [\#190](https://github.com/auth0/laravel-auth0/pull/190) ([giannidhooge](https://github.com/giannidhooge)) - -**Fixed** - -- Fix composer.json whitespace issue [\#192](https://github.com/auth0/laravel-auth0/pull/192) ([jimmyjames](https://github.com/jimmyjames)) - -## [6.0.1](https://github.com/auth0/laravel-auth0/tree/6.0.1) (2020-04-28) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.0.0...6.0.1) - -**Fixed** - -- Fix access token decoding and validation [\#183](https://github.com/auth0/laravel-auth0/pull/183) ([jimmyjames](https://github.com/jimmyjames)) - -## [6.0.0](https://github.com/auth0/laravel-auth0/tree/6.0.0) (2020-04-09) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.4.0...6.0.0) - -**This is a major release and includes breaking changes!** This release also includes a major version change for the PHP SDK that it relies on. Please see the [migration guide](https://github.com/auth0/auth0-PHP/blob/master/MIGRATE-v5-TO-v7.md) for the PHP SDK for more information. - -**Closed issues** - -- auth0-PHP 7.0 - State and nonce handling [\#163](https://github.com/auth0/laravel-auth0/issues/163) -- Cannot use actingAs unit tests functionality [\#161](https://github.com/auth0/laravel-auth0/issues/161) - -**Added** - -- Implement auth0 guard [\#166](https://github.com/auth0/laravel-auth0/pull/166) ([Tamrael](https://github.com/Tamrael)) - -**Changed** - -- Use array for Auth0JWTUser and add repo return types [\#176](https://github.com/auth0/laravel-auth0/pull/176) ([joshcanhelp](https://github.com/joshcanhelp)) -- Update PHP SDK to v7.0.0 [\#162](https://github.com/auth0/laravel-auth0/pull/162) ([joshcanhelp](https://github.com/joshcanhelp)) -- Bind SessionState handler interface in container [\#147](https://github.com/auth0/laravel-auth0/pull/147) ([nstapelbroek](https://github.com/nstapelbroek)) - -**Fixed** - -- Fix Laravel session management [\#174](https://github.com/auth0/laravel-auth0/pull/174) ([joshcanhelp](https://github.com/joshcanhelp)) - -## [5.4.0](https://github.com/auth0/laravel-auth0/tree/5.4.0) (2020-03-27) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.3.1...5.4.0) - -**Closed issues** - -- Laravel 7.0 supported release. [\#171](https://github.com/auth0/laravel-auth0/issues/171) - -**Fixed** - -- Fixed PHPDocs [\#170](https://github.com/auth0/laravel-auth0/pull/170) ([YAhiru](https://github.com/YAhiru)) - -**Added** - -- Laravel 7 support [\#167](https://github.com/auth0/laravel-auth0/pull/167) ([giannidhooge](https://github.com/giannidhooge)) - -## [5.3.1](https://github.com/auth0/laravel-auth0/tree/5.3.1) (2019-11-14) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.3.0...5.3.1) - -**Closed issues** - -- Setting of state_handler in Auth0Service causes "Invalid state" error [\#154](https://github.com/auth0/laravel-auth0/issues/154) - -**Fixed** - -- Allow store and state_handler to be passed in from config [\#156](https://github.com/auth0/laravel-auth0/pull/156) ([joshcanhelp](https://github.com/joshcanhelp)) -- Add 'persist_refresh_token' key to laravel-auth0 configuration file. [\#152](https://github.com/auth0/laravel-auth0/pull/152) ([tpenaranda](https://github.com/tpenaranda)) -- Replace `setEnvironment` with `setEnvProperty` [\#145](https://github.com/auth0/laravel-auth0/pull/145) ([nstapelbroek](https://github.com/nstapelbroek)) - -## [5.3.0](https://github.com/auth0/laravel-auth0/tree/5.3.0) (2019-09-26) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.2.0...5.3.0) - -**Closed issues** - -- Feature request: Add Laravel 6 support [\#138](https://github.com/auth0/laravel-auth0/issues/138) -- SessionStateHandler should use LaravelSessionStore not SessionStore [\#125](https://github.com/auth0/laravel-auth0/issues/125) - -**Added** - -- Support Laravel 6 [\#139](https://github.com/auth0/laravel-auth0/pull/139) ([FreekVR](https://github.com/FreekVR)) - -**Fixed** - -- Use LaravelSessionStore in the SessionStateHandler. [\#135](https://github.com/auth0/laravel-auth0/pull/135) ([nstapelbroek](https://github.com/nstapelbroek)) - -## [5.2.0](https://github.com/auth0/laravel-auth0/tree/5.2.0) (2019-06-27) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.1.0...5.2.0) - -**Closed issues** - -- Authenticate as a Laravel API user using the Auth0 token [\#129](https://github.com/auth0/laravel-auth0/issues/129) -- Redirect to previous page after login [\#122](https://github.com/auth0/laravel-auth0/issues/122) -- Auth0User uses private variables so they cannot be accessed or overridden in child class [\#120](https://github.com/auth0/laravel-auth0/issues/120) -- API routes broken in auth0-laravel-php-web-app (and in general)? [\#117](https://github.com/auth0/laravel-auth0/issues/117) -- API returning "token algorithm not supported" [\#116](https://github.com/auth0/laravel-auth0/issues/116) -- Changing name of user identifier [\#115](https://github.com/auth0/laravel-auth0/issues/115) -- Possible to use User object functions? [\#114](https://github.com/auth0/laravel-auth0/issues/114) -- Auth0-PHP@5.3.1 breaks Laravel-Auth0 [\#108](https://github.com/auth0/laravel-auth0/issues/108) -- Extend Illuminate\Foundation\Auth\User [\#104](https://github.com/auth0/laravel-auth0/issues/104) -- [Bug] Inconsistencies with the singleton Auth0Service [\#103](https://github.com/auth0/laravel-auth0/issues/103) -- How do you combine Auth0 Lock with Laravel Auth0? [\#102](https://github.com/auth0/laravel-auth0/issues/102) -- OnLogin callback question [\#97](https://github.com/auth0/laravel-auth0/issues/97) - -**Added** - -- Add composer.lock file [\#123](https://github.com/auth0/laravel-auth0/pull/123) ([lbalmaceda](https://github.com/lbalmaceda)) - -**Changed** - -- Change private properties to protected [\#132](https://github.com/auth0/laravel-auth0/pull/132) ([joshcanhelp](https://github.com/joshcanhelp)) -- Return null instead of false in Auth0UserProvider. [\#128](https://github.com/auth0/laravel-auth0/pull/128) ([afreakk](https://github.com/afreakk)) -- Change the visibility of the getter method from private to public [\#121](https://github.com/auth0/laravel-auth0/pull/121) ([irieznykov](https://github.com/irieznykov)) -- Updated required PHP version to 5.4 in composer [\#118](https://github.com/auth0/laravel-auth0/pull/118) ([dmyers](https://github.com/dmyers)) -- Changed arrays to use short array syntax [\#110](https://github.com/auth0/laravel-auth0/pull/110) ([dmyers](https://github.com/dmyers)) - -**Fixed** - -- Fix cachehandler resolving issues [\#131](https://github.com/auth0/laravel-auth0/pull/131) ([deviouspk](https://github.com/deviouspk)) -- Added the Auth0Service as a singleton through the classname [\#107](https://github.com/auth0/laravel-auth0/pull/107) ([JCombee](https://github.com/JCombee)) -- Fixed typo [\#106](https://github.com/auth0/laravel-auth0/pull/106) ([IvanArjona](https://github.com/IvanArjona)) - -## [5.1.0](https://github.com/auth0/laravel-auth0/tree/5.1.0) (2018-03-20) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.0.2...5.1.0) - -**Closed issues** - -- pls change config arg name [\#95](https://github.com/auth0/laravel-auth0/issues/95) - -**Added** - -- AutoDiscovery [\#91](https://github.com/auth0/laravel-auth0/pull/91) ([m1guelpf](https://github.com/m1guelpf)) -- Added guzzle options to config to allow for connection options [\#88](https://github.com/auth0/laravel-auth0/pull/88) ([mjmgooch](https://github.com/mjmgooch)) - -**Changed** - -- Change default settings file [\#96](https://github.com/auth0/laravel-auth0/pull/96) ([joshcanhelp](https://github.com/joshcanhelp)) -- Utilise Auth0->Login to ensure state validation [\#90](https://github.com/auth0/laravel-auth0/pull/90) ([cocojoe](https://github.com/cocojoe)) - -**Fixed** - -- Make code comments gender neutral [\#98](https://github.com/auth0/laravel-auth0/pull/98) ([devjack](https://github.com/devjack)) -- Fix README and CHANGELOG [\#99](https://github.com/auth0/laravel-auth0/pull/99) ([joshcanhelp](https://github.com/joshcanhelp)) - -## [5.0.2](https://github.com/auth0/laravel-auth0/tree/5.0.2) (2017-08-30) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.0.1...5.0.2) - -**Merged pull requests:** - -- Use instead of to identify the Auth0 user [\#80](https://github.com/auth0/laravel-auth0/pull/80) ([glena](https://github.com/glena)) - -## [5.0.1](https://github.com/auth0/laravel-auth0/tree/5.0.1) (2017-02-23) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.0.0...5.0.1) - -Fixed `supported_algs` configuration name - -## [5.0.0](https://github.com/auth0/laravel-auth0/tree/5.0.0) (2017-02-22) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.8...5.0.0) - -**Merged pull requests:** - -- V5: update to auth0 sdk v5 [\#69](https://github.com/auth0/laravel-auth0/pull/69) ([glena](https://github.com/glena)) - -## [4.0.8](https://github.com/auth0/laravel-auth0/tree/4.0.8) (2017-01-27) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.7...4.0.8) - -**Closed issues** - -- Allow use of RS256 Protocol [\#63](https://github.com/auth0/wp-auth0/issues/63) -- Add RS256 to the list of supported algorithms [\#62](https://github.com/auth0/wp-auth0/issues/62) - -**Merged pull requests:** - -- allow to configure the algorithm supported for token verification [\#65](https://github.com/auth0/laravel-auth0/pull/65) ([glena](https://github.com/glena)) - -## [4.0.7](https://github.com/auth0/laravel-auth0/tree/4.0.7) (2017-01-02) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.6...4.0.7) - -**Merged pull requests:** - -- it should pass all the configs to the oauth client [\#64](https://github.com/auth0/laravel-auth0/pull/64) ([glena](https://github.com/glena)) - -## [4.0.6](https://github.com/auth0/laravel-auth0/tree/4.0.6) (2016-11-29) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.5...4.0.6) - -**Merged pull requests:** - -- Code style & docblocks [\#56](https://github.com/auth0/laravel-auth0/pull/56) ([seanmangar](https://github.com/seanmangar)) -- Adding accessor to retrieve JWT from Auth0Service [\#58](https://github.com/auth0/laravel-auth0/pull/58) ([ryantology](https://github.com/ryantology)) - -## [4.0.5](https://github.com/auth0/laravel-auth0/tree/4.0.5) (2016-11-29) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.4...4.0.5) - -**Merged pull requests:** - -- Added flag for not encoded tokens + removed example [\#57](https://github.com/auth0/laravel-auth0/pull/57) ([glena](https://github.com/glena)) - -## [4.0.4](https://github.com/auth0/laravel-auth0/tree/4.0.4) (2016-11-25) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.2...4.0.4) - -**Merged pull requests:** - -- Fixing config type [\#55](https://github.com/auth0/laravel-auth0/pull/55) ([adamgoose](https://github.com/adamgoose)) - -## [4.0.2](https://github.com/auth0/laravel-auth0/tree/4.0.2) (2016-10-03) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.1...4.0.2) - -**Merged pull requests:** - -- Fixing JWTVerifier [\#54](https://github.com/auth0/laravel-auth0/pull/54) ([adamgoose](https://github.com/adamgoose)) - -## [4.0.1](https://github.com/auth0/laravel-auth0/tree/4.0.1) (2016-09-19) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.0...4.0.1) - -**Merged pull requests:** - -- fix error becuase of contract and class with the same name [\#52](https://github.com/auth0/laravel-auth0/pull/52) ([glena](https://github.com/glena)) - -## [4.0.0](https://github.com/auth0/laravel-auth0/tree/4.0.0) (2016-09-15) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.2.1...4.0.0) - -Better support for Laravel 5.3: Support for Laravel Passport for token verification -Support of auth0 PHP sdk v4 with JWKs cache - -**Merged pull requests:** - -- Merge pull request #50 from auth0/4.x.x-dev [\#50](https://github.com/auth0/laravel-auth0/pull/50) ([glena](https://github.com/glena)) - -## [3.2.1](https://github.com/auth0/laravel-auth0/tree/3.2.1) (2016-09-12) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.2.0...3.2.1) - -**Merged pull requests:** - -- Fix for Laravel 5.2 [\#49](https://github.com/auth0/laravel-auth0/pull/49) ([dscafati](https://github.com/dscafati)) - -## [3.2.0](https://github.com/auth0/laravel-auth0/tree/3.2.0) (2016-07-11) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.1.0...3.2.0) - -**Merged pull requests:** - -- New optional jwt middleware [\#40](https://github.com/auth0/laravel-auth0/pull/40) ([glena](https://github.com/glena)) - -## [3.1.0](https://github.com/auth0/laravel-auth0/tree/3.1.0) (2016-05-02) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.3...3.1.0) - -**Merged pull requests:** - -- 3.1.0 [\#36](https://github.com/auth0/laravel-auth0/pull/36) ([glena](https://github.com/glena)) - -## [3.0.3](https://github.com/auth0/laravel-auth0/tree/3.0.3) (2016-01-28) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.2...3.0.3) - -**Closed issues:** - -- Tag 2.2.2 breaks on Laravel 5.1 [\#30](https://github.com/auth0/laravel-auth0/issues/30) - -**Merged pull requests:** - -- Conform to 5.2's Authenticatable contract [\#31](https://github.com/auth0/laravel-auth0/pull/31) ([ryannjohnson](https://github.com/ryannjohnson)) - -## [3.0.2](https://github.com/auth0/laravel-auth0/tree/3.0.2) (2016-01-25) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.2.1...3.0.2) - -**Merged pull requests:** - -- Added optional persistence configuration values [\#29](https://github.com/auth0/laravel-auth0/pull/29) ([carnevalle](https://github.com/carnevalle)) - -## [2.2.1](https://github.com/auth0/laravel-auth0/tree/2.2.1) (2016-01-22) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.1...2.2.1) - -**Closed issues:** - -- Create a logout route [\#25](https://github.com/auth0/laravel-auth0/issues/25) - -**Merged pull requests:** - -- Auth0 SDK checks for null values instead of false [\#27](https://github.com/auth0/laravel-auth0/pull/27) ([thijsvdanker](https://github.com/thijsvdanker)) - -## [3.0.1](https://github.com/auth0/laravel-auth0/tree/3.0.1) (2016-01-18) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.0...3.0.1) - -**Merged pull requests:** - -- updated auth0-php dependency [\#24](https://github.com/auth0/laravel-auth0/pull/24) ([glena](https://github.com/glena)) - -## [3.0.0](https://github.com/auth0/laravel-auth0/tree/3.0.0) (2016-01-06) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.2.0...3.0.0) - -**Closed issues:** - -- auth0/auth0-php ~1.0 requirement doesn't support latest GuzzleHttp [\#21](https://github.com/auth0/laravel-auth0/issues/21) - -**Merged pull requests:** - -- updated to be compatible with laravel 5.2 [\#23](https://github.com/auth0/laravel-auth0/pull/23) ([glena](https://github.com/glena)) - -## [2.2.0](https://github.com/auth0/laravel-auth0/tree/2.2.0) (2015-11-30) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.4...2.2.0) - -**Merged pull requests:** - -- updated auth0-php dependency version [\#22](https://github.com/auth0/laravel-auth0/pull/22) ([glena](https://github.com/glena)) -- Update login.blade.php [\#20](https://github.com/auth0/laravel-auth0/pull/20) ([Annyv2](https://github.com/Annyv2)) - -## [2.1.4](https://github.com/auth0/laravel-auth0/tree/2.1.4) (2015-10-27) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.3...2.1.4) - -**Merged pull requests:** - -- Middleware contract has been deprecated in 5.1 [\#19](https://github.com/auth0/laravel-auth0/pull/19) ([thijsvdanker](https://github.com/thijsvdanker)) -- Fixed some typo's in the comments. [\#18](https://github.com/auth0/laravel-auth0/pull/18) ([thijsvdanker](https://github.com/thijsvdanker)) -- Removed note about unstable dependency from README [\#17](https://github.com/auth0/laravel-auth0/pull/17) ([thijsvdanker](https://github.com/thijsvdanker)) -- Update composer instructions [\#16](https://github.com/auth0/laravel-auth0/pull/16) ([iWader](https://github.com/iWader)) -- Use a tagged release of adoy/oauth2 [\#15](https://github.com/auth0/laravel-auth0/pull/15) ([thijsvdanker](https://github.com/thijsvdanker)) - -## [2.1.3](https://github.com/auth0/laravel-auth0/tree/2.1.3) (2015-07-17) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.2...2.1.3) - -**Merged pull requests:** - -- updated jwt dependency [\#14](https://github.com/auth0/laravel-auth0/pull/14) ([glena](https://github.com/glena)) - -## [2.1.2](https://github.com/auth0/laravel-auth0/tree/2.1.2) (2015-05-15) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.1...2.1.2) - -**Merged pull requests:** - -- Added override of info headers [\#13](https://github.com/auth0/laravel-auth0/pull/13) ([glena](https://github.com/glena)) - -## [2.1.1](https://github.com/auth0/laravel-auth0/tree/2.1.1) (2015-05-12) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.0...2.1.1) - -**Closed issues:** - -- SDK Client headers spec compliant [\#11](https://github.com/auth0/laravel-auth0/issues/11) -- Support for Laravel 5? [\#6](https://github.com/auth0/laravel-auth0/issues/6) - -**Merged pull requests:** - -- SDK Client headers spec compliant \#11 [\#12](https://github.com/auth0/laravel-auth0/pull/12) ([glena](https://github.com/glena)) - -## [2.1.0](https://github.com/auth0/laravel-auth0/tree/2.1.0) (2015-05-07) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.0.0...2.1.0) - -**Merged pull requests:** - -- Upgrade to auth-php 1.0.0: Added support to API V2 [\#10](https://github.com/auth0/laravel-auth0/pull/10) ([glena](https://github.com/glena)) - -## [2.0.0](https://github.com/auth0/laravel-auth0/tree/2.0.0) (2015-04-20) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.8...2.0.0) - -**Merged pull requests:** - -- Package V2 for Laravel5 [\#9](https://github.com/auth0/laravel-auth0/pull/9) ([glena](https://github.com/glena)) - -## [1.0.8](https://github.com/auth0/laravel-auth0/tree/1.0.8) (2015-04-14) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.7...1.0.8) - -## [1.0.7](https://github.com/auth0/laravel-auth0/tree/1.0.7) (2015-04-13) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.6...1.0.7) - -**Merged pull requests:** - -- Fixed the way the access token is pased to the A0User [\#7](https://github.com/auth0/laravel-auth0/pull/7) ([glena](https://github.com/glena)) -- Update README.md [\#5](https://github.com/auth0/laravel-auth0/pull/5) ([pose](https://github.com/pose)) - -## [1.0.6](https://github.com/auth0/laravel-auth0/tree/1.0.6) (2014-08-01) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.5...1.0.6) - -## [1.0.5](https://github.com/auth0/laravel-auth0/tree/1.0.5) (2014-08-01) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.4...1.0.5) - -**Closed issues:** - -- Problem with normal laravel user table [\#4](https://github.com/auth0/laravel-auth0/issues/4) - -**Merged pull requests:** - -- Update README.md [\#3](https://github.com/auth0/laravel-auth0/pull/3) ([patekuru](https://github.com/patekuru)) - -## [1.0.4](https://github.com/auth0/laravel-auth0/tree/1.0.4) (2014-05-07) - -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.3...1.0.4) - -## [1.0.3](https://github.com/auth0/laravel-auth0/tree/1.0.3) (2014-04-21) +> Changelog entries for releases prior to 8.0 have been relocated to [CHANGELOG.ARCHIVE.md](CHANGELOG.ARCHIVE.md). From df5c6effd1b664d76a9e3e8730d72216abb326f8 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 27 Mar 2023 14:36:28 -0500 Subject: [PATCH 239/525] Replace redundant dependency. --- composer.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/composer.json b/composer.json index b0abc356..0e4fa8d1 100644 --- a/composer.json +++ b/composer.json @@ -55,9 +55,7 @@ "phpstan/phpstan-strict-rules": "^1.5", "phpstan/phpstan": "^1.10", "psalm/plugin-laravel": "^2.8", - "psr-mock/http-client-implementation": "1.x-dev", - "psr-mock/http-factory-implementation": "1.x-dev", - "psr-mock/http-message-implementation": "1.x-dev", + "psr-mock/http": "^1.0", "rector/rector": "^0.15", "vimeo/psalm": "^5.8", "wikimedia/composer-merge-plugin": "^2.0" From f6d045c0db25b3330224c259d06217071f72b6ff Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 27 Mar 2023 14:36:35 -0500 Subject: [PATCH 240/525] Cleanup configuration. --- rector.php | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/rector.php b/rector.php index 6ed59291..50008adb 100644 --- a/rector.php +++ b/rector.php @@ -332,10 +332,6 @@ ); $rectorConfig->rules([ - // AddParamTypeFromPropertyTypeRector::class, - // ChangeOrIfReturnToEarlyReturnRector::class, - // RemoveAlwaysTrueIfConditionRector::class, - // RenameParamToMatchTypeRector::class, AbsolutizeRequireAndIncludePathRector::class, ActionInjectionToConstructorInjectionRector::class, AddArrayDefaultToArrayPropertyRector::class, @@ -364,7 +360,6 @@ CallUserFuncToMethodCallRector::class, CallUserFuncWithArrowFunctionToInlineRector::class, CatchExceptionNameMatchingTypeRector::class, - // ChangeAndIfToEarlyReturnRector::class, ChangeArrayPushToArrayAssignRector::class, ChangeGlobalVariablesToPropertiesRector::class, ChangeIfElseValueAssignToEarlyReturnRector::class, @@ -413,10 +408,8 @@ JoinStringConcatRector::class, LogicalToBooleanRector::class, MakeInheritedMethodVisibilitySameAsParentRector::class, - // MixedTypeRector::class, MultipleClassFileToPsr4ClassesRector::class, NarrowUnionTypeDocRector::class, - // NewlineAfterStatementRector::class, NewlineBeforeNewAssignSetRector::class, NewStaticToNewSelfRector::class, NormalizeNamespaceByPSR4ComposerAutoloadRector::class, @@ -432,17 +425,13 @@ PreparedValueToEarlyReturnRector::class, PrivatizeFinalClassMethodRector::class, PrivatizeFinalClassPropertyRector::class, - // PrivatizeLocalGetterToPropertyRector::class, PropertyTypeFromStrictSetterGetterRector::class, - // RecastingRemovalRector::class, RemoveAlwaysElseRector::class, RemoveAlwaysTrueConditionSetInConstructorRector::class, RemoveAndTrueRector::class, - // RemoveConcatAutocastRector::class, RemoveDeadConditionAboveReturnRector::class, RemoveDeadContinueRector::class, RemoveDeadIfForeachForRector::class, - // RemoveDeadInstanceOfRector::class, RemoveDeadLoopRector::class, RemoveDeadReturnRector::class, RemoveDeadStmtRector::class, @@ -479,14 +468,10 @@ RemoveUnusedPromotedPropertyRector::class, RemoveUnusedVariableAssignRector::class, RemoveUnusedVariableInCatchRector::class, - // RemoveUselessParamTagRector::class, RemoveUselessReturnTagRector::class, RemoveUselessVarTagRector::class, RenameForeachValueVariableToMatchExprVariableRector::class, RenameForeachValueVariableToMatchMethodCallReturnTypeRector::class, - // RenamePropertyToMatchTypeRector::class, - // RenameVariableToMatchMethodCallReturnTypeRector::class, - // RenameVariableToMatchNewTypeRector::class, ReplaceMultipleBooleanNotRector::class, ReturnAnnotationIncorrectNullableRector::class, ReturnBinaryAndToEarlyReturnRector::class, @@ -542,7 +527,6 @@ StrEndsWithRector::class, StrictArraySearchRector::class, StringableForToStringRector::class, - // StringClassNameToClassConstantRector::class, StrlenZeroToIdenticalEmptyStringRector::class, StrStartsWithRector::class, StrvalToTypeCastRector::class, @@ -558,7 +542,6 @@ TypedPropertyFromStrictConstructorRector::class, TypedPropertyFromStrictGetterMethodReturnTypeRector::class, TypedPropertyFromStrictSetUpRector::class, - // UnionTypesRector::class, UnnecessaryTernaryExpressionRector::class, UnSpreadOperatorRector::class, UnusedForeachValueToArrayKeysRector::class, From dd30dcc01f444f4c8bf7f221c29a40c53dc6dadb Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 27 Mar 2023 14:37:00 -0500 Subject: [PATCH 241/525] Update .gitattributes --- .gitattributes | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 3a4048b8..ee29bd54 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9,7 +9,6 @@ docs/ export-ignore EXAMPLES.md export-ignore examples/ export-ignore opslevel.yml export-ignore -phpdoc.dist.xml export-ignore phpstan.neon.dist export-ignore phpunit.xml.dist export-ignore psalm.xml.dist export-ignore From fccb5c7b41836c075d45357a1408f6be7cab8433 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 27 Mar 2023 14:37:18 -0500 Subject: [PATCH 242/525] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1e1e2c20..c23d02f8 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ composer.local.json composer.local.json_ .php-cs-fixer.cache composer.local.old +.vscode From 7a46ba93cbe0d37b09f1943d29c1607f63dae1a3 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 27 Mar 2023 15:52:01 -0500 Subject: [PATCH 243/525] Update ServiceProvider.php --- src/Contract/ServiceProvider.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Contract/ServiceProvider.php b/src/Contract/ServiceProvider.php index d73c9a47..c36565ea 100644 --- a/src/Contract/ServiceProvider.php +++ b/src/Contract/ServiceProvider.php @@ -4,8 +4,6 @@ namespace Auth0\Laravel\Contract; -use Illuminate\Contracts\Support\DeferrableProvider; - -interface ServiceProvider extends DeferrableProvider +interface ServiceProvider { } From 59447e8d8e8a3e1f914e4861c154dac985ea34ed Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 27 Mar 2023 16:05:22 -0500 Subject: [PATCH 244/525] Update .gitattributes --- .gitattributes | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/.gitattributes b/.gitattributes index ee29bd54..a4fe7cca 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,19 +1,21 @@ -.editorconfig export-ignore -.gitattributes export-ignore -.github/ export-ignore -.gitignore export-ignore -.semgrepignore export-ignore -.shiprc export-ignore -CHANGELOG.md export-ignore -docs/ export-ignore -EXAMPLES.md export-ignore -examples/ export-ignore -opslevel.yml export-ignore -phpstan.neon.dist export-ignore -phpunit.xml.dist export-ignore -psalm.xml.dist export-ignore -rector.php export-ignore -tests/ export-ignore -UPGRADE.md export-ignore -vendor/ export-ignore -CHANGELOG.ARCHIVE.md export-ignore +.editorconfig export-ignore +.gitattributes export-ignore +.github/ export-ignore +.gitignore export-ignore +.semgrepignore export-ignore +.shiprc export-ignore +CHANGELOG.md export-ignore +docs/ export-ignore +EXAMPLES.md export-ignore +examples/ export-ignore +opslevel.yml export-ignore +phpstan.neon.dist export-ignore +phpunit.xml.dist export-ignore +psalm.xml.dist export-ignore +rector.php export-ignore +tests/ export-ignore +UPGRADE.md export-ignore +vendor/ export-ignore +CHANGELOG.ARCHIVE.md export-ignore +infection.json5.dist export-ignore +.php-cs-fixer.dist.php export-ignore From ac287b9b2705a61d86b8e4f044ab2850786e6b4c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 27 Mar 2023 16:05:37 -0500 Subject: [PATCH 245/525] Rename LICENSE.txt to LICENSE.md for consistency with other SDK repos --- LICENSE.txt => LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename LICENSE.txt => LICENSE.md (93%) diff --git a/LICENSE.txt b/LICENSE.md similarity index 93% rename from LICENSE.txt rename to LICENSE.md index a77a3309..3cd3cbfa 100644 --- a/LICENSE.txt +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2022 Auth0, Inc. (http://auth0.com) +Copyright (c) 2023 Auth0, Inc. (https://auth0.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 735fdfffbeba4071b927263c837d3a3538427a9f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 27 Mar 2023 16:07:04 -0500 Subject: [PATCH 246/525] Update Auth0.php --- src/Auth0.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Auth0.php b/src/Auth0.php index 19effe9c..0887ff87 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -53,14 +53,12 @@ public function getConfiguration(): Configuration * @var array $config */ if (! isset($config['tokenCache']) || ! isset($config['managementTokenCache'])) { - $cache = new LaravelCachePool(); - if (! isset($config['tokenCache'])) { - $config['tokenCache'] = $cache; + $config['tokenCache'] = app('cache.psr6'); } if (! isset($config['managementTokenCache'])) { - $config['managementTokenCache'] = $cache; + $config['managementTokenCache'] = app('cache.psr6'); } } From 419b6e82e24b21c28e4e8ae34302db60143230a5 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 27 Mar 2023 16:08:04 -0500 Subject: [PATCH 247/525] Update Auth0.php --- src/Auth0.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Auth0.php b/src/Auth0.php index 0887ff87..19effe9c 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -53,12 +53,14 @@ public function getConfiguration(): Configuration * @var array $config */ if (! isset($config['tokenCache']) || ! isset($config['managementTokenCache'])) { + $cache = new LaravelCachePool(); + if (! isset($config['tokenCache'])) { - $config['tokenCache'] = app('cache.psr6'); + $config['tokenCache'] = $cache; } if (! isset($config['managementTokenCache'])) { - $config['managementTokenCache'] = app('cache.psr6'); + $config['managementTokenCache'] = $cache; } } From 3dd71d7acbecc15a8fe3992443e6b4ffb75f7ae4 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 3 Apr 2023 01:59:41 -0500 Subject: [PATCH 248/525] Rename `autoLogin` to `legacyGuardUserMethod` and add description. --- config/auth0.php | 6 ++++-- src/Auth/Guard.php | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/config/auth0.php b/config/auth0.php index 79e34fdd..5fc380da 100644 --- a/config/auth0.php +++ b/config/auth0.php @@ -61,7 +61,9 @@ ], 'behavior' => [ - // Defaults to false. If true, the SDK will attempt to automatically log in a user when Guard::user() is called. - 'autoLogin' => Configuration::stringToBoolOrNull(env('AUTH0_BEHAVIOR_AUTO_LOGIN'), false), + // If TRUE, the Guard will follow < 7.5 behavior in which calling Guard::user() will automatically login a user using discovered credentials, if they are not already. + // Note that if this property is missing from the configuration, the SDK will default to true as a fallback for previous behavior. + // You must explicitly set it to FALSE to disable this behavior. + 'legacyGuardUserMethod' => Configuration::stringToBoolOrNull(env('AUTH0_BEHAVIOR_LEGACY_GUARD_USER_METHOD'), false), ] ]; diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 1a54381e..2926fc0a 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -560,14 +560,14 @@ public function setUser( public function user(): ?Authenticatable { - $autoLogin = config('auth0.behavior.autoLogin', true); - $currentUser = $this->getCredential()?->getUser(); + $legacyBehavior = config('auth0.behavior.legacyGuardUserMethod', true); + $currentUser = $this->getCredential()?->getUser(); if (null !== $currentUser) { return $currentUser; } - if (true === $autoLogin) { + if (true === $legacyBehavior) { $token = $this->find(self::SOURCE_TOKEN); if (null !== $token) { From 30bfea85ee852c83ca6fdc7026bcc9f45150357f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 3 Apr 2023 02:00:06 -0500 Subject: [PATCH 249/525] Use PHP SDK ^8.5 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0e4fa8d1..9b95f6cc 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "php": "^8.0", "ext-json": "*", "ext-mbstring": "*", - "auth0/auth0-php": "dev-main", + "auth0/auth0-php": "^8.5", "illuminate/contracts": "^9.0 || ^10.0", "illuminate/http": "^9.0 || ^10.0", "illuminate/support": "^9.0 || ^10.0", From c37c5e1f2b220b2db94bb4d1f2382687df613d3c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 3 Apr 2023 02:00:17 -0500 Subject: [PATCH 250/525] Typo fix in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 48d39659..63eb4f4b 100644 --- a/README.md +++ b/README.md @@ -58,10 +58,10 @@ Note the **Domain**, **Client ID**, and **Client Secret**. These values will be ### Publish SDK configuration -Use Laravels CLI to generate an Auth0 configuration file within your project: +Use Artisan to generate an Auth0 configuration file within your project: ``` -php artisan vendor:publish --tag auth0-config +php artisan vendor:publish --tag=auth0-config ``` A new file will appear within your project, `app/config/auth0.php`. You should avoid making changes to this file directly. From 546823121c443ef5df3cf90a8df49b1e7b4d74da Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 3 Apr 2023 02:20:24 -0500 Subject: [PATCH 251/525] Add SDK 7.3 and 7.4 to tempalte --- .github/ISSUE_TEMPLATE/Bug Report.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index 32252601..c180003c 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -11,6 +11,8 @@ body: label: SDK Version description: What version of our Laravel plugin are you running? (`composer show | grep auth0/login`) options: + - 7.4 + - 7.3 - 7.2 - 7.1 - 7.0 @@ -25,6 +27,7 @@ body: label: PHP Version description: What version of PHP are you running? (`php -v`) options: + - PHP 8.3 - PHP 8.2 - PHP 8.1 - PHP 8.0 From 8264ba6b51dbd52da1594813e841e27381017613 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 3 Apr 2023 02:36:46 -0500 Subject: [PATCH 252/525] Update rep_opened.yml --- .github/workflows/rep_opened.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rep_opened.yml b/.github/workflows/rep_opened.yml index 714d03cc..0d6ec4b3 100644 --- a/.github/workflows/rep_opened.yml +++ b/.github/workflows/rep_opened.yml @@ -4,6 +4,9 @@ on: pull_request_target: types: - opened + - edited + - ready_for_review + - converted_to_draft permissions: issues: write @@ -19,10 +22,14 @@ jobs: with: script: | const pattern = /^(\w*)(?:\(([\w]*)\))?: (.*)$/; - const title = context.payload.pull_request.title - const [type, scope, subject] = title.match(pattern).slice(1); - - console.log(`Type: ${type}`, `Scope: ${scope}`, `Subject: ${subject}`) + const title = context.payload.pull_request.title; + + try { + const [type, scope, subject] = title.match(pattern).slice(1); + console.log(`Type: ${type}`, `Scope: ${scope}`, `Subject: ${subject}`) + } catch (error) { + console.error(error); + } if (type !== undefined) { const labels = { From e57489dfe2a7fd3da20af08e4f90b10be0812c61 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 3 Apr 2023 02:39:36 -0500 Subject: [PATCH 253/525] Update rep_opened.yml --- .github/workflows/rep_opened.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rep_opened.yml b/.github/workflows/rep_opened.yml index 0d6ec4b3..7466d4fc 100644 --- a/.github/workflows/rep_opened.yml +++ b/.github/workflows/rep_opened.yml @@ -28,10 +28,13 @@ jobs: const [type, scope, subject] = title.match(pattern).slice(1); console.log(`Type: ${type}`, `Scope: ${scope}`, `Subject: ${subject}`) } catch (error) { + const type = null; + const scope = null; + const subject = null; console.error(error); } - if (type !== undefined) { + if (type !== undefined && type !== null) { const labels = { 'feat': 'type-improvement', 'refactor': 'type-improvement', From 0b26789e572df14d2a6d049b4ead1716ca8d5091 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 3 Apr 2023 02:41:52 -0500 Subject: [PATCH 254/525] Update rep_opened.yml --- .github/workflows/rep_opened.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rep_opened.yml b/.github/workflows/rep_opened.yml index 7466d4fc..95c4eeea 100644 --- a/.github/workflows/rep_opened.yml +++ b/.github/workflows/rep_opened.yml @@ -24,13 +24,14 @@ jobs: const pattern = /^(\w*)(?:\(([\w]*)\))?: (.*)$/; const title = context.payload.pull_request.title; + let type = null; + let scope = null; + let subject = null; + try { - const [type, scope, subject] = title.match(pattern).slice(1); + [type, scope, subject] = title.match(pattern).slice(1); console.log(`Type: ${type}`, `Scope: ${scope}`, `Subject: ${subject}`) } catch (error) { - const type = null; - const scope = null; - const subject = null; console.error(error); } From 2e5d72dda6dd414b085f5712f095871cc7c6b0ab Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 3 Apr 2023 08:50:11 -0500 Subject: [PATCH 255/525] release: 7.5.0 (#352) --- .github/ISSUE_TEMPLATE/Bug Report.yml | 1 + CHANGELOG.md | 3 +-- src/Auth0.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index c180003c..d0224c18 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -11,6 +11,7 @@ body: label: SDK Version description: What version of our Laravel plugin are you running? (`composer show | grep auth0/login`) options: + - 7.5 - 7.4 - 7.3 - 7.2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 44b33aec..a1eb9d62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,7 @@ ## [Unreleased] -Most of these changes rely on upstream changes in the Auth0-PHP SDK that are waiting for release. -These changes will not function correctly until that release is made. +## [7.5.0](https://github.com/auth0/laravel-auth0/tree/7.5.0) (2023-04-03) **Added** diff --git a/src/Auth0.php b/src/Auth0.php index 19effe9c..3ffee599 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -25,7 +25,7 @@ final class Auth0 implements ServiceContract * * @var string */ - public const VERSION = '7.4.0'; + public const VERSION = '7.5.0'; public function __construct( private ?SDKContract $sdk = null, From 91a2eec0f154232524466522d34d0747799f4c61 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 10:24:45 -0500 Subject: [PATCH 256/525] Update README.md --- README.md | 152 ++++++++++++++++++++++++++---------------------------- 1 file changed, 74 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index 63eb4f4b..a08ebc35 100644 --- a/README.md +++ b/README.md @@ -26,52 +26,70 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. - Laravel 10 (PHP 8.1+) or Laravel 9 (PHP 8.0+) - [Composer](https://getcomposer.org/) -- PHP Extensions: - - [mbstring](https://www.php.net/manual/en/book.mbstring.php) -- Dependencies: - - [PSR-18 HTTP Client implementation](https://github.com/auth0/auth0-PHP/FAQ.md#what-is-psr-18) - - [PSR-17 HTTP Factory implementation](https://github.com/auth0/auth0-PHP/FAQ.md#what-is-psr-17) - - [PSR-7 HTTP Messages implementation](https://github.com/auth0/auth0-PHP/FAQ.md#what-is-psr-7) +- [Auth0 account](https://auth0.com/signup) > Please review our [support policy](#support-policy) for details on our PHP and Laravel version support. -> [Octane support](#octane-support) is experimental and not advisable for use in production at this time. - ### Installation -Ensure you have [the necessary dependencies](#requirements) installed, then add the SDK to your application using [Composer](https://getcomposer.org/): +Open a shell to the root of your Laravel application directory, and import the SDK using [Composer](https://getcomposer.org/): -``` +```bash composer require auth0/login ``` -### Configure Auth0 +Next, generate the `config/auth0.php` configuration file for your application: -Create a **Regular Web Application** in the [Auth0 Dashboard](https://manage.auth0.com/#/applications). Verify that the "Token Endpoint Authentication Method" is set to `POST`. +```bash +php artisan vendor:publish --tag=auth0-config +``` -Next, configure the callback and logout URLs for your application under the "Application URIs" section of the "Settings" page: +### Create an Auth0 Application -- **Allowed Callback URLs**: The URL of your application where Auth0 will redirect to during authentication, e.g., `http://localhost:3000/callback`. -- **Allowed Logout URLs**: The URL of your application where Auth0 will redirect to after logout, e.g., `http://localhost:3000/login`. +First, [install the Auth0 CLI](https://github.com/auth0/auth0-cli#installation) and [authenticate to your tenant](https://github.com/auth0/auth0-cli#authenticating-to-your-tenant). -Note the **Domain**, **Client ID**, and **Client Secret**. These values will be used during configuration later. +Next, create a new Auth0 application using the CLI: -### Publish SDK configuration +```bash +auth0 apps create \ + --name "My Auth0 Laravel App" \ + --type "regular" \ + --auth-method "post" \ + --callbacks "http://localhost:8000/callback" \ + --logout-urls "http://localhost:8000/login" \ + --reveal-secrets \ + --no-input +``` -Use Artisan to generate an Auth0 configuration file within your project: +Make note of your tenant's **Domain** (e.g. `tenant.region.auth0.com`), **Client ID**, and **Client Secret** returned. These will be required later during configuration. -``` -php artisan vendor:publish --tag=auth0-config -``` +### Determine Your Application Type + +This SDK supports two application types: **stateful** and **stateless**. + +- **Stateful** applications use a session to store user information (their state). + - These provide a login/logout experience. + - These are **authenticating** users. + - These often need to know the **identity** of the requestor. + - These are often considered traditional web applications. +- **Stateless** applications authorize requests to routes. + - These use Access Tokens to firewall requests. + - These are **authorizing** requests. + - These are agnostic to the identity of the requestor. + - These are typically considered backend services. + - These are often used to provide data to single-page applications. -A new file will appear within your project, `app/config/auth0.php`. You should avoid making changes to this file directly. +It's important to understand the differences between these two application types, and which one is appropriate for your application. -### Configure `.env` file +> _Note_ +> At this time, the SDK does not support simultaneously using stateless and stateful guards within the same application. If you need to support both, you will need to create two separate application instances. Support for this is planned for a future release. + +### Configure the SDK Open the `.env` file within your application's directory, and add the following lines appropriate for your application type:
- For Stateful Web Applications + Stateful Applications ``` AUTH0_DOMAIN="Your Auth0 domain" @@ -85,7 +103,7 @@ Provide a sufficiently long, random string for your `AUTH0_COOKIE_SECRET` using
- For Stateless Backend Applications + Stateless Services ``` AUTH0_STRATEGY="api" @@ -97,107 +115,85 @@ AUTH0_AUDIENCE="Your Auth0 API identifier"
-### Setup your Laravel application +### Setup Your Application -Integrating the SDK's Guard requires changes to your `config\auth.php` file. +Open your `app/config/auth.php` file. -To begin, find the `defaults` section. Set the default `guard` to `auth0`, like this: - -```php -// 📂 config/auth.php -'defaults' => [ - 'guard' => 'auth0', - // 📝 Leave any other settings in this section alone. -], -``` - -Next, find the `guards` section, and add `auth0` there: +Find the `guards` section, and add a new guard using the `auth0.guard` driver: ```php // 👆 Continued from above, in config/auth.php 'guards' => [ // 📝 Any additional guards you use should stay here, too. - 'auth0' => [ - 'driver' => 'auth0', - 'provider' => 'auth0', + 'yourGuard' => [ + 'driver' => 'auth0.guard', + 'provider' => 'yourProvider', ], ], ``` -Next, find the `providers` section, and add `auth0` there as well: +Next, find the `providers` section, and add an entry matching the name of the `provider` you configured in the guard, using `auth0.provider` as the `driver`: ```php // 👆 Continued from above, in config/auth.php 'providers' => [ // 📝 Any additional providers you use should stay here, too. - 'auth0' => [ - 'driver' => 'auth0', + 'yourProvider' => [ + 'driver' => 'auth0.provider', 'repository' => \Auth0\Laravel\Auth\User\Repository::class ], ], ``` -Although it is enabled by default, now is a good time to ensure the `StartSession` middleware is enabled in your `app/Http/Kernel.php` file: - -```php -protected $middlewareGroups = [ - 'web' => [ - // ... - \Illuminate\Session\Middleware\StartSession::class, - // ... - ], -]; -``` +## Authentication -## Add login to stateful web applications +For stateful applications that want to provide a login/logout experience, the SDK provides a series of routing controllers to handle the essential elements of the authentication flow with Auth0. -For regular web applications that provide login and logout, we provide prebuilt route controllers to add to your `app/routes/web.php` file that will automatically handle your application's authentication flow with Auth0 for you: +You should add these controllers to the route most appropriate for your application. For example, `app/routes/web.php` is a common location for most applications. ```php -Route::get('/login', \Auth0\Laravel\Http\Controller\Stateful\Login::class)->name('login'); -Route::get('/logout', \Auth0\Laravel\Http\Controller\Stateful\Logout::class)->name('logout'); -Route::get('/auth0/callback', \Auth0\Laravel\Http\Controller\Stateful\Callback::class)->name('auth0.callback'); +use Auth0\Laravel\Http\Controller\Stateful\{Login, Logout, Callback}; + +Route::get('/login', Login::class)->name('login'); +Route::get('/logout', Logout::class)->name('logout'); +Route::get('/callback', Callback::class)->name('callback'); ``` -## Protect routes with middleware +Wherever you decide to add these routes, please ensure requests handled by them are managed through a configured Auth0 guard. -This SDK includes middleware to simplify either authenticating (regular web applications) or authorizing (backend api applications) your Laravel routes, depending on your application type. +## Routing Protection -
-Stateful Web Applications +The SDK provides a series of routing middleware to help you secure your application's routes. Any routes you wish to protect should be wrapped in the appropriate middleware. -These are for traditional applications that handle logging in and out. +
+Stateful Applications -The `auth0.authenticate` middleware will check for an available user session and redirect any requests without one to the login route: +**`auth0.authenticate` requires a user to be logged in to access a route.** Other requests will be redirected to the `login` route. ```php Route::get('/required', function () { - return view('example.user.template'); + return view(/* Authenticated */); })->middleware(['auth0.authenticate']); ``` -The `auth0.authenticate.optional` middleware will check for an available user session, but won't reject or redirect requests without one, allowing you to treat such requests as "guest" requests: +**`auth0.authenticate.optional` allows anyone to access a route.** It will check if a user is logged in, and if so, will make sure `Auth::user()` is available to the route. This is useful when you wish to display different content to logged-in users and guests. ```php Route::get('/', function () { if (Auth::check()) { - return view('example.user.template'); + return view(/* Authenticated */) } - return view('example.guest.template'); + return view(/* Guest */) })->middleware(['auth0.authenticate.optional']); ``` -> Note that the `example.user.template` and `example.guest.templates` views are just examples and are not part of the SDK; replace these as appropriate for your application. -
-Stateless Backend Applications - -These are applications that accept an Access Token through the 'Authorization' header of a request. +Stateless Services -The `auth0.authorize` middleware will resolve an Access Token and reject any request with an invalid token. +**`auth0.authorize` requires a valid access token for a request.** Otherwise, it will return a `401 Unauthorized` response. ```php Route::get('/api/private', function () { @@ -209,7 +205,7 @@ Route::get('/api/private', function () { })->middleware(['auth0.authorize']); ``` -The `auth0.authorize` middleware also allows you to optionally filter requests for access tokens based on scopes: +**`auth0.authorize` can further require access tokens to have a specific scope.** If the scope is not present for the token, it will return a `403 Forbidden` response. ```php Route::get('/api/private-scoped', function () { @@ -221,7 +217,7 @@ Route::get('/api/private-scoped', function () { })->middleware(['auth0.authorize:read:messages']); ``` -The `auth0.authorize.optional` middleware will resolve an available Access Token, but won't block requests without one. This is useful when you want to treat tokenless requests as "guests": +**`auth0.authorize.optional` allows anyone to access a route.** It will check if a valid access token is present, and if so, will make sure `Auth::user()` is available to the route. This is useful when you wish to return different responses to authenticated and unauthenticated requests. ```php Route::get('/api/public', function () { From 424d540575fc6f0c6d54c07b8a3b727abcf62e7c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 10:33:59 -0500 Subject: [PATCH 257/525] Update README.md --- README.md | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a08ebc35..ebf071d8 100644 --- a/README.md +++ b/README.md @@ -119,37 +119,34 @@ AUTH0_AUDIENCE="Your Auth0 API identifier" Open your `app/config/auth.php` file. -Find the `guards` section, and add a new guard using the `auth0.guard` driver: +Find the `guards` section, and add a new guard to the `guards` array that uses the `auth0.guard` driver. ```php -// 👆 Continued from above, in config/auth.php 'guards' => [ - // 📝 Any additional guards you use should stay here, too. - 'yourGuard' => [ + 'someGuardName' => [ 'driver' => 'auth0.guard', - 'provider' => 'yourProvider', + 'provider' => 'someProviderName', ], ], ``` -Next, find the `providers` section, and add an entry matching the name of the `provider` you configured in the guard, using `auth0.provider` as the `driver`: +Find the `providers` section, and add a new provider to the `providers` array that uses `auth0.provider` as the driver. ```php -// 👆 Continued from above, in config/auth.php -'providers' => [ - // 📝 Any additional providers you use should stay here, too. - 'yourProvider' => [ + 'someProviderName' => [ 'driver' => 'auth0.provider', 'repository' => \Auth0\Laravel\Auth\User\Repository::class ], ], ``` +`someGuardName` and `someProviderName` can be any names you choose, but please ensure the `provider` name matches the `provider` value in the guard definition. + ## Authentication -For stateful applications that want to provide a login/logout experience, the SDK provides a series of routing controllers to handle the essential elements of the authentication flow with Auth0. +**For stateful applications** that use a login/logout experience, the SDK provides a series of routing controllers to handle the authentication flow. -You should add these controllers to the route most appropriate for your application. For example, `app/routes/web.php` is a common location for most applications. +Add these routes where most appropriate for your configuration; `app/routes/web.php` is a common location for most applications. ```php use Auth0\Laravel\Http\Controller\Stateful\{Login, Logout, Callback}; @@ -159,7 +156,7 @@ Route::get('/logout', Logout::class)->name('logout'); Route::get('/callback', Callback::class)->name('callback'); ``` -Wherever you decide to add these routes, please ensure requests handled by them are managed through a configured Auth0 guard. +Please ensure requests for these routes are managed by an Auth0 guard configured by your application. ## Routing Protection From 1c7fdad9a6da80ba540b0a97d9d73772018fe562 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 10:39:41 -0500 Subject: [PATCH 258/525] Update CHANGELOG.md --- CHANGELOG.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1eb9d62..a908e1b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ## [7.5.0](https://github.com/auth0/laravel-auth0/tree/7.5.0) (2023-04-03) +This release includes support for Laravel 10, and major improvements to the internal state handling mechanisms of the SDK. + **Added** - Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) @@ -15,7 +17,6 @@ The following changes have no effect on the external API of this package, but ma - `Guard` will now more reliably detect changes in the underlying Auth0-PHP SDK session state. - `Guard` will now more reliably sync changes back to the underlying Auth0-PHP SDK session state. -- `Guard` now inherits the `DeferrableProvider` interface to better support Laravel's deferred provider loading. - `StateInstance` concept has been replaced by new `Credentials` entity. - `Guard` updated to use new `Credentials` entity as primary internal storage for user data. - `Auth0\Laravel\Traits\ActingAsAuth0User` was updated to use new`Credentials` entity. @@ -25,13 +26,23 @@ The following changes have no effect on the external API of this package, but ma **Fixed** - A 'Session store not set on request' error could occur when downstream applications implemented unit testing that use the Guard. This should be resolved now. -- An issue wherein the `Guard` would not always honor the `provider` configuration value in `config/auth.php`. +- `Guard` would not always honor the `provider` configuration value in `config/auth.php`. - `Guard` is no longer defined as a Singleton to better support applications that need multi-guard configurations. **Maintenance** -- Reworked test suite to use PEST framework. -- Restored test coverage to 100%. +- Upgraded test suite to use PEST 2.0 framework. +- Updated test coverage to 100%. + +**Important Notes** + +**1. Changes to `user()` behavior** +This release includes a significant behavior change around the `user()` method of the Guard. Previously, by simply invoking the method, the SDK would search for any available credential (access token, device session, etc.) and automatically assign the user within the Guard. The HTTP middleware have been upgraded to handle the user assignment step, and `user()` now only returns the current state of user assignment without altering it. + +A new property has been added to the `config/auth0.php` configuration file: `behavior`. This is an array. At this time, there is a single option: `legacyGuardUserMethod`, a bool. If this value is set to true, or if the key is missing, the previously expected behavior will be applied, and `user()` will behave as it did before this release. The property defaults to `false`. + +**2. Changes to Guard and Provider driver aliases** +We identified an issue with using identical alias naming for both the Guard and Provider singletons under Laravel 10, which has required us to rename these aliases. As previous guidance had bee to instantiate these using their class names, this should not be a breaking change in most cases, but if you had used `auth0` as the driver name for either the Guard or the Provider entries, please note that these have changed. Please use `auth0.guard` for the Guard driver, and `auth0.provider` for the Provider driver. This is a regrettable change, but was necessary for adequate Laravel 10 support. Thanks to our contributors for this release: [taida957789](https://github.com/taida957789) From bcb73dcc2adb105eb2aee79aceca1a63a4b5d296 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 10:41:29 -0500 Subject: [PATCH 259/525] Update CHANGELOG.md --- CHANGELOG.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a908e1b1..4cd8140e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,31 +8,31 @@ This release includes support for Laravel 10, and major improvements to the inte **Added** -- Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) -- New `Auth0\Laravel\Traits\Imposter` trait to allow for easier testing. [Example usage](./tests/Unit/Traits/ImpersonateTest.php) -- New Exception types have been added for more precise error catching. +— Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) +— New `Auth0\Laravel\Traits\Imposter` trait to allow for easier testing. [Example usage](./tests/Unit/Traits/ImpersonateTest.php) +— New Exception types have been added for more precise error catching. **Changed** The following changes have no effect on the external API of this package, but may affect internal usage. -- `Guard` will now more reliably detect changes in the underlying Auth0-PHP SDK session state. -- `Guard` will now more reliably sync changes back to the underlying Auth0-PHP SDK session state. -- `StateInstance` concept has been replaced by new `Credentials` entity. -- `Guard` updated to use new `Credentials` entity as primary internal storage for user data. -- `Auth0\Laravel\Traits\ActingAsAuth0User` was updated to use new`Credentials` entity. -- The HTTP middleware have been refactored to more clearly differentiate between token and session based identities. -- The `authenticate`, `authenticate.optional` and `authorize.optional` HTTP middleware now support scope filtering, as `authorize` already did. +— `Guard` will now more reliably detect changes in the underlying Auth0-PHP SDK session state. +— `Guard` will now more reliably sync changes back to the underlying Auth0-PHP SDK session state. +— `StateInstance` concept has been replaced by new `Credentials` entity. +— `Guard` updated to use new `Credentials` entity as primary internal storage for user data. +— `Auth0\Laravel\Traits\ActingAsAuth0User` was updated to use new`Credentials` entity. +— The HTTP middleware have been refactored to more clearly differentiate between token and session based identities. +— The `authenticate`, `authenticate.optional` and `authorize.optional` HTTP middleware now support scope filtering, as `authorize` already did. **Fixed** -- A 'Session store not set on request' error could occur when downstream applications implemented unit testing that use the Guard. This should be resolved now. -- `Guard` would not always honor the `provider` configuration value in `config/auth.php`. -- `Guard` is no longer defined as a Singleton to better support applications that need multi-guard configurations. +— A 'Session store not set on request' error could occur when downstream applications implemented unit testing that use the Guard. This should be resolved now. +— `Guard` would not always honor the `provider` configuration value in `config/auth.php`. +— `Guard` is no longer defined as a Singleton to better support applications that need multi-guard configurations. **Maintenance** -- Upgraded test suite to use PEST 2.0 framework. -- Updated test coverage to 100%. +— Upgraded test suite to use PEST 2.0 framework. +— Updated test coverage to 100%. **Important Notes** @@ -42,7 +42,7 @@ This release includes a significant behavior change around the `user()` method o A new property has been added to the `config/auth0.php` configuration file: `behavior`. This is an array. At this time, there is a single option: `legacyGuardUserMethod`, a bool. If this value is set to true, or if the key is missing, the previously expected behavior will be applied, and `user()` will behave as it did before this release. The property defaults to `false`. **2. Changes to Guard and Provider driver aliases** -We identified an issue with using identical alias naming for both the Guard and Provider singletons under Laravel 10, which has required us to rename these aliases. As previous guidance had bee to instantiate these using their class names, this should not be a breaking change in most cases, but if you had used `auth0` as the driver name for either the Guard or the Provider entries, please note that these have changed. Please use `auth0.guard` for the Guard driver, and `auth0.provider` for the Provider driver. This is a regrettable change, but was necessary for adequate Laravel 10 support. +We identified an issue with using identical alias naming for both the Guard and Provider singletons under Laravel 10, which has required us to rename these aliases. As previous guidance had been to instantiate these using their class names, this should not be a breaking change in most cases. However, if you had used `auth0` as the name for either the Guard or the Provider drivers, kindly note that these have changed. Please use `auth0.guard` for the Guard driver, and `auth0.provider` for the Provider driver. This is a regrettable change, but was necessary for adequate Laravel 10 support. Thanks to our contributors for this release: [taida957789](https://github.com/taida957789) From 421ef0ec382c02f62730baf92839a97d4dc27651 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 10:43:42 -0500 Subject: [PATCH 260/525] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ebf071d8..48c82a82 100644 --- a/README.md +++ b/README.md @@ -81,8 +81,8 @@ This SDK supports two application types: **stateful** and **stateless**. It's important to understand the differences between these two application types, and which one is appropriate for your application. -> _Note_ -> At this time, the SDK does not support simultaneously using stateless and stateful guards within the same application. If you need to support both, you will need to create two separate application instances. Support for this is planned for a future release. +> **Note** +> The SDK does not support simultaneously using stateless and stateful guards within the same application at this time. If you need to support both, you will need to create two separate application instances. Support for this is planned for a future release. ### Configure the SDK From 0c30e8c5a0c49729b086090b4e8062946b737ffe Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 10:44:56 -0500 Subject: [PATCH 261/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 48c82a82..ba0d2dbe 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ Find the `providers` section, and add a new provider to the `providers` array th ], ``` -`someGuardName` and `someProviderName` can be any names you choose, but please ensure the `provider` name matches the `provider` value in the guard definition. +`someGuardName` and `someProviderName` can be any names you choose, but please ensure the provider's name (in this case, `someProviderName`) matches the `provider` value in the guard definition. ## Authentication From 3df52a1ea0638b66c4f25908cdd575560c799f57 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 10:46:05 -0500 Subject: [PATCH 262/525] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ba0d2dbe..c3d0fbd7 100644 --- a/README.md +++ b/README.md @@ -142,9 +142,9 @@ Find the `providers` section, and add a new provider to the `providers` array th `someGuardName` and `someProviderName` can be any names you choose, but please ensure the provider's name (in this case, `someProviderName`) matches the `provider` value in the guard definition. -## Authentication +## Adding Login -**For stateful applications** that use a login/logout experience, the SDK provides a series of routing controllers to handle the authentication flow. +For stateful applications that use a login/logout experience, the SDK provides routing controllers that handle the authentication flow for your application. Add these routes where most appropriate for your configuration; `app/routes/web.php` is a common location for most applications. From cd942f283a34b4d363d982db0aff8c023e5aabcc Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 10:47:25 -0500 Subject: [PATCH 263/525] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c3d0fbd7..1bf00a1f 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Next, generate the `config/auth0.php` configuration file for your application: php artisan vendor:publish --tag=auth0-config ``` -### Create an Auth0 Application +### Creating an Auth0 Application First, [install the Auth0 CLI](https://github.com/auth0/auth0-cli#installation) and [authenticate to your tenant](https://github.com/auth0/auth0-cli#authenticating-to-your-tenant). @@ -63,7 +63,7 @@ auth0 apps create \ Make note of your tenant's **Domain** (e.g. `tenant.region.auth0.com`), **Client ID**, and **Client Secret** returned. These will be required later during configuration. -### Determine Your Application Type +### Determining Your Application Type This SDK supports two application types: **stateful** and **stateless**. @@ -84,7 +84,7 @@ It's important to understand the differences between these two application types > **Note** > The SDK does not support simultaneously using stateless and stateful guards within the same application at this time. If you need to support both, you will need to create two separate application instances. Support for this is planned for a future release. -### Configure the SDK +### Configuring the SDK Open the `.env` file within your application's directory, and add the following lines appropriate for your application type: @@ -158,7 +158,7 @@ Route::get('/callback', Callback::class)->name('callback'); Please ensure requests for these routes are managed by an Auth0 guard configured by your application. -## Routing Protection +## Protecting Routes The SDK provides a series of routing middleware to help you secure your application's routes. Any routes you wish to protect should be wrapped in the appropriate middleware. From c8c50f2a1baaee57e904b144fd509465e33d27bd Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 10:48:06 -0500 Subject: [PATCH 264/525] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1bf00a1f..8ee74c99 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ Find the `providers` section, and add a new provider to the `providers` array th `someGuardName` and `someProviderName` can be any names you choose, but please ensure the provider's name (in this case, `someProviderName`) matches the `provider` value in the guard definition. -## Adding Login +### Adding Login For stateful applications that use a login/logout experience, the SDK provides routing controllers that handle the authentication flow for your application. @@ -158,7 +158,7 @@ Route::get('/callback', Callback::class)->name('callback'); Please ensure requests for these routes are managed by an Auth0 guard configured by your application. -## Protecting Routes +### Protecting Routes The SDK provides a series of routing middleware to help you secure your application's routes. Any routes you wish to protect should be wrapped in the appropriate middleware. From f9dc1354aff7be5402a132c6519d840841a510d1 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 10:49:08 -0500 Subject: [PATCH 265/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ee74c99..ca32d3d6 100644 --- a/README.md +++ b/README.md @@ -246,7 +246,7 @@ We drop support for Laravel and PHP versions when they reach end-of-life and cea Octane compatibility is currently considered experimental and unsupported. -Although we are working toward ensuring the SDK is fully compatible with this feature, we do not recommend using this with our SDK in production until we have full confidence and announced support. Due to the aggressive changes Octane makes to Laravel's core behavior, there is an opportunity for problems we haven't fully identified or resolved yet. +Although we are working toward ensuring the SDK is fully compatible with this feature, we do not recommend using this with our SDK in production until we have full confidence and announced support. Due to the caching behavior of Octane, there is an opportunity for problems we have not fully identified or resolved yet. Feedback and bug fix contributions are greatly appreciated as we work toward full. Octane support. From 42601d878c9248cef3a708488d8a0858886f507a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 10:49:31 -0500 Subject: [PATCH 266/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca32d3d6..199f0604 100644 --- a/README.md +++ b/README.md @@ -248,7 +248,7 @@ Octane compatibility is currently considered experimental and unsupported. Although we are working toward ensuring the SDK is fully compatible with this feature, we do not recommend using this with our SDK in production until we have full confidence and announced support. Due to the caching behavior of Octane, there is an opportunity for problems we have not fully identified or resolved yet. -Feedback and bug fix contributions are greatly appreciated as we work toward full. Octane support. +Feedback and bug-fix contributions are greatly appreciated as we work toward full support. ## Feedback From 2c91892fa81a91c9d1769bbd27d5c5ca3b13d694 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 10:51:56 -0500 Subject: [PATCH 267/525] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 199f0604..208008f2 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,9 @@ This SDK supports two application types: **stateful** and **stateless**. - These are typically considered backend services. - These are often used to provide data to single-page applications. -It's important to understand the differences between these two application types, and which one is appropriate for your application. +It's important to understand the differences between these two application types, and which one is appropriate for your use case. + +As we continue, we'll use these terms to help guide you to the correct configuration paths for your application type. > **Note** > The SDK does not support simultaneously using stateless and stateful guards within the same application at this time. If you need to support both, you will need to create two separate application instances. Support for this is planned for a future release. From c1016754d979aab405bb9bbb0a847e465a32fb42 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 10:53:57 -0500 Subject: [PATCH 268/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 208008f2..4efb61cc 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ AUTH0_AUDIENCE="Your Auth0 API identifier"
-### Setup Your Application +### Configuring Your Application Open your `app/config/auth.php` file. From 11d3ca9a2bbdafe34ba65feffbca4fd27a713b3a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 10:59:16 -0500 Subject: [PATCH 269/525] Update README.md --- README.md | 55 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 4efb61cc..41fde7a3 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. - [Composer](https://getcomposer.org/) - [Auth0 account](https://auth0.com/signup) +We will be using the [Auth0 CLI](https://github.com/auth0/auth0-cli) in our examples to expedite getting started If you're planning on following along, you should have the CLI [installed](https://github.com/auth0/auth0-cli#installation) and [authenticated](https://github.com/auth0/auth0-cli#authenticating-to-your-tenant). + > Please review our [support policy](#support-policy) for details on our PHP and Laravel version support. ### Installation @@ -44,6 +46,27 @@ Next, generate the `config/auth0.php` configuration file for your application: php artisan vendor:publish --tag=auth0-config ``` +### Determine Your Application Type + +Before we begin configuring your application, it's important to understand the difference between "stateful" and "stateless" applications, and which one is appropriate for your use case. + +- **Stateful** applications use a session to store user information (their state). + - These provide a login/logout experience. + - These are **authenticating** users. + - These often need to know the **identity** of the requestor. + - These are often considered traditional web applications. +- **Stateless** applications authorize requests to routes. + - These use Access Tokens to firewall requests. + - These are **authorizing** requests. + - These are agnostic to the identity of the requestor. + - These are typically considered backend services. + - These are often used to provide data to single-page applications. + +As we continue, we'll use these terms to help guide you to the correct configuration paths for your application type. + +> **Note** +> The SDK does not support simultaneously using stateless and stateful guards within the same application at this time. If you need to support both, you will need to create two separate application instances. Support for this is planned for a future release. + ### Creating an Auth0 Application First, [install the Auth0 CLI](https://github.com/auth0/auth0-cli#installation) and [authenticate to your tenant](https://github.com/auth0/auth0-cli#authenticating-to-your-tenant). @@ -63,28 +86,24 @@ auth0 apps create \ Make note of your tenant's **Domain** (e.g. `tenant.region.auth0.com`), **Client ID**, and **Client Secret** returned. These will be required later during configuration. -### Determining Your Application Type - -This SDK supports two application types: **stateful** and **stateless**. +### Optional: Creating an Auth0 API -- **Stateful** applications use a session to store user information (their state). - - These provide a login/logout experience. - - These are **authenticating** users. - - These often need to know the **identity** of the requestor. - - These are often considered traditional web applications. -- **Stateless** applications authorize requests to routes. - - These use Access Tokens to firewall requests. - - These are **authorizing** requests. - - These are agnostic to the identity of the requestor. - - These are typically considered backend services. - - These are often used to provide data to single-page applications. +First, [install the Auth0 CLI](https://github.com/auth0/auth0-cli#installation) and [authenticate to your tenant](https://github.com/auth0/auth0-cli#authenticating-to-your-tenant). -It's important to understand the differences between these two application types, and which one is appropriate for your use case. +Next, create a new Auth0 application using the CLI: -As we continue, we'll use these terms to help guide you to the correct configuration paths for your application type. +```bash +auth0 apps create \ + --name "My Auth0 Laravel App" \ + --type "regular" \ + --auth-method "post" \ + --callbacks "http://localhost:8000/callback" \ + --logout-urls "http://localhost:8000/login" \ + --reveal-secrets \ + --no-input +``` -> **Note** -> The SDK does not support simultaneously using stateless and stateful guards within the same application at this time. If you need to support both, you will need to create two separate application instances. Support for this is planned for a future release. +Make note of your tenant's **Domain** (e.g. `tenant.region.auth0.com`), **Client ID**, and **Client Secret** returned. These will be required later during configuration. ### Configuring the SDK From 279ae1c80e99016b64ddca097d4f4ac7120cd3e4 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 11:13:50 -0500 Subject: [PATCH 270/525] Update README.md --- README.md | 91 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 41fde7a3..31af93c7 100644 --- a/README.md +++ b/README.md @@ -69,13 +69,11 @@ As we continue, we'll use these terms to help guide you to the correct configura ### Creating an Auth0 Application -First, [install the Auth0 CLI](https://github.com/auth0/auth0-cli#installation) and [authenticate to your tenant](https://github.com/auth0/auth0-cli#authenticating-to-your-tenant). - -Next, create a new Auth0 application using the CLI: +Create a new Auth0 application using [the Auth0 CLI](https://github.com/auth0/): ```bash auth0 apps create \ - --name "My Auth0 Laravel App" \ + --name "My Laravel Application" \ --type "regular" \ --auth-method "post" \ --callbacks "http://localhost:8000/callback" \ @@ -84,57 +82,70 @@ auth0 apps create \ --no-input ``` -Make note of your tenant's **Domain** (e.g. `tenant.region.auth0.com`), **Client ID**, and **Client Secret** returned. These will be required later during configuration. +You will receive a response with details about your new application. -### Optional: Creating an Auth0 API +Please make a note of your tenant's **domain** (e.g. `tenant.region.auth0.com`), **client ID**, and **client secret**. These will be required later during configuration. -First, [install the Auth0 CLI](https://github.com/auth0/auth0-cli#installation) and [authenticate to your tenant](https://github.com/auth0/auth0-cli#authenticating-to-your-tenant). +### Creating an Auth0 API -Next, create a new Auth0 application using the CLI: +**This is only required if you are building a stateless application.** You can create a new Auth0 API using [the Auth0 CLI](https://github.com/auth0/): ```bash -auth0 apps create \ - --name "My Auth0 Laravel App" \ - --type "regular" \ - --auth-method "post" \ - --callbacks "http://localhost:8000/callback" \ - --logout-urls "http://localhost:8000/login" \ - --reveal-secrets \ +auth0 apis create \ + --name "My Laravel Application's API" \ + --identifier "https://github.com/auth0/laravel-auth0" \ + --offline-access \ --no-input ``` -Make note of your tenant's **Domain** (e.g. `tenant.region.auth0.com`), **Client ID**, and **Client Secret** returned. These will be required later during configuration. +You will receive a response with details about your new API. + +You can choose any `--name` and `--identifier` values you like. The `--identifier` value must be a valid URL, but it does not need to be publicly accessible. The identifier value cannot be changed once it is set. + +Note that the identifier value will be used as the audience claim in your Access Tokens, so it is important to choose a value that will not conflict with other APIs you may be using. + +The identifier value will used to configure the `audience` parameter in your application's configuration later. ### Configuring the SDK -Open the `.env` file within your application's directory, and add the following lines appropriate for your application type: +Open the `.env` file within your application's directory, append the lines below as identified for your application type to that file, and fill in the values as appropriate: -
- Stateful Applications +#### Stateful Applications -``` -AUTH0_DOMAIN="Your Auth0 domain" -AUTH0_CLIENT_ID="Your Auth0 application client ID" -AUTH0_CLIENT_SECRET="Your Auth0 application client secret" -AUTH0_COOKIE_SECRET="A randomly generated string" +```ini +# This should be the `domain` value from your Auth0 application. +AUTH0_DOMAIN= + +# This should be the `client_id` value from your Auth0 application. +AUTH0_CLIENT_ID= + +# This should be the `client_secret` value from your Auth0 application. +AUTH0_CLIENT_SECRET= + +# This should be a sufficiently long, random string. +AUTH0_COOKIE_SECRET= ``` -Provide a sufficiently long, random string for your `AUTH0_COOKIE_SECRET` using `openssl rand -hex 32`. +You can use `openssl rand -hex 32` to generate an adequate string for the cookie secret. -
+#### Stateless Services -
- Stateless Services +```ini +# This should be left as "api". +AUTH0_STRATEGY=api -``` -AUTH0_STRATEGY="api" -AUTH0_DOMAIN="Your Auth0 domain" -AUTH0_CLIENT_ID="Your Auth0 application client ID" -AUTH0_CLIENT_SECRET="Your Auth0 application client secret" -AUTH0_AUDIENCE="Your Auth0 API identifier" -``` +# This should be the `domain` value from your Auth0 application. +AUTH0_DOMAIN= -
+# This should be the `client_id` value from your Auth0 application. +AUTH0_CLIENT_ID= + +# This should be the `client_secret` value from your Auth0 application. +AUTH0_CLIENT_SECRET= + +# This should be the `identifier` value from your Auth0 API. +AUTH0_AUDIENCE= +``` ### Configuring Your Application @@ -183,8 +194,7 @@ Please ensure requests for these routes are managed by an Auth0 guard configured The SDK provides a series of routing middleware to help you secure your application's routes. Any routes you wish to protect should be wrapped in the appropriate middleware. -
-Stateful Applications +#### Stateful Applications **`auth0.authenticate` requires a user to be logged in to access a route.** Other requests will be redirected to the `login` route. @@ -206,10 +216,7 @@ Route::get('/', function () { })->middleware(['auth0.authenticate.optional']); ``` -
- -
-Stateless Services +#### Stateless Services **`auth0.authorize` requires a valid access token for a request.** Otherwise, it will return a `401 Unauthorized` response. From 978805ef322fd9dc4601f5ac147adbd60596d03a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 11:19:21 -0500 Subject: [PATCH 271/525] Update README.md --- README.md | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 31af93c7..57c979bb 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. - [Composer](https://getcomposer.org/) - [Auth0 account](https://auth0.com/signup) -We will be using the [Auth0 CLI](https://github.com/auth0/auth0-cli) in our examples to expedite getting started If you're planning on following along, you should have the CLI [installed](https://github.com/auth0/auth0-cli#installation) and [authenticated](https://github.com/auth0/auth0-cli#authenticating-to-your-tenant). +Our examples use the [Auth0 CLI](https://github.com/auth0/auth0-cli) to help get you kickstarted quickly. You should have the CLI [installed](https://github.com/auth0/auth0-cli#installation) and [authenticated](https://github.com/auth0/auth0-cli#authenticating-to-your-tenant). > Please review our [support policy](#support-policy) for details on our PHP and Laravel version support. @@ -88,7 +88,7 @@ Please make a note of your tenant's **domain** (e.g. `tenant.region.auth0.com`), ### Creating an Auth0 API -**This is only required if you are building a stateless application.** You can create a new Auth0 API using [the Auth0 CLI](https://github.com/auth0/): +You can create a new Auth0 API using [the Auth0 CLI](https://github.com/auth0/): ```bash auth0 apis create \ @@ -108,9 +108,7 @@ The identifier value will used to configure the `audience` parameter in your app ### Configuring the SDK -Open the `.env` file within your application's directory, append the lines below as identified for your application type to that file, and fill in the values as appropriate: - -#### Stateful Applications +Open the `.env` file within your application's directory, append the lines below, and fill in the values: ```ini # This should be the `domain` value from your Auth0 application. @@ -124,27 +122,17 @@ AUTH0_CLIENT_SECRET= # This should be a sufficiently long, random string. AUTH0_COOKIE_SECRET= + +# This should be the `identifier` value from your Auth0 API. +AUTH0_AUDIENCE= ``` You can use `openssl rand -hex 32` to generate an adequate string for the cookie secret. -#### Stateless Services +If you are building a stateless application, you should also configure the `AUTH0_STRATEGY` environment variable as `api`: ```ini -# This should be left as "api". AUTH0_STRATEGY=api - -# This should be the `domain` value from your Auth0 application. -AUTH0_DOMAIN= - -# This should be the `client_id` value from your Auth0 application. -AUTH0_CLIENT_ID= - -# This should be the `client_secret` value from your Auth0 application. -AUTH0_CLIENT_SECRET= - -# This should be the `identifier` value from your Auth0 API. -AUTH0_AUDIENCE= ``` ### Configuring Your Application From 61496556497d3ebc24264725318411fb4f34d409 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 11:21:56 -0500 Subject: [PATCH 272/525] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 57c979bb..3f661521 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Our examples use the [Auth0 CLI](https://github.com/auth0/auth0-cli) to help get ### Installation -Open a shell to the root of your Laravel application directory, and import the SDK using [Composer](https://getcomposer.org/): +Open a shell to the root of your Laravel application's root directory, and import the SDK using [Composer](https://getcomposer.org/): ```bash composer require auth0/login @@ -108,7 +108,7 @@ The identifier value will used to configure the `audience` parameter in your app ### Configuring the SDK -Open the `.env` file within your application's directory, append the lines below, and fill in the values: +Open the `.env` file within your Laravel application's root directory, append the lines below, and fill in the values: ```ini # This should be the `domain` value from your Auth0 application. From 6b6f125cea1655640076e01b531e7d5fea39c848 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 11:24:08 -0500 Subject: [PATCH 273/525] Update README.md --- README.md | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 3f661521..7e5899d8 100644 --- a/README.md +++ b/README.md @@ -108,28 +108,27 @@ The identifier value will used to configure the `audience` parameter in your app ### Configuring the SDK -Open the `.env` file within your Laravel application's root directory, append the lines below, and fill in the values: +Open the `.env` file within your Laravel application's root directory, append the lines below to it, and fill in the missing values: ```ini -# This should be the `domain` value from your Auth0 application. +# Use the `domain` you noted earlier during application creation. AUTH0_DOMAIN= -# This should be the `client_id` value from your Auth0 application. +# Use the `client id` you noted earlier during application creation. AUTH0_CLIENT_ID= -# This should be the `client_secret` value from your Auth0 application. +# Use the `client_secret id` you noted earlier during application creation. AUTH0_CLIENT_SECRET= -# This should be a sufficiently long, random string. -AUTH0_COOKIE_SECRET= - -# This should be the `identifier` value from your Auth0 API. +# Use the `identifier id` you noted earlier during API creation. AUTH0_AUDIENCE= -``` -You can use `openssl rand -hex 32` to generate an adequate string for the cookie secret. +# This should be any sufficiently long, random string. +# You can use `openssl rand -hex 32` to generate an adequate string. +AUTH0_COOKIE_SECRET= +``` -If you are building a stateless application, you should also configure the `AUTH0_STRATEGY` environment variable as `api`: +If you are building a stateless application, you should also configure the `AUTH0_STRATEGY` environment variable: ```ini AUTH0_STRATEGY=api @@ -137,7 +136,7 @@ AUTH0_STRATEGY=api ### Configuring Your Application -Open your `app/config/auth.php` file. +Open your `config/auth.php` file. Find the `guards` section, and add a new guard to the `guards` array that uses the `auth0.guard` driver. @@ -166,7 +165,7 @@ Find the `providers` section, and add a new provider to the `providers` array th For stateful applications that use a login/logout experience, the SDK provides routing controllers that handle the authentication flow for your application. -Add these routes where most appropriate for your configuration; `app/routes/web.php` is a common location for most applications. +Add these routes where most appropriate for your configuration; `routes/web.php` is a common location for most applications. ```php use Auth0\Laravel\Http\Controller\Stateful\{Login, Logout, Callback}; From ce675cfa86eca42e5c9e22bfd4a27105f0eec570 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 11:24:54 -0500 Subject: [PATCH 274/525] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7e5899d8..8eeb7033 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,7 @@ Find the `guards` section, and add a new guard to the `guards` array that uses t Find the `providers` section, and add a new provider to the `providers` array that uses `auth0.provider` as the driver. ```php +'providers' => [ 'someProviderName' => [ 'driver' => 'auth0.provider', 'repository' => \Auth0\Laravel\Auth\User\Repository::class From 85f967a122f489e1557213950e741f68caf915dd Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 11:29:26 -0500 Subject: [PATCH 275/525] Update README.md --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8eeb7033..587d3e9d 100644 --- a/README.md +++ b/README.md @@ -84,11 +84,16 @@ auth0 apps create \ You will receive a response with details about your new application. -Please make a note of your tenant's **domain** (e.g. `tenant.region.auth0.com`), **client ID**, and **client secret**. These will be required later during configuration. +Please make a note of your tenant's **domain** (e.g. `tenant.region.auth0.com`), **client ID**, and **client secret**. These will be required in the configuration step below. ### Creating an Auth0 API -You can create a new Auth0 API using [the Auth0 CLI](https://github.com/auth0/): +You can create a new Auth0 API using [the Auth0 CLI](https://github.com/auth0/). + +In the following command, you can choose any `--name` and `--identifier` values you like. However, the `--identifier` value must be a valid URL, although it does not need to be publicly accessible. Note that the identifier value cannot be changed later. + +> **Note** +> The identifier value will be used as the audience claim in your Access Tokens, so it is important to choose a value that will not conflict with other APIs you may be using. ```bash auth0 apis create \ @@ -100,11 +105,7 @@ auth0 apis create \ You will receive a response with details about your new API. -You can choose any `--name` and `--identifier` values you like. The `--identifier` value must be a valid URL, but it does not need to be publicly accessible. The identifier value cannot be changed once it is set. - -Note that the identifier value will be used as the audience claim in your Access Tokens, so it is important to choose a value that will not conflict with other APIs you may be using. - -The identifier value will used to configure the `audience` parameter in your application's configuration later. +Please make a note of your new API's **identifier**. This will be required in the configuration step, and will be referred to as the `audience`. ### Configuring the SDK @@ -160,7 +161,7 @@ Find the `providers` section, and add a new provider to the `providers` array th ], ``` -`someGuardName` and `someProviderName` can be any names you choose, but please ensure the provider's name (in this case, `someProviderName`) matches the `provider` value in the guard definition. +> **Note** > `someGuardName` and `someProviderName` can be any names you choose, but please ensure the provider's name (in this case, `someProviderName`) matches the `provider` value in the guard definition. ### Adding Login From 964357dfaecef785a2c4715439d6d0388d42c0fd Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 11:31:13 -0500 Subject: [PATCH 276/525] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 587d3e9d..7b36c293 100644 --- a/README.md +++ b/README.md @@ -118,10 +118,10 @@ AUTH0_DOMAIN= # Use the `client id` you noted earlier during application creation. AUTH0_CLIENT_ID= -# Use the `client_secret id` you noted earlier during application creation. +# Use the `client_secret` you noted earlier during application creation. AUTH0_CLIENT_SECRET= -# Use the `identifier id` you noted earlier during API creation. +# Use the `identifier` you noted earlier during API creation. AUTH0_AUDIENCE= # This should be any sufficiently long, random string. From e288b5790fdbc5c18191f8b144c6776238c777cc Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 11:32:31 -0500 Subject: [PATCH 277/525] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b36c293..e6117f15 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,8 @@ Find the `providers` section, and add a new provider to the `providers` array th ], ``` -> **Note** > `someGuardName` and `someProviderName` can be any names you choose, but please ensure the provider's name (in this case, `someProviderName`) matches the `provider` value in the guard definition. +> **Note** +> Please ensure the provider's name (in this case, `someProviderName`) matches the `provider` value in the guard definition. ### Adding Login From 1d114481c52aff37d37559210b568a484c538f37 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 11:33:16 -0500 Subject: [PATCH 278/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e6117f15..518aedf0 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ Find the `providers` section, and add a new provider to the `providers` array th For stateful applications that use a login/logout experience, the SDK provides routing controllers that handle the authentication flow for your application. -Add these routes where most appropriate for your configuration; `routes/web.php` is a common location for most applications. +Add these routes where most appropriate for your configuration. `routes/web.php` is a common location for many Laravel applications. ```php use Auth0\Laravel\Http\Controller\Stateful\{Login, Logout, Callback}; From cced828becbf18cfccf5171da567b2f8aa4bb6a7 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 11:34:09 -0500 Subject: [PATCH 279/525] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 518aedf0..ced829fb 100644 --- a/README.md +++ b/README.md @@ -166,9 +166,10 @@ Find the `providers` section, and add a new provider to the `providers` array th ### Adding Login -For stateful applications that use a login/logout experience, the SDK provides routing controllers that handle the authentication flow for your application. +> **Note** +> This section only applies to stateful application types. -Add these routes where most appropriate for your configuration. `routes/web.php` is a common location for many Laravel applications. +The SDK provides routing controllers that handle the authentication flow for your application. Add these routes where most appropriate for your configuration. `routes/web.php` is a common location for many Laravel applications. ```php use Auth0\Laravel\Http\Controller\Stateful\{Login, Logout, Callback}; From 751440473f3ae10a5ba6e501770e1ee03dd7539e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 11:35:59 -0500 Subject: [PATCH 280/525] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ced829fb..83070355 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ Route::get('/required', function () { })->middleware(['auth0.authenticate']); ``` -**`auth0.authenticate.optional` allows anyone to access a route.** It will check if a user is logged in, and if so, will make sure `Auth::user()` is available to the route. This is useful when you wish to display different content to logged-in users and guests. +**`auth0.authenticate.optional` allows anyone to access a route.** It will check if a user is logged in, and will make sure `Auth::user()` is available to the route if so. This is useful when you wish to display different content to logged-in users and guests. ```php Route::get('/', function () { @@ -233,7 +233,7 @@ Route::get('/api/private-scoped', function () { })->middleware(['auth0.authorize:read:messages']); ``` -**`auth0.authorize.optional` allows anyone to access a route.** It will check if a valid access token is present, and if so, will make sure `Auth::user()` is available to the route. This is useful when you wish to return different responses to authenticated and unauthenticated requests. +**`auth0.authorize.optional` allows anyone to access a route.** It will check if a valid access token is present, and will make sure `Auth::user()` is available to the route if so. This is useful when you wish to return different responses to authenticated and unauthenticated requests. ```php Route::get('/api/public', function () { From d362a2df4451f77439aa5e3778e7d1fbb9e59973 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 11:39:12 -0500 Subject: [PATCH 281/525] Update README.md --- README.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 83070355..3bf79448 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,11 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. ## Documentation -- Stateful Applications - - [Quickstart](https://auth0.com/docs/quickstart/webapp/laravel) — add login, logout, and user information to a Laravel application using Auth0. - - [Sample Application](https://github.com/auth0-samples/auth0-laravel-php-web-app) — a sample Laravel web application integrated with Auth0. -- Stateless Applications - - [Quickstart](https://auth0.com/docs/quickstart/backend/php) — add access token handling and route authorization to a backend Laravel application using Auth0. - - [Sample Application](https://github.com/auth0-samples/auth0-laravel-api-samples) — a sample Laravel backend application integrated with Auth0. -- [Examples](./EXAMPLES.md) — code samples for common scenarios. -- [Docs site](https://www.auth0.com/docs) — explore our docs site and learn more about Auth0. +- Quickstart Demonstrations + - [Application using Sessions (Stateful)](https://auth0.com/docs/quickstart/laravel/php) — Traditional web application that uses sessions and supports logging in, logging out, and querying user profiles. [The complete source code is also available.](https://github.com/auth0-samples/auth0-laravel-php-web-app) + - [API using Access Tokens (Stateless)](https://auth0.com/docs/quickstart/backend/laravel) — Backend service that authorizes endpoints using access tokens provided by a frontend client and returns JSON responses. [The complete source code is also available.](https://github.com/auth0-samples/auth0-laravel-api-samples) +- [Laravel Examples](./EXAMPLES.md) — Code samples for common scenarios. +- [Documentation Hub](https://www.auth0.com/docs) — Learn more about integrating Auth0. ## Getting Started From e2cd29a3919785665d7746af808f319932c63f0e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 13:03:00 -0500 Subject: [PATCH 282/525] Update EXAMPLES.md --- EXAMPLES.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index 8bcb44bf..d66d8a11 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -1,15 +1,19 @@ -# Examples using laravel-auth0 +# Auth0 Laravel SDK Examples -- [Custom user models and repositories](#custom-user-models-and-repositories) -- [Authorizing HTTP tests](#authorizing-http-tests) +- [Extending the SDK with Custom User Models and Repositories](#extending-the-sdk-with-custom-user-models-and-repositories) + - [Creating a Custom User Model](#creating-a-custom-user-model) + - [Creating a Custom User Repository](#creating-a-custom-user-repository) + - [Using a Custom User Repository](#using-a-custom-user-repository) +- [Authorizing HTTP Tests](#authorizing-http-tests) +- [Protecting Routes with Scope Filtering](#protecting-routes-with-scope-filtering) -## Custom user models and repositories +## Extending the SDK with Custom User Models and Repositories In Laravel, a User Repository is an interface that sits between your authentication source (Auth0) and core Laravel authentication services. It allows you to shape and manipulate the user model and it's data as you need to. For example, Auth0's unique identifier is a `string` in the format `auth0|123456abcdef`. If you were to attempt to persist a user to many traditional databases you'd likely encounter an error as, by default, a unique identifier is often expected to be an `integer` rather than a `string` type. A custom user model and repository is a great way to address integration challenges like this. -### Creating a custom user model +### Creating a Custom User Model Let's setup a custom user model for our application. To do this, let's create a file at `app/Auth/Models/User.php` within our Laravel project. This new class needs to implement the `Illuminate\Contracts\Auth\Authenticatable` interface to be compatible with Laravel's Guard API and this SDK. It must also implement either `Auth0\Laravel\Contract\Model\Stateful\User` or `Auth0\Laravel\Contract\Model\Stateless\User` depending on your application's needs. For example: @@ -111,13 +115,13 @@ Finally, update your application's `config/auth.php` file. Within the Auth0 prov ], ``` -## Authorizing HTTP tests +## Authorizing HTTP Tests If your application does contain HTTP tests which access routes that are protected by the `auth0.authorize` middleware, you can use the trait `Auth0\Laravel\Traits\ActingAsAuth0User` in your tests, which will give you a helper method `actingAsAuth0User(array $attributes=[])` similar to Laravel's `actingAs` method, that allows you to impersonate an authenticated state suitable for the middleware. The argument `attributes` is optional and you can use it to set any auth0 specific user attributes like scope, sub, azp, iap and so on. If no attributes are set, some default values are used. -### Example with a scope protected route +### Protecting Routes with Scope Filtering Let's assume you have a route like the following, that is protected by the scope `read:messages`: From 7018e8e74b66480c497c8a9661db0557060d99b0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 13:03:43 -0500 Subject: [PATCH 283/525] Update EXAMPLES.md --- EXAMPLES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index d66d8a11..26ff1082 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -121,7 +121,7 @@ If your application does contain HTTP tests which access routes that are protect The argument `attributes` is optional and you can use it to set any auth0 specific user attributes like scope, sub, azp, iap and so on. If no attributes are set, some default values are used. -### Protecting Routes with Scope Filtering +## Protecting Routes with Scope Filtering Let's assume you have a route like the following, that is protected by the scope `read:messages`: From 6615c0c6bcfec145f4743dee503c8507b6f48d54 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 13:04:28 -0500 Subject: [PATCH 284/525] Update EXAMPLES.md --- EXAMPLES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index 26ff1082..7bef2982 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -109,7 +109,7 @@ Finally, update your application's `config/auth.php` file. Within the Auth0 prov //... 'auth0' => [ - 'driver' => 'auth0', + 'driver' => 'auth0.provider', 'repository' => App\Auth\CustomUserRepository::class ], ], From 1e26f9bf2db5204c3b769be16913dd82eb4688c3 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 13:04:49 -0500 Subject: [PATCH 285/525] Update EXAMPLES.md --- EXAMPLES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index 7bef2982..63c9e961 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -110,7 +110,7 @@ Finally, update your application's `config/auth.php` file. Within the Auth0 prov 'auth0' => [ 'driver' => 'auth0.provider', - 'repository' => App\Auth\CustomUserRepository::class + 'repository' => \App\Auth\CustomUserRepository::class ], ], ``` From 626f6db4720d554a1419174ba65efbb661e8c17b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 14:18:49 -0500 Subject: [PATCH 286/525] Remove redundant phpcsf cli parameters. --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 9b95f6cc..15c87aa1 100644 --- a/composer.json +++ b/composer.json @@ -110,8 +110,8 @@ "mutate": "@php ./vendor/bin/infection --test-framework=pest --show-mutations", "pest:coverage": "@php vendor/bin/pest --order-by random --compact --coverage", "pest": "@php vendor/bin/pest --order-by random --compact", - "phpcs:fix": "@php vendor/bin/php-cs-fixer fix src", - "phpcs": "@php vendor/bin/php-cs-fixer fix src --dry-run --diff", + "phpcs:fix": "@php vendor/bin/php-cs-fixer fix", + "phpcs": "@php vendor/bin/php-cs-fixer fix --dry-run --diff", "phpstan": "@php vendor/bin/phpstan analyze", "psalm:fix": "@php vendor/bin/psalter --issues=all", "psalm": "@php vendor/bin/psalm", From 030fc9d786ff9fc2af7a3095545d865260aed830 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 14:19:02 -0500 Subject: [PATCH 287/525] Potential bugfix for custom repository exception. --- src/Auth/User/Provider.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Auth/User/Provider.php b/src/Auth/User/Provider.php index 7280cb9d..f289bc5e 100644 --- a/src/Auth/User/Provider.php +++ b/src/Auth/User/Provider.php @@ -49,7 +49,11 @@ private function resolveRepository( } if (! app()->bound($model)) { - throw new BindingResolutionException(sprintf('The configured Repository %s could not be loaded.', $model)); + try { + app()->make($model); + } catch (BindingResolutionException) { + throw new BindingResolutionException(sprintf('The configured Repository %s could not be loaded.', $model)); + } } $this->setRepositoryName($model); From cdb04edcb43ad7cba6374932429ae38791f21378 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 15:58:39 -0500 Subject: [PATCH 288/525] release: 7.5.1 (#355) --- CHANGELOG.md | 36 +++++++++++++++++++++--------------- src/Auth0.php | 2 +- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cd8140e..817e74f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,37 +2,43 @@ ## [Unreleased] +## [7.5.1](https://github.com/auth0/laravel-auth0/tree/7.5.1) (2023-04-04) + +**Fixed** + +- Resolved an issue wherein custom user repositories could fail to be instantiated under certain circumstances. + ## [7.5.0](https://github.com/auth0/laravel-auth0/tree/7.5.0) (2023-04-03) This release includes support for Laravel 10, and major improvements to the internal state handling mechanisms of the SDK. **Added** -— Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) -— New `Auth0\Laravel\Traits\Imposter` trait to allow for easier testing. [Example usage](./tests/Unit/Traits/ImpersonateTest.php) -— New Exception types have been added for more precise error catching. +- Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) +- New `Auth0\Laravel\Traits\Imposter` trait to allow for easier testing. [Example usage](./tests/Unit/Traits/ImpersonateTest.php) +- New Exception types have been added for more precise error catching. **Changed** The following changes have no effect on the external API of this package, but may affect internal usage. -— `Guard` will now more reliably detect changes in the underlying Auth0-PHP SDK session state. -— `Guard` will now more reliably sync changes back to the underlying Auth0-PHP SDK session state. -— `StateInstance` concept has been replaced by new `Credentials` entity. -— `Guard` updated to use new `Credentials` entity as primary internal storage for user data. -— `Auth0\Laravel\Traits\ActingAsAuth0User` was updated to use new`Credentials` entity. -— The HTTP middleware have been refactored to more clearly differentiate between token and session based identities. -— The `authenticate`, `authenticate.optional` and `authorize.optional` HTTP middleware now support scope filtering, as `authorize` already did. +- `Guard` will now more reliably detect changes in the underlying Auth0-PHP SDK session state. +- `Guard` will now more reliably sync changes back to the underlying Auth0-PHP SDK session state. +- `StateInstance` concept has been replaced by new `Credentials` entity. +- `Guard` updated to use new `Credentials` entity as primary internal storage for user data. +- `Auth0\Laravel\Traits\ActingAsAuth0User` was updated to use new`Credentials` entity. +- The HTTP middleware have been refactored to more clearly differentiate between token and session based identities. +- The `authenticate`, `authenticate.optional` and `authorize.optional` HTTP middleware now support scope filtering, as `authorize` already did. **Fixed** -— A 'Session store not set on request' error could occur when downstream applications implemented unit testing that use the Guard. This should be resolved now. -— `Guard` would not always honor the `provider` configuration value in `config/auth.php`. -— `Guard` is no longer defined as a Singleton to better support applications that need multi-guard configurations. +- A 'Session store not set on request' error could occur when downstream applications implemented unit testing that use the Guard. This should be resolved now. +- `Guard` would not always honor the `provider` configuration value in `config/auth.php`. +- `Guard` is no longer defined as a Singleton to better support applications that need multi-guard configurations. **Maintenance** -— Upgraded test suite to use PEST 2.0 framework. -— Updated test coverage to 100%. +- Upgraded test suite to use PEST 2.0 framework. +- Updated test coverage to 100%. **Important Notes** diff --git a/src/Auth0.php b/src/Auth0.php index 3ffee599..3d041c57 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -25,7 +25,7 @@ final class Auth0 implements ServiceContract * * @var string */ - public const VERSION = '7.5.0'; + public const VERSION = '7.5.1'; public function __construct( private ?SDKContract $sdk = null, From aedc6adbed65df34faf618ac08773c9d7cacfb6c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 4 Apr 2023 16:15:44 -0500 Subject: [PATCH 289/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3bf79448..9eb1bf95 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. -[![Package](https://img.shields.io/packagist/dt/auth0/login)](https://packagist.org/packages/auth0/laravel-auth0) +[![Package](https://img.shields.io/packagist/dt/auth0/login)](https://packagist.org/packages/auth0/login) ![Build Status](https://img.shields.io/github/checks-status/auth0/laravel-auth0/main) [![Coverage](https://img.shields.io/codecov/c/github/auth0/laravel-auth0/main)](https://codecov.io/gh/auth0/laravel-auth0) [![License](https://img.shields.io/packagist/l/auth0/login)](https://doge.mit-license.org/) From 37708b3c3b8d062a02b87953747fe4028aa1cf7f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 9 Apr 2023 21:38:03 -0500 Subject: [PATCH 290/525] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 817e74f1..6ba76c91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +- Relaxed response types from middleware to use low-level `Symfony\Component\HttpFoundation\Response` class, allowing for broader and custom response types. + ## [7.5.1](https://github.com/auth0/laravel-auth0/tree/7.5.1) (2023-04-04) **Fixed** From 4b19ca17d8ebae6b27254d2b29be9cbc9f62b052 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 9 Apr 2023 21:42:51 -0500 Subject: [PATCH 291/525] Add parallelization to PEST tests --- .github/workflows/php_composer_normalize.yml | 8 +- .github/workflows/php_composer_validate.yml | 8 +- .github/workflows/php_pest.yml | 41 +++++----- .github/workflows/php_phpcsf.yml | 22 ++---- .github/workflows/php_phpstan.yml | 36 ++++----- .github/workflows/php_psalm.yml | 36 ++++----- .github/workflows/php_rector.yml | 36 ++++----- .github/workflows/rep_cleanup.yml | 43 ----------- .github/workflows/rep_opened.yml | 81 -------------------- .github/workflows/rep_stale.yml | 21 ----- .github/workflows/sec_semgrep.yml | 14 ++-- .github/workflows/sec_snyk.yml | 15 +--- composer.json | 4 +- phpunit.xml.dist | 4 + tests/Pest.php | 12 +-- 15 files changed, 104 insertions(+), 277 deletions(-) delete mode 100644 .github/workflows/rep_cleanup.yml delete mode 100644 .github/workflows/rep_opened.yml delete mode 100644 .github/workflows/rep_stale.yml diff --git a/.github/workflows/php_composer_normalize.yml b/.github/workflows/php_composer_normalize.yml index edbba57b..304bd54c 100644 --- a/.github/workflows/php_composer_normalize.yml +++ b/.github/workflows/php_composer_normalize.yml @@ -1,18 +1,14 @@ -name: Composer +name: "Composer Normalize" on: - pull_request_target: - types: - - labeled + pull_request_target: {} push: branches: - main jobs: normalize: - name: Normalize runs-on: ubuntu-latest - if: github.event.label.name == 'run' || github.ref_name == 'main' steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/php_composer_validate.yml b/.github/workflows/php_composer_validate.yml index c2e94216..a05a3a3b 100644 --- a/.github/workflows/php_composer_validate.yml +++ b/.github/workflows/php_composer_validate.yml @@ -1,18 +1,14 @@ -name: Composer +name: "Composer Validate" on: - pull_request_target: - types: - - labeled + pull_request_target: {} push: branches: - main jobs: validate: - name: Validate runs-on: ubuntu-latest - if: github.event.label.name == 'run' || github.ref_name == 'main' steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/php_pest.yml b/.github/workflows/php_pest.yml index 5e27673b..d6cf1ad5 100644 --- a/.github/workflows/php_pest.yml +++ b/.github/workflows/php_pest.yml @@ -1,41 +1,40 @@ -name: Unit Tests +name: "PEST" on: - pull_request_target: - types: - - labeled + pull_request_target: {} push: branches: - main jobs: pest: - name: PEST - runs-on: ${{ matrix.operating-systems }} - if: github.event.label.name == 'run' || github.ref_name == 'main' + runs-on: ubuntu-latest strategy: fail-fast: false - matrix: - operating-systems: - - ubuntu-latest - php-versions: - - 8.1 - - 8.2 steps: + - uses: actions/checkout@v3 + - uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php-versions }} + php-version: 8.1 coverage: pcov - extensions: mbstring, openssl - - uses: actions/checkout@v3 + - id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - run: composer install --no-progress --prefer-dist --optimize-autoloader - - run: composer install --prefer-dist - - run: vendor/bin/pest --coverage-clover coverage/coverage.xml --order-by random + - run: vendor/bin/pest --order-by random --compact --parallel - - if: (matrix.php-versions == '8.1') - uses: codecov/codecov-action@v2 + - uses: codecov/codecov-action@v3 with: - directory: coverage + directory: ./coverage/ + flags: unittests diff --git a/.github/workflows/php_phpcsf.yml b/.github/workflows/php_phpcsf.yml index 80cf3daa..e3b39756 100644 --- a/.github/workflows/php_phpcsf.yml +++ b/.github/workflows/php_phpcsf.yml @@ -1,34 +1,24 @@ -name: Standards +name: "PHP CS Fixer" on: - pull_request_target: - types: - - labeled + pull_request_target: {} push: branches: - main jobs: - phpcs: - name: PHP CS Fixer - runs-on: ${{ matrix.operating-systems }} - if: github.event.label.name == 'run' || github.ref_name == 'main' + phpcsf: + runs-on: ubuntu-latest strategy: fail-fast: false - matrix: - operating-systems: - - ubuntu-latest - php-versions: - - 8.1 steps: - uses: actions/checkout@v3 - uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php-versions }} - coverage: pcov + php-version: 8.1 - id: composer-cache run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT @@ -41,4 +31,4 @@ jobs: - run: composer install --no-progress --prefer-dist --optimize-autoloader - # - run: vendor/bin/php-cs-fixer fix src --dry-run --diff + - run: vendor/bin/php-cs-fixer fix src --dry-run --diff diff --git a/.github/workflows/php_phpstan.yml b/.github/workflows/php_phpstan.yml index 3c19afe9..beff1f1e 100644 --- a/.github/workflows/php_phpstan.yml +++ b/.github/workflows/php_phpstan.yml @@ -1,34 +1,34 @@ -name: Analysis +name: "PHPStan" on: - pull_request_target: - types: - - labeled + pull_request_target: {} push: branches: - main jobs: phpstan: - name: PHPStan - runs-on: ${{ matrix.operating-systems }} - if: github.event.label.name == 'run' || github.ref_name == 'main' + runs-on: ubuntu-latest strategy: fail-fast: false - matrix: - operating-systems: - - ubuntu-latest - php-versions: - - 8.1 steps: + - uses: actions/checkout@v3 + - uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php-versions }} - coverage: pcov - extensions: mbstring, openssl + php-version: 8.1 - - uses: actions/checkout@v3 - - run: composer update --no-ansi --no-interaction --no-progress --prefer-dist --prefer-stable - - run: vendor/bin/phpstan analyze --no-progress + - id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - run: composer install --no-progress --prefer-dist --optimize-autoloader + + - run: vendor/bin/phpstan analyze diff --git a/.github/workflows/php_psalm.yml b/.github/workflows/php_psalm.yml index 1c4fee06..8280a6bc 100644 --- a/.github/workflows/php_psalm.yml +++ b/.github/workflows/php_psalm.yml @@ -1,34 +1,34 @@ -name: Analysis +name: "Psalm" on: - pull_request_target: - types: - - labeled + pull_request_target: {} push: branches: - main jobs: psalm: - name: Psalm - runs-on: ${{ matrix.operating-systems }} - if: github.event.label.name == 'run' || github.ref_name == 'main' + runs-on: ubuntu-latest strategy: fail-fast: false - matrix: - operating-systems: - - ubuntu-latest - php-versions: - - 8.1 steps: + - uses: actions/checkout@v3 + - uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php-versions }} - coverage: pcov - extensions: mbstring, openssl + php-version: 8.1 - - uses: actions/checkout@v3 - - run: composer update --no-ansi --no-interaction --no-progress --prefer-dist --prefer-stable - # - run: vendor/bin/psalm --no-progress + - id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - run: composer install --no-progress --prefer-dist --optimize-autoloader + + - run: vendor/bin/psalm diff --git a/.github/workflows/php_rector.yml b/.github/workflows/php_rector.yml index a4814ff3..34ae9cf9 100644 --- a/.github/workflows/php_rector.yml +++ b/.github/workflows/php_rector.yml @@ -1,34 +1,34 @@ -name: Standards +name: "Rector" on: - pull_request_target: - types: - - labeled + pull_request_target: {} push: branches: - main jobs: rector: - name: Rector - runs-on: ${{ matrix.operating-systems }} - if: github.event.label.name == 'run' || github.ref_name == 'main' + runs-on: ubuntu-latest strategy: fail-fast: false - matrix: - operating-systems: - - ubuntu-latest - php-versions: - - 8.1 steps: + - uses: actions/checkout@v3 + - uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php-versions }} - coverage: pcov - extensions: mbstring, openssl + php-version: 8.1 - - uses: actions/checkout@v3 - - run: composer update --no-ansi --no-interaction --no-progress --prefer-dist --prefer-stable - # - run: vendor/bin/rector process src --dry-run + - id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - run: composer install --no-progress --prefer-dist --optimize-autoloader + + - run: vendor/bin/rector process --dry-run diff --git a/.github/workflows/rep_cleanup.yml b/.github/workflows/rep_cleanup.yml deleted file mode 100644 index 32ce79f5..00000000 --- a/.github/workflows/rep_cleanup.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Repository - -on: - pull_request_target: - types: - - closed - - reopened - - converted_to_draft - - review_requested - - review_request_removed - - synchronize - -jobs: - rep-cleanup: - name: Cleanup - runs-on: ubuntu-latest - - permissions: - issues: write - pull-requests: write - - steps: - - uses: actions/github-script@v6 - with: - script: | - try { - labels = await github.rest.issues.listLabelsOnIssue({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo - }) - - if (labels.data.some(label => label.name === 'run')) { - github.rest.issues.removeLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - name: 'run' - }); - } - } catch (error) { - console.error(error); - } diff --git a/.github/workflows/rep_opened.yml b/.github/workflows/rep_opened.yml deleted file mode 100644 index 95c4eeea..00000000 --- a/.github/workflows/rep_opened.yml +++ /dev/null @@ -1,81 +0,0 @@ -name: Repository - -on: - pull_request_target: - types: - - opened - - edited - - ready_for_review - - converted_to_draft - -permissions: - issues: write - pull-requests: write - -jobs: - rep-opened: - name: PR/Issue Setup - runs-on: ubuntu-latest - - steps: - - uses: actions/github-script@v6 - with: - script: | - const pattern = /^(\w*)(?:\(([\w]*)\))?: (.*)$/; - const title = context.payload.pull_request.title; - - let type = null; - let scope = null; - let subject = null; - - try { - [type, scope, subject] = title.match(pattern).slice(1); - console.log(`Type: ${type}`, `Scope: ${scope}`, `Subject: ${subject}`) - } catch (error) { - console.error(error); - } - - if (type !== undefined && type !== null) { - const labels = { - 'feat': 'type-improvement', - 'refactor': 'type-improvement', - 'perf': 'type-improvement', - 'build': 'type-chore', - 'cj': 'type-chore', - 'style': 'type-chore', - 'fix': 'type-bug', - 'security': 'type-security', - 'docs': 'type-documentation', - 'test': 'type-tests', - 'release': 'type-release', - } - - if (type in labels) { - github.rest.issues.addLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: [labels[type]] - }) - } - } - - let isMember = false; - - try { - isMember = await github.rest.orgs.checkMembershipForUser({ - org: context.repo.owner, - username: context.payload.pull_request.user.login - }); - } catch (error) { - console.error(error); - } - - if (! isMember) { - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: '**👋 Thanks for contributing!** Please be patient while a maintainer reviews your PR. In the meantime, please make sure you\'ve read our [contributing guide](CONTRIBUTING.md).' - }) - } diff --git a/.github/workflows/rep_stale.yml b/.github/workflows/rep_stale.yml deleted file mode 100644 index 0c6f2548..00000000 --- a/.github/workflows/rep_stale.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Repository - -on: - schedule: - - cron: "30 1 * * *" - -permissions: - issues: write - pull-requests: write - -jobs: - rep-stale: - name: Maintenance - runs-on: ubuntu-latest - - steps: - - uses: actions/stale@v6 - with: - days-before-stale: 7 - days-before-close: 14 - repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/sec_semgrep.yml b/.github/workflows/sec_semgrep.yml index 2dfe7677..44552b60 100644 --- a/.github/workflows/sec_semgrep.yml +++ b/.github/workflows/sec_semgrep.yml @@ -1,21 +1,17 @@ -name: Security +name: "Semgrep" on: - pull_request_target: - types: - - labeled + pull_request_target: {} push: branches: - main -permissions: - security-events: write - jobs: semgrep: - name: Semgrep runs-on: ubuntu-latest - if: github.event.label.name == 'run' || github.ref_name == 'main' + + strategy: + fail-fast: false container: image: returntocorp/semgrep diff --git a/.github/workflows/sec_snyk.yml b/.github/workflows/sec_snyk.yml index 2dcde887..93a6b606 100644 --- a/.github/workflows/sec_snyk.yml +++ b/.github/workflows/sec_snyk.yml @@ -1,9 +1,7 @@ -name: Security +name: "Snyk" on: - pull_request_target: - types: - - labeled + pull_request_target: {} push: branches: - main @@ -13,17 +11,10 @@ permissions: jobs: snyk: - name: Snyk - runs-on: ${{ matrix.operating-systems }} - if: github.event.label.name == 'run' || github.ref_name == 'main' + runs-on: ubuntu-latest strategy: fail-fast: false - matrix: - operating-systems: - - ubuntu-latest - php-versions: - - 8.1 steps: - uses: shivammathur/setup-php@v2 diff --git a/composer.json b/composer.json index 15c87aa1..fedf6a34 100644 --- a/composer.json +++ b/composer.json @@ -108,8 +108,8 @@ }, "scripts": { "mutate": "@php ./vendor/bin/infection --test-framework=pest --show-mutations", - "pest:coverage": "@php vendor/bin/pest --order-by random --compact --coverage", - "pest": "@php vendor/bin/pest --order-by random --compact", + "pest:coverage": "@php vendor/bin/pest --order-by random --compact --coverage --parallel", + "pest": "@php vendor/bin/pest --order-by random --compact --parallel", "phpcs:fix": "@php vendor/bin/php-cs-fixer fix", "phpcs": "@php vendor/bin/php-cs-fixer fix --dry-run --diff", "phpstan": "@php vendor/bin/phpstan analyze", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 85e566e1..bbb4fa0c 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -22,4 +22,8 @@ tests/Unit + + + + diff --git a/tests/Pest.php b/tests/Pest.php index a9be220f..6318bd5c 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -19,13 +19,13 @@ uses(\Auth0\Laravel\Tests\TestCase::class)->in(__DIR__); -uses()->afterEach(function (): void { - $commands = ['optimize:clear']; +// uses()->afterEach(function (): void { +// $commands = ['optimize:clear']; - foreach ($commands as $command) { - Artisan::call($command); - } -})->in(__DIR__); +// foreach ($commands as $command) { +// Artisan::call($command); +// } +// })->in(__DIR__); uses()->beforeEach(function (): void { $this->events = []; From fcc56e88fd101586e45c874d6918142c1c0c9453 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 9 Apr 2023 21:43:25 -0500 Subject: [PATCH 292/525] Relax return type of middleware --- src/Auth/Guard.php | 3 +++ src/Contract/Http/Controller/Stateful/Callback.php | 5 +++-- src/Contract/Http/Controller/Stateful/Login.php | 5 +++-- src/Contract/Http/Controller/Stateful/Logout.php | 5 +++-- .../Http/Middleware/Stateful/Authenticate.php | 11 ++++++++--- .../Http/Middleware/Stateful/AuthenticateOptional.php | 11 ++++++++--- src/Contract/Http/Middleware/Stateless/Authorize.php | 9 +++++++-- .../Http/Middleware/Stateless/AuthorizeOptional.php | 10 ++++++++-- src/Event/Middleware/StatefulRequest.php | 6 ++++-- src/Event/Middleware/StatelessRequest.php | 6 ++++-- src/Http/Controller/Stateful/Callback.php | 5 +++-- src/Http/Controller/Stateful/Login.php | 5 +++-- src/Http/Controller/Stateful/Logout.php | 5 +++-- src/Http/Middleware/MiddlewareAbstract.php | 9 +++++++++ src/Http/Middleware/Stateful/Authenticate.php | 7 +++---- src/Http/Middleware/Stateful/AuthenticateOptional.php | 5 ++--- src/Http/Middleware/Stateless/Authorize.php | 4 ++-- src/Http/Middleware/Stateless/AuthorizeOptional.php | 4 ++-- 18 files changed, 78 insertions(+), 37 deletions(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 2926fc0a..5453ad98 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -245,6 +245,7 @@ private function pushState( $pushHash = ''; } // @codeCoverageIgnoreEnd + $pushHash = md5($pushHash); if ($pushHash === $this->pushHash) { @@ -567,6 +568,7 @@ public function user(): ?Authenticatable return $currentUser; } + // @codeCoverageIgnoreStart if (true === $legacyBehavior) { $token = $this->find(self::SOURCE_TOKEN); @@ -584,6 +586,7 @@ public function user(): ?Authenticatable return $this->getCredential()?->getUser(); } } + // @codeCoverageIgnoreFalse return null; } diff --git a/src/Contract/Http/Controller/Stateful/Callback.php b/src/Contract/Http/Controller/Stateful/Callback.php index 3c418551..cfc0d7a2 100644 --- a/src/Contract/Http/Controller/Stateful/Callback.php +++ b/src/Contract/Http/Controller/Stateful/Callback.php @@ -4,7 +4,8 @@ namespace Auth0\Laravel\Contract\Http\Controller\Stateful; -use Illuminate\Http\{RedirectResponse, Request}; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; interface Callback { @@ -13,5 +14,5 @@ interface Callback * * @param Request $request the incoming request instance */ - public function __invoke(Request $request): RedirectResponse; + public function __invoke(Request $request): Response; } diff --git a/src/Contract/Http/Controller/Stateful/Login.php b/src/Contract/Http/Controller/Stateful/Login.php index 32116706..661e4c17 100644 --- a/src/Contract/Http/Controller/Stateful/Login.php +++ b/src/Contract/Http/Controller/Stateful/Login.php @@ -4,7 +4,8 @@ namespace Auth0\Laravel\Contract\Http\Controller\Stateful; -use Illuminate\Http\{RedirectResponse, Request}; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; interface Login { @@ -14,5 +15,5 @@ interface Login * * @param Request $request the incoming request instance */ - public function __invoke(Request $request): RedirectResponse; + public function __invoke(Request $request): Response; } diff --git a/src/Contract/Http/Controller/Stateful/Logout.php b/src/Contract/Http/Controller/Stateful/Logout.php index 459013aa..34145a3f 100644 --- a/src/Contract/Http/Controller/Stateful/Logout.php +++ b/src/Contract/Http/Controller/Stateful/Logout.php @@ -4,7 +4,8 @@ namespace Auth0\Laravel\Contract\Http\Controller\Stateful; -use Illuminate\Http\{RedirectResponse, Request}; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; interface Logout { @@ -14,5 +15,5 @@ interface Logout * * @param Request $request the incoming request instance */ - public function __invoke(Request $request): RedirectResponse; + public function __invoke(Request $request): Response; } diff --git a/src/Contract/Http/Middleware/Stateful/Authenticate.php b/src/Contract/Http/Middleware/Stateful/Authenticate.php index 79c70b73..93cdb41a 100644 --- a/src/Contract/Http/Middleware/Stateful/Authenticate.php +++ b/src/Contract/Http/Middleware/Stateful/Authenticate.php @@ -5,8 +5,8 @@ namespace Auth0\Laravel\Contract\Http\Middleware\Stateful; use Closure; -use Illuminate\Http\{JsonResponse, RedirectResponse, Request, Response}; -use Illuminate\Routing\Redirector; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; interface Authenticate { @@ -15,6 +15,11 @@ interface Authenticate * * @param Request $request * @param Closure $next + * @param string $scope */ - public function handle(Request $request, Closure $next): Response | RedirectResponse | JsonResponse | Redirector; + public function handle( + Request $request, + Closure $next, + string $scope = '', + ): Response; } diff --git a/src/Contract/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Contract/Http/Middleware/Stateful/AuthenticateOptional.php index dbfafde5..a8abdd39 100644 --- a/src/Contract/Http/Middleware/Stateful/AuthenticateOptional.php +++ b/src/Contract/Http/Middleware/Stateful/AuthenticateOptional.php @@ -5,8 +5,8 @@ namespace Auth0\Laravel\Contract\Http\Middleware\Stateful; use Closure; -use Illuminate\Http\{JsonResponse, Request, Response}; -use Illuminate\Routing\Redirector; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; interface AuthenticateOptional { @@ -15,6 +15,11 @@ interface AuthenticateOptional * * @param Request $request * @param Closure $next + * @param string $scope */ - public function handle(Request $request, Closure $next): Response | Redirector | JsonResponse; + public function handle( + Request $request, + Closure $next, + string $scope = '', + ): Response; } diff --git a/src/Contract/Http/Middleware/Stateless/Authorize.php b/src/Contract/Http/Middleware/Stateless/Authorize.php index 39ff9ae5..2b1223ce 100644 --- a/src/Contract/Http/Middleware/Stateless/Authorize.php +++ b/src/Contract/Http/Middleware/Stateless/Authorize.php @@ -5,7 +5,8 @@ namespace Auth0\Laravel\Contract\Http\Middleware\Stateless; use Closure; -use Illuminate\Http\{JsonResponse, Request, Response}; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; interface Authorize { @@ -16,5 +17,9 @@ interface Authorize * @param Closure $next * @param string $scope */ - public function handle(Request $request, Closure $next, string $scope): Response | JsonResponse; + public function handle( + Request $request, + Closure $next, + string $scope = '' + ): Response; } diff --git a/src/Contract/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Contract/Http/Middleware/Stateless/AuthorizeOptional.php index 6eec638c..f53fda1a 100644 --- a/src/Contract/Http/Middleware/Stateless/AuthorizeOptional.php +++ b/src/Contract/Http/Middleware/Stateless/AuthorizeOptional.php @@ -5,7 +5,8 @@ namespace Auth0\Laravel\Contract\Http\Middleware\Stateless; use Closure; -use Illuminate\Http\{JsonResponse, Request, Response}; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; interface AuthorizeOptional { @@ -14,6 +15,11 @@ interface AuthorizeOptional * * @param Request $request * @param Closure $next + * @param string $scope */ - public function handle(Request $request, Closure $next): Response | JsonResponse; + public function handle( + Request $request, + Closure $next, + string $scope = '' + ): Response; } diff --git a/src/Event/Middleware/StatefulRequest.php b/src/Event/Middleware/StatefulRequest.php index 39bcc6c1..672275b2 100644 --- a/src/Event/Middleware/StatefulRequest.php +++ b/src/Event/Middleware/StatefulRequest.php @@ -11,7 +11,9 @@ final class StatefulRequest extends Auth0Event implements StatefulRequestContract { - public function __construct(public Request $request, public Guard $guard) - { + public function __construct( + public Request $request, + public Guard $guard + ) { } } diff --git a/src/Event/Middleware/StatelessRequest.php b/src/Event/Middleware/StatelessRequest.php index 000b7724..1bd4ff97 100644 --- a/src/Event/Middleware/StatelessRequest.php +++ b/src/Event/Middleware/StatelessRequest.php @@ -11,7 +11,9 @@ final class StatelessRequest extends Auth0Event implements StatelessRequestContract { - public function __construct(public Request $request, public Guard $guard) - { + public function __construct( + public Request $request, + public Guard $guard + ) { } } diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index ba81f093..7438bafc 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -12,7 +12,8 @@ use Auth0\Laravel\Http\Controller\ControllerAbstract; use Illuminate\Auth\Events\{Attempting, Authenticated, Failed, Validated}; use Illuminate\Contracts\Auth\Authenticatable; -use Illuminate\Http\{RedirectResponse, Request}; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; use Throwable; use function is_string; @@ -26,7 +27,7 @@ final class Callback extends ControllerAbstract implements CallbackContract */ public function __invoke( Request $request, - ): RedirectResponse { + ): Response { $guard = auth()->guard(); if (! $guard instanceof GuardContract || $guard->check()) { diff --git a/src/Http/Controller/Stateful/Login.php b/src/Http/Controller/Stateful/Login.php index f734c6f3..0b23d181 100644 --- a/src/Http/Controller/Stateful/Login.php +++ b/src/Http/Controller/Stateful/Login.php @@ -8,7 +8,8 @@ use Auth0\Laravel\Contract\Auth\Guard as GuardContract; use Auth0\Laravel\Contract\Http\Controller\Stateful\Login as LoginContract; use Auth0\Laravel\Http\Controller\ControllerAbstract; -use Illuminate\Http\{RedirectResponse, Request}; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; final class Login extends ControllerAbstract implements LoginContract { @@ -19,7 +20,7 @@ final class Login extends ControllerAbstract implements LoginContract */ public function __invoke( Request $request, - ): RedirectResponse { + ): Response { $guard = auth()->guard(); if (! $guard instanceof GuardContract) { diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index 70c6face..36549150 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -8,7 +8,8 @@ use Auth0\Laravel\Contract\Auth\Guard as GuardContract; use Auth0\Laravel\Contract\Http\Controller\Stateful\Logout as LogoutContract; use Auth0\Laravel\Http\Controller\ControllerAbstract; -use Illuminate\Http\{RedirectResponse, Request}; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; use function is_string; @@ -21,7 +22,7 @@ final class Logout extends ControllerAbstract implements LogoutContract */ public function __invoke( Request $request, - ): RedirectResponse { + ): Response { $guard = auth()->guard(); if (! $guard instanceof GuardContract) { diff --git a/src/Http/Middleware/MiddlewareAbstract.php b/src/Http/Middleware/MiddlewareAbstract.php index f2671f64..27831ad3 100644 --- a/src/Http/Middleware/MiddlewareAbstract.php +++ b/src/Http/Middleware/MiddlewareAbstract.php @@ -4,9 +4,18 @@ namespace Auth0\Laravel\Http\Middleware; +use Closure; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; + /** * @codeCoverageIgnore */ abstract class MiddlewareAbstract { + abstract public function handle( + Request $request, + Closure $next, + string $scope = '', + ): Response; } diff --git a/src/Http/Middleware/Stateful/Authenticate.php b/src/Http/Middleware/Stateful/Authenticate.php index 097ec4ed..c8363a89 100644 --- a/src/Http/Middleware/Stateful/Authenticate.php +++ b/src/Http/Middleware/Stateful/Authenticate.php @@ -10,8 +10,7 @@ use Auth0\Laravel\Event\Middleware\StatefulRequest; use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; use Closure; -use Illuminate\Http\{JsonResponse, RedirectResponse, Request, Response}; -use Illuminate\Routing\Redirector; +use Symfony\Component\HttpFoundation\{Response, Request}; /** * This middleware will configure the authenticated user for the session using a @@ -24,7 +23,7 @@ public function handle( Request $request, Closure $next, string $scope = '', - ): Response | RedirectResponse | JsonResponse | Redirector { + ): Response { $guard = auth()->guard(); if (! $guard instanceof GuardContract) { @@ -46,6 +45,6 @@ public function handle( abort(Response::HTTP_FORBIDDEN, 'Forbidden'); } - return redirect(config('auth0.routes.login', 'login')); // @phpstan-ignore-line + return redirect()->to(config('auth0.routes.login', 'login')); // @phpstan-ignore-line } } diff --git a/src/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Http/Middleware/Stateful/AuthenticateOptional.php index 6c4363b9..ca0de19b 100644 --- a/src/Http/Middleware/Stateful/AuthenticateOptional.php +++ b/src/Http/Middleware/Stateful/AuthenticateOptional.php @@ -10,8 +10,7 @@ use Auth0\Laravel\Event\Middleware\StatefulRequest; use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; use Closure; -use Illuminate\Http\{JsonResponse, Request, Response}; -use Illuminate\Routing\Redirector; +use Symfony\Component\HttpFoundation\{Response, Request}; /** * This middleware will configure the authenticated user for the session using a @@ -24,7 +23,7 @@ public function handle( Request $request, Closure $next, string $scope = '', - ): Response | Redirector | JsonResponse { + ): Response { $guard = auth()->guard(); if (! $guard instanceof GuardContract) { diff --git a/src/Http/Middleware/Stateless/Authorize.php b/src/Http/Middleware/Stateless/Authorize.php index 15a36999..6a84ccd6 100644 --- a/src/Http/Middleware/Stateless/Authorize.php +++ b/src/Http/Middleware/Stateless/Authorize.php @@ -10,7 +10,7 @@ use Auth0\Laravel\Event\Middleware\StatelessRequest; use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; use Closure; -use Illuminate\Http\{JsonResponse, Request, Response}; +use Symfony\Component\HttpFoundation\{Response, Request}; /** * This middleware will configure the authenticated user using an available access token. @@ -22,7 +22,7 @@ public function handle( Request $request, Closure $next, string $scope = '', - ): Response | JsonResponse { + ): Response { $guard = auth()->guard(); if (! $guard instanceof GuardContract) { diff --git a/src/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Http/Middleware/Stateless/AuthorizeOptional.php index 12f7389f..5ed52948 100644 --- a/src/Http/Middleware/Stateless/AuthorizeOptional.php +++ b/src/Http/Middleware/Stateless/AuthorizeOptional.php @@ -10,7 +10,7 @@ use Auth0\Laravel\Event\Middleware\StatelessRequest; use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; use Closure; -use Illuminate\Http\{JsonResponse, Request, Response}; +use Symfony\Component\HttpFoundation\{Response, Request}; /** * This middleware will configure the authenticated user using an available access token. @@ -21,7 +21,7 @@ public function handle( Request $request, Closure $next, string $scope = '', - ): Response | JsonResponse { + ): Response { $guard = auth()->guard(); if (! $guard instanceof GuardContract) { From 6c283efce85b0110060a78805caef9ddafc9a493 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 9 Apr 2023 21:45:23 -0500 Subject: [PATCH 293/525] Update Bug Report.yml --- .github/ISSUE_TEMPLATE/Bug Report.yml | 35 +++++++++++++-------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index d0224c18..0bfc8fb6 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -5,20 +5,29 @@ body: - type: markdown attributes: value: Thanks for taking the time to help us improve this project! + - type: dropdown + id: laravel + attributes: + label: Laravel Version + description: What version of Laravel are you running? + options: + - Laravel 10.x + - Laravel 9.x + - Other (specify in 'additional context') + validations: + required: true - type: dropdown id: sdk attributes: label: SDK Version description: What version of our Laravel plugin are you running? (`composer show | grep auth0/login`) options: - - 7.5 - - 7.4 - - 7.3 - - 7.2 - - 7.1 - - 7.0 - - 6.5 - - 6.4 + - SDK 7.5 + - SDK 7.4 + - SDK 7.3 + - SDK 7.2 + - SDK 7.1 + - SDK 7.0 - Other (specify in 'additional context') validations: required: true @@ -35,16 +44,6 @@ body: - Other (specify in 'additional context') validations: required: true - - type: dropdown - id: composer - attributes: - label: Composer Version - description: What version of Composer are you running? (`composer -v`) - options: - - 2.x - - 1.x - validations: - required: true - type: textarea id: bug-description attributes: From 7cfa14b86c4d95cf9da9b11e674b606a9e805c93 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 9 Apr 2023 21:55:50 -0500 Subject: [PATCH 294/525] Relax return type of middleware --- src/Auth/Guard.php | 30 +++++++++---------- src/Auth0.php | 6 ++-- src/Cache/LaravelCachePool.php | 2 +- .../Http/Middleware/Stateless/Authorize.php | 2 +- .../Stateless/AuthorizeOptional.php | 2 +- src/Event/Middleware/StatefulRequest.php | 2 +- src/Event/Middleware/StatelessRequest.php | 2 +- src/Http/Controller/Stateful/Callback.php | 3 +- src/Http/Controller/Stateful/Login.php | 3 +- src/Http/Controller/Stateful/Logout.php | 3 +- src/Http/Middleware/Stateful/Authenticate.php | 6 ++-- .../Stateful/AuthenticateOptional.php | 8 +++-- src/Http/Middleware/Stateless/Authorize.php | 7 +++-- .../Stateless/AuthorizeOptional.php | 6 ++-- 14 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 5453ad98..b5500ed5 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -68,7 +68,7 @@ private function findSession(): ?Credential $session = $this->pullState(); $user = $session?->getUser(); - if (null !== $session && $user instanceof Authenticatable) { + if ($session instanceof Credential && $user instanceof Authenticatable) { $user = $this->getProvider()->retrieveByCredentials($this->normalizeUserArray($user)); if ($user instanceof Authenticatable) { @@ -232,7 +232,7 @@ private function pushState( $sdk = $this->getSdk(); $credential ??= $this->getCredential(); - if (null === $credential) { + if (! $credential instanceof Credential) { $sdk->clear(true); return $this; @@ -291,7 +291,7 @@ private function pushState( private function refreshSession( ?Credential $credential, ): ?Credential { - if (null === $credential || true !== $credential->getAccessTokenExpired()) { + if (! $credential instanceof Credential || true !== $credential->getAccessTokenExpired()) { return $credential; } @@ -307,7 +307,7 @@ private function refreshSession( $session = null; } - if (null !== $session) { + if ($session instanceof Credential) { event(new TokenRefreshSucceeded()); $user = $this->getProvider()->retrieveByCredentials((array) $session->getUser()); @@ -332,7 +332,7 @@ private function refreshSession( public function authenticate(): Authenticatable { - if (null !== ($user = $this->user())) { + if (($user = $this->user()) instanceof Authenticatable) { return $user; } @@ -354,7 +354,7 @@ public function find( if (self::SOURCE_TOKEN === $source) { $candidate = $this->findToken(); - if (null !== $candidate) { + if ($candidate instanceof Credential) { return $candidate; } } @@ -362,7 +362,7 @@ public function find( if (self::SOURCE_SESSION === $source) { $candidate = $this->findSession(); - if (null !== $candidate) { + if ($candidate instanceof Credential) { return $candidate; } } @@ -379,9 +379,9 @@ public function forgetUser(): self public function getCredential(): ?Credential { - if (! $this->impersonating && self::SOURCE_SESSION === $this->getCredentialSource() && null !== $this->credential) { + if (! $this->impersonating && self::SOURCE_SESSION === $this->getCredentialSource() && $this->credential instanceof Credential) { $updated = $this->findSession(); - $source = null !== $updated ? self::SOURCE_SESSION : null; + $source = $updated instanceof Credential ? self::SOURCE_SESSION : null; $this->setCredential($updated, $source); $this->pushState($updated); } @@ -467,7 +467,7 @@ public function hasScope( public function hasUser(): bool { - return null !== $this->getCredential()?->getUser(); + return $this->getCredential()?->getUser() instanceof Authenticatable; } public function id(): int | string | null @@ -489,7 +489,7 @@ public function login( $this->pushState($credential); $user = $credential?->getUser(); - if (null !== $credential && $user instanceof Authenticatable) { + if ($credential instanceof Credential && $user instanceof Authenticatable) { event(new Login(self::class, $user, true)); } @@ -501,7 +501,7 @@ public function logout(): self $this->impersonating = false; $user = $this->user(); - if (null !== $user) { + if ($user instanceof Authenticatable) { event(new Logout(self::class, $user)); } @@ -564,7 +564,7 @@ public function user(): ?Authenticatable $legacyBehavior = config('auth0.behavior.legacyGuardUserMethod', true); $currentUser = $this->getCredential()?->getUser(); - if (null !== $currentUser) { + if ($currentUser instanceof Authenticatable) { return $currentUser; } @@ -572,7 +572,7 @@ public function user(): ?Authenticatable if (true === $legacyBehavior) { $token = $this->find(self::SOURCE_TOKEN); - if (null !== $token) { + if ($token instanceof Credential) { $this->login($token, self::SOURCE_TOKEN); return $this->getCredential()?->getUser(); @@ -580,7 +580,7 @@ public function user(): ?Authenticatable $session = $this->find(self::SOURCE_SESSION); - if (null !== $session) { + if ($session instanceof Credential) { $this->login($token, self::SOURCE_SESSION); return $this->getCredential()?->getUser(); diff --git a/src/Auth0.php b/src/Auth0.php index 3d041c57..11ec49e8 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -46,7 +46,7 @@ private function setSdkTelemetry(): self public function getConfiguration(): Configuration { - if (null === $this->configuration) { + if (! $this->configuration instanceof Configuration) { $config = config('auth0'); /** @@ -108,7 +108,7 @@ public function getCredentials(): ?object public function getSdk(): SDKContract { - if (null !== $this->sdk) { + if ($this->sdk instanceof SDKContract) { return $this->sdk; } @@ -129,7 +129,7 @@ public function setConfiguration(Configuration $configuration): self { $this->configuration = $configuration; - if (null !== $this->sdk) { + if ($this->sdk instanceof SDKContract) { $this->sdk->setConfiguration($configuration); } diff --git a/src/Cache/LaravelCachePool.php b/src/Cache/LaravelCachePool.php index ab2246b2..5cbf5664 100644 --- a/src/Cache/LaravelCachePool.php +++ b/src/Cache/LaravelCachePool.php @@ -86,7 +86,7 @@ public function commit(): bool $item = $this->getDeferred((string) $singleDeferred); // @codeCoverageIgnoreStart - if (null !== $item && ! $this->save($item)) { + if ($item instanceof CacheItemInterface && ! $this->save($item)) { $success = false; } // @codeCoverageIgnoreEnd diff --git a/src/Contract/Http/Middleware/Stateless/Authorize.php b/src/Contract/Http/Middleware/Stateless/Authorize.php index 2b1223ce..a8282410 100644 --- a/src/Contract/Http/Middleware/Stateless/Authorize.php +++ b/src/Contract/Http/Middleware/Stateless/Authorize.php @@ -20,6 +20,6 @@ interface Authorize public function handle( Request $request, Closure $next, - string $scope = '' + string $scope = '', ): Response; } diff --git a/src/Contract/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Contract/Http/Middleware/Stateless/AuthorizeOptional.php index f53fda1a..cef476d4 100644 --- a/src/Contract/Http/Middleware/Stateless/AuthorizeOptional.php +++ b/src/Contract/Http/Middleware/Stateless/AuthorizeOptional.php @@ -20,6 +20,6 @@ interface AuthorizeOptional public function handle( Request $request, Closure $next, - string $scope = '' + string $scope = '', ): Response; } diff --git a/src/Event/Middleware/StatefulRequest.php b/src/Event/Middleware/StatefulRequest.php index 672275b2..c58d00fe 100644 --- a/src/Event/Middleware/StatefulRequest.php +++ b/src/Event/Middleware/StatefulRequest.php @@ -13,7 +13,7 @@ final class StatefulRequest extends Auth0Event implements StatefulRequestContrac { public function __construct( public Request $request, - public Guard $guard + public Guard $guard, ) { } } diff --git a/src/Event/Middleware/StatelessRequest.php b/src/Event/Middleware/StatelessRequest.php index 1bd4ff97..765224df 100644 --- a/src/Event/Middleware/StatelessRequest.php +++ b/src/Event/Middleware/StatelessRequest.php @@ -13,7 +13,7 @@ final class StatelessRequest extends Auth0Event implements StatelessRequestContr { public function __construct( public Request $request, - public Guard $guard + public Guard $guard, ) { } } diff --git a/src/Http/Controller/Stateful/Callback.php b/src/Http/Controller/Stateful/Callback.php index 7438bafc..78fc6859 100644 --- a/src/Http/Controller/Stateful/Callback.php +++ b/src/Http/Controller/Stateful/Callback.php @@ -6,6 +6,7 @@ use Auth0\Laravel\Auth\Guard; use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Contract\Entities\Credential; use Auth0\Laravel\Contract\Http\Controller\Stateful\Callback as CallbackContract; use Auth0\Laravel\Event\Stateful\{AuthenticationFailed, AuthenticationSucceeded}; use Auth0\Laravel\Exception\Stateful\CallbackException; @@ -123,7 +124,7 @@ public function __invoke( $credential = $guard->find(Guard::SOURCE_SESSION); $user = $credential?->getUser(); - if (null !== $credential && $user instanceof Authenticatable) { + if ($credential instanceof Credential && $user instanceof Authenticatable) { event(new Validated($guard::class, $user)); $guard->login($credential, Guard::SOURCE_SESSION); diff --git a/src/Http/Controller/Stateful/Login.php b/src/Http/Controller/Stateful/Login.php index 0b23d181..50acabb7 100644 --- a/src/Http/Controller/Stateful/Login.php +++ b/src/Http/Controller/Stateful/Login.php @@ -10,6 +10,7 @@ use Auth0\Laravel\Http\Controller\ControllerAbstract; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; +use Auth0\Laravel\Contract\Entities\Credential; final class Login extends ControllerAbstract implements LoginContract { @@ -27,7 +28,7 @@ public function __invoke( return redirect()->intended(config('auth0.routes.home', '/')); } - $loggedIn = $guard->check() ? true : null !== $guard->find(Guard::SOURCE_SESSION); + $loggedIn = $guard->check() ? true : $guard->find(Guard::SOURCE_SESSION) instanceof Credential; if ($loggedIn) { return redirect()->intended(config('auth0.routes.home', '/')); diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index 36549150..38f3d00d 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -10,6 +10,7 @@ use Auth0\Laravel\Http\Controller\ControllerAbstract; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; +use Auth0\Laravel\Contract\Entities\Credential; use function is_string; @@ -29,7 +30,7 @@ public function __invoke( return redirect()->intended(config('auth0.routes.home', '/')); } - $loggedIn = $guard->check() ? true : null !== $guard->find(Guard::SOURCE_SESSION); + $loggedIn = $guard->check() ? true : $guard->find(Guard::SOURCE_SESSION) instanceof Credential; if ($loggedIn) { session()->invalidate(); diff --git a/src/Http/Middleware/Stateful/Authenticate.php b/src/Http/Middleware/Stateful/Authenticate.php index c8363a89..3c871d7c 100644 --- a/src/Http/Middleware/Stateful/Authenticate.php +++ b/src/Http/Middleware/Stateful/Authenticate.php @@ -10,7 +10,9 @@ use Auth0\Laravel\Event\Middleware\StatefulRequest; use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; use Closure; -use Symfony\Component\HttpFoundation\{Response, Request}; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; +use Auth0\Laravel\Contract\Entities\Credential; /** * This middleware will configure the authenticated user for the session using a @@ -35,7 +37,7 @@ public function handle( $credential = $guard->find(Guard::SOURCE_SESSION); - if (null !== $credential) { + if ($credential instanceof Credential) { if ('' === $scope || $guard->hasScope($scope, $credential)) { $guard->login($credential, Guard::SOURCE_SESSION); diff --git a/src/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Http/Middleware/Stateful/AuthenticateOptional.php index ca0de19b..a9bafeb1 100644 --- a/src/Http/Middleware/Stateful/AuthenticateOptional.php +++ b/src/Http/Middleware/Stateful/AuthenticateOptional.php @@ -10,7 +10,9 @@ use Auth0\Laravel\Event\Middleware\StatefulRequest; use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; use Closure; -use Symfony\Component\HttpFoundation\{Response, Request}; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; +use Auth0\Laravel\Contract\Entities\Credential; /** * This middleware will configure the authenticated user for the session using a @@ -23,7 +25,7 @@ public function handle( Request $request, Closure $next, string $scope = '', - ): Response { + ): Response { $guard = auth()->guard(); if (! $guard instanceof GuardContract) { @@ -35,7 +37,7 @@ public function handle( $credential = $guard->find(Guard::SOURCE_SESSION); - if (null !== $credential && ('' === $scope || $guard->hasScope($scope, $credential))) { + if ($credential instanceof Credential && ('' === $scope || $guard->hasScope($scope, $credential))) { $guard->login($credential, Guard::SOURCE_SESSION); } diff --git a/src/Http/Middleware/Stateless/Authorize.php b/src/Http/Middleware/Stateless/Authorize.php index 6a84ccd6..94e49aea 100644 --- a/src/Http/Middleware/Stateless/Authorize.php +++ b/src/Http/Middleware/Stateless/Authorize.php @@ -10,8 +10,9 @@ use Auth0\Laravel\Event\Middleware\StatelessRequest; use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; use Closure; -use Symfony\Component\HttpFoundation\{Response, Request}; - +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; +use Auth0\Laravel\Contract\Entities\Credential; /** * This middleware will configure the authenticated user using an available access token. * If a token is not available, it will raise an exception. @@ -34,7 +35,7 @@ public function handle( $credential = $guard->find(Guard::SOURCE_TOKEN); - if (null !== $credential) { + if ($credential instanceof Credential) { if ('' === $scope || $guard->hasScope($scope, $credential)) { $guard->login($credential, Guard::SOURCE_TOKEN); diff --git a/src/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Http/Middleware/Stateless/AuthorizeOptional.php index 5ed52948..df1fdb59 100644 --- a/src/Http/Middleware/Stateless/AuthorizeOptional.php +++ b/src/Http/Middleware/Stateless/AuthorizeOptional.php @@ -10,7 +10,9 @@ use Auth0\Laravel\Event\Middleware\StatelessRequest; use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; use Closure; -use Symfony\Component\HttpFoundation\{Response, Request}; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Response; +use Auth0\Laravel\Contract\Entities\Credential; /** * This middleware will configure the authenticated user using an available access token. @@ -33,7 +35,7 @@ public function handle( $credential = $guard->find(Guard::SOURCE_TOKEN); - if (null !== $credential && ('' === $scope || $guard->hasScope($scope, $credential))) { + if ($credential instanceof Credential && ('' === $scope || $guard->hasScope($scope, $credential))) { $guard->login($credential, Guard::SOURCE_TOKEN); return $next($request); From 1667f51ddb0697e4626fa983d7115376b597c159 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 9 Apr 2023 21:57:00 -0500 Subject: [PATCH 295/525] Update sec_semgrep.yml --- .github/workflows/sec_semgrep.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/sec_semgrep.yml b/.github/workflows/sec_semgrep.yml index 44552b60..4bc66a5f 100644 --- a/.github/workflows/sec_semgrep.yml +++ b/.github/workflows/sec_semgrep.yml @@ -6,6 +6,9 @@ on: branches: - main +permissions: + security-events: write + jobs: semgrep: runs-on: ubuntu-latest From 5a60fa854200953972798434dea5fa6f60146219 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 9 Apr 2023 21:57:03 -0500 Subject: [PATCH 296/525] Update sec_snyk.yml --- .github/workflows/sec_snyk.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sec_snyk.yml b/.github/workflows/sec_snyk.yml index 93a6b606..93cb3e7b 100644 --- a/.github/workflows/sec_snyk.yml +++ b/.github/workflows/sec_snyk.yml @@ -19,7 +19,7 @@ jobs: steps: - uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php-versions }} + php-version: 8.1 coverage: none extensions: mbstring env: From 3ed973f020e94ec453ae988aa8b749d904d34527 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 9 Apr 2023 21:57:42 -0500 Subject: [PATCH 297/525] Relax return type of middleware --- src/Http/Controller/Stateful/Login.php | 2 +- src/Http/Controller/Stateful/Logout.php | 2 +- src/Http/Middleware/Stateful/Authenticate.php | 2 +- src/Http/Middleware/Stateful/AuthenticateOptional.php | 2 +- src/Http/Middleware/Stateless/Authorize.php | 3 ++- src/Http/Middleware/Stateless/AuthorizeOptional.php | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Http/Controller/Stateful/Login.php b/src/Http/Controller/Stateful/Login.php index 50acabb7..203682ac 100644 --- a/src/Http/Controller/Stateful/Login.php +++ b/src/Http/Controller/Stateful/Login.php @@ -6,11 +6,11 @@ use Auth0\Laravel\Auth\Guard; use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Contract\Entities\Credential; use Auth0\Laravel\Contract\Http\Controller\Stateful\Login as LoginContract; use Auth0\Laravel\Http\Controller\ControllerAbstract; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; -use Auth0\Laravel\Contract\Entities\Credential; final class Login extends ControllerAbstract implements LoginContract { diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php index 38f3d00d..e665870a 100644 --- a/src/Http/Controller/Stateful/Logout.php +++ b/src/Http/Controller/Stateful/Logout.php @@ -6,11 +6,11 @@ use Auth0\Laravel\Auth\Guard; use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Contract\Entities\Credential; use Auth0\Laravel\Contract\Http\Controller\Stateful\Logout as LogoutContract; use Auth0\Laravel\Http\Controller\ControllerAbstract; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; -use Auth0\Laravel\Contract\Entities\Credential; use function is_string; diff --git a/src/Http/Middleware/Stateful/Authenticate.php b/src/Http/Middleware/Stateful/Authenticate.php index 3c871d7c..d3f12569 100644 --- a/src/Http/Middleware/Stateful/Authenticate.php +++ b/src/Http/Middleware/Stateful/Authenticate.php @@ -6,13 +6,13 @@ use Auth0\Laravel\Auth\Guard; use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Contract\Entities\Credential; use Auth0\Laravel\Contract\Http\Middleware\Stateful\Authenticate as AuthenticateContract; use Auth0\Laravel\Event\Middleware\StatefulRequest; use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; -use Auth0\Laravel\Contract\Entities\Credential; /** * This middleware will configure the authenticated user for the session using a diff --git a/src/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Http/Middleware/Stateful/AuthenticateOptional.php index a9bafeb1..1a34186d 100644 --- a/src/Http/Middleware/Stateful/AuthenticateOptional.php +++ b/src/Http/Middleware/Stateful/AuthenticateOptional.php @@ -6,13 +6,13 @@ use Auth0\Laravel\Auth\Guard; use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Contract\Entities\Credential; use Auth0\Laravel\Contract\Http\Middleware\Stateful\AuthenticateOptional as AuthenticateOptionalContract; use Auth0\Laravel\Event\Middleware\StatefulRequest; use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; -use Auth0\Laravel\Contract\Entities\Credential; /** * This middleware will configure the authenticated user for the session using a diff --git a/src/Http/Middleware/Stateless/Authorize.php b/src/Http/Middleware/Stateless/Authorize.php index 94e49aea..1653200b 100644 --- a/src/Http/Middleware/Stateless/Authorize.php +++ b/src/Http/Middleware/Stateless/Authorize.php @@ -6,13 +6,14 @@ use Auth0\Laravel\Auth\Guard; use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Contract\Entities\Credential; use Auth0\Laravel\Contract\Http\Middleware\Stateless\Authorize as AuthorizeContract; use Auth0\Laravel\Event\Middleware\StatelessRequest; use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; -use Auth0\Laravel\Contract\Entities\Credential; + /** * This middleware will configure the authenticated user using an available access token. * If a token is not available, it will raise an exception. diff --git a/src/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Http/Middleware/Stateless/AuthorizeOptional.php index df1fdb59..4151cdeb 100644 --- a/src/Http/Middleware/Stateless/AuthorizeOptional.php +++ b/src/Http/Middleware/Stateless/AuthorizeOptional.php @@ -6,13 +6,13 @@ use Auth0\Laravel\Auth\Guard; use Auth0\Laravel\Contract\Auth\Guard as GuardContract; +use Auth0\Laravel\Contract\Entities\Credential; use Auth0\Laravel\Contract\Http\Middleware\Stateless\AuthorizeOptional as AuthorizeOptionalContract; use Auth0\Laravel\Event\Middleware\StatelessRequest; use Auth0\Laravel\Http\Middleware\MiddlewareAbstract; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; -use Auth0\Laravel\Contract\Entities\Credential; /** * This middleware will configure the authenticated user using an available access token. From 5863d5c1478a335247895c282a9790da39c6bbf4 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 10 Apr 2023 12:03:49 -0500 Subject: [PATCH 298/525] Release 7.5.2 (#360) --- CHANGELOG.md | 4 ++++ src/Auth0.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ba76c91..5c107a2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +## [7.5.2](https://github.com/auth0/laravel-auth0/tree/7.5.2) (2023-04-10) + +**Fixed** + - Relaxed response types from middleware to use low-level `Symfony\Component\HttpFoundation\Response` class, allowing for broader and custom response types. ## [7.5.1](https://github.com/auth0/laravel-auth0/tree/7.5.1) (2023-04-04) diff --git a/src/Auth0.php b/src/Auth0.php index 11ec49e8..cf4872dc 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -25,7 +25,7 @@ final class Auth0 implements ServiceContract * * @var string */ - public const VERSION = '7.5.1'; + public const VERSION = '7.5.2'; public function __construct( private ?SDKContract $sdk = null, From 844b6c939dc275effbcd214097732c95c32023e8 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 11 Apr 2023 12:39:37 -0500 Subject: [PATCH 299/525] fix: legacyGuardUserMethod should use `$session` not `$token` (#365) --- src/Auth/Guard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index b5500ed5..a6beb186 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -581,7 +581,7 @@ public function user(): ?Authenticatable $session = $this->find(self::SOURCE_SESSION); if ($session instanceof Credential) { - $this->login($token, self::SOURCE_SESSION); + $this->login($session, self::SOURCE_SESSION); return $this->getCredential()?->getUser(); } From 4f7a770cb5da912b2274a149b30dc17976dd802d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 11 Apr 2023 14:44:00 -0500 Subject: [PATCH 300/525] feature: Add guard assignment helper middleware (#362) --- README.md | 88 +++++++++++++++++----- src/Auth/Guard.php | 5 +- src/Http/Middleware/Guard.php | 47 ++++++++++++ src/ServiceProvider.php | 6 +- tests/Unit/Http/Middleware/GuardTest.php | 95 ++++++++++++++++++++++++ tests/Unit/ServiceProviderTest.php | 14 ++-- 6 files changed, 226 insertions(+), 29 deletions(-) create mode 100644 src/Http/Middleware/Guard.php create mode 100644 tests/Unit/Http/Middleware/GuardTest.php diff --git a/README.md b/README.md index 9eb1bf95..708bc4d0 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ auth0 apis create \ You will receive a response with details about your new API. -Please make a note of your new API's **identifier**. This will be required in the configuration step, and will be referred to as the `audience`. +Please make a note of your new API's **identifier**. This will be required in the configuration step and will be referred to as the `audience`. ### Configuring the SDK @@ -169,18 +169,22 @@ Find the `providers` section, and add a new provider to the `providers` array th The SDK provides routing controllers that handle the authentication flow for your application. Add these routes where most appropriate for your configuration. `routes/web.php` is a common location for many Laravel applications. ```php +name('login'); -Route::get('/logout', Logout::class)->name('logout'); -Route::get('/callback', Callback::class)->name('callback'); -``` +Route::middleware('guard:someGuardName')->group(function () { + Route::get('/login', Login::class)->name('login'); + Route::get('/logout', Logout::class)->name('logout'); + Route::get('/callback', Callback::class)->name('callback'); +}); -Please ensure requests for these routes are managed by an Auth0 guard configured by your application. +// Other routes... +``` -### Protecting Routes +### Routing Middleware -The SDK provides a series of routing middleware to help you secure your application's routes. Any routes you wish to protect should be wrapped in the appropriate middleware. +The SDK provides a collection of routing middleware to help you secure your application's routes. Any routes you wish to protect should be wrapped in the appropriate middleware. #### Stateful Applications @@ -189,10 +193,10 @@ The SDK provides a series of routing middleware to help you secure your applicat ```php Route::get('/required', function () { return view(/* Authenticated */); -})->middleware(['auth0.authenticate']); +})->middleware('auth0.authenticate'); ``` -**`auth0.authenticate.optional` allows anyone to access a route.** It will check if a user is logged in, and will make sure `Auth::user()` is available to the route if so. This is useful when you wish to display different content to logged-in users and guests. +**`auth0.authenticate.optional` allows anyone to access a route.** It will check if a user is logged in and will make sure `Auth::user()` is available to the route if so. This is useful when you wish to display different content to logged-in users and guests. ```php Route::get('/', function () { @@ -201,7 +205,7 @@ Route::get('/', function () { } return view(/* Guest */) -})->middleware(['auth0.authenticate.optional']); +})->middleware('auth0.authenticate.optional'); ``` #### Stateless Services @@ -211,11 +215,11 @@ Route::get('/', function () { ```php Route::get('/api/private', function () { return response()->json([ - 'message' => 'Hello from a private endpoint! You need to be authenticated to see this.', + 'message' => 'Hello from a private endpoint! You need to be authorized to see this.', 'authorized' => Auth::check(), 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, ], 200, [], JSON_PRETTY_PRINT); -})->middleware(['auth0.authorize']); +})->middleware(['auth0.authorize'); ``` **`auth0.authorize` can further require access tokens to have a specific scope.** If the scope is not present for the token, it will return a `403 Forbidden` response. @@ -223,27 +227,75 @@ Route::get('/api/private', function () { ```php Route::get('/api/private-scoped', function () { return response()->json([ - 'message' => 'Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.', + 'message' => 'Hello from a private endpoint! You need to be authorized and have a scope of read:messages to see this.', 'authorized' => Auth::check(), 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, ], 200, [], JSON_PRETTY_PRINT); -})->middleware(['auth0.authorize:read:messages']); +})->middleware('auth0.authorize:read:messages'); ``` -**`auth0.authorize.optional` allows anyone to access a route.** It will check if a valid access token is present, and will make sure `Auth::user()` is available to the route if so. This is useful when you wish to return different responses to authenticated and unauthenticated requests. +**`auth0.authorize.optional` allows anyone to access a route.** It will check if a valid access token is present and will make sure `Auth::user()` is available to the route if so. This is useful when you wish to return different responses to authenticated and unauthenticated requests. ```php Route::get('/api/public', function () { return response()->json([ - 'message' => 'Hello from a public endpoint! You don\'t need to be authenticated to see this.', + 'message' => 'Hello from a public endpoint! You don\'t need to be authorized to see this.', 'authorized' => Auth::check(), 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, ], 200, [], JSON_PRETTY_PRINT); -})->middleware(['auth0.authorize.optional']); +})->middleware('auth0.authorize.optional'); ```
+### Guard Assignment + +For the SDK to function, requests must be routed through a guard configured with the `auth0.guard` driver. This can be done in several ways. + +#### Default Guard + +You can set the `default` guard in your `config/auth.php` file to the guard you have configured for the SDK. + +```php + [ + 'guard' => 'someGuardName' + ], + + // ... +]; +``` + +#### Route Middleware + +As a convenience, the SDK provides a `guard` middleware that can be used to assign a specific guard to handle a route group. + +```php +group(function () { + Route::get('/example', \App\HtpController\Example::class)->name('example'); + // Other routes... +}); +``` + +#### AuthManager `shouldUse()` Method + +You can also use the `shouldUse()` method on the `AuthManager` to assign a specific guard. + +This is the equivalent of setting the `default` guard in your `config/auth.php` file, but can be done at runtime. + +```php +shouldUse('someGuardName'); + +Route::get('/example', \App\HttpController\Example::class)->name('example'); +// Other routes.. +``` + ## Support Policy Our support lifecycle mirrors the [Laravel release support](https://laravel.com/docs/releases#support-policy) and [PHP release support](https://www.php.net/supported-versions.php) schedules. diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index a6beb186..307fcc61 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -559,6 +559,9 @@ public function setUser( $this->pushState($credential); } + /** + * @codeCoverageIgnore + */ public function user(): ?Authenticatable { $legacyBehavior = config('auth0.behavior.legacyGuardUserMethod', true); @@ -568,7 +571,6 @@ public function user(): ?Authenticatable return $currentUser; } - // @codeCoverageIgnoreStart if (true === $legacyBehavior) { $token = $this->find(self::SOURCE_TOKEN); @@ -586,7 +588,6 @@ public function user(): ?Authenticatable return $this->getCredential()?->getUser(); } } - // @codeCoverageIgnoreFalse return null; } diff --git a/src/Http/Middleware/Guard.php b/src/Http/Middleware/Guard.php new file mode 100644 index 00000000..89724b2b --- /dev/null +++ b/src/Http/Middleware/Guard.php @@ -0,0 +1,47 @@ +defaultGuard = $guard; + } + } + + public function handle( + Request $request, + Closure $next, + ?string $guard = null, + ): Response { + $guard = trim($guard ?? ''); + + if ('' === $guard) { + auth()->shouldUse($this->defaultGuard); + + return $next($request); + } + + auth()->shouldUse($guard); + + return $next($request); + } +} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 4c05b0fb..e9448358 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -8,6 +8,7 @@ use Auth0\Laravel\Auth\User\{Provider, Repository}; use Auth0\Laravel\Contract\ServiceProvider as ServiceProviderContract; use Auth0\Laravel\Http\Controller\Stateful\{Callback, Login, Logout}; +use Auth0\Laravel\Http\Middleware\Guard as ShouldUseMiddleware; use Auth0\Laravel\Http\Middleware\Stateful\{Authenticate, AuthenticateOptional}; use Auth0\Laravel\Http\Middleware\Stateless\{Authorize, AuthorizeOptional}; use Auth0\Laravel\Store\LaravelSession; @@ -32,6 +33,7 @@ public function boot( $router->aliasMiddleware('auth0.authenticate', Authenticate::class); $router->aliasMiddleware('auth0.authorize.optional', AuthorizeOptional::class); $router->aliasMiddleware('auth0.authorize', Authorize::class); + $router->aliasMiddleware('guard', ShouldUseMiddleware::class); return $this; } @@ -50,7 +52,8 @@ public function provides() Login::class, Logout::class, Provider::class, - Repository::class + Repository::class, + ShouldUseMiddleware::class ]; } @@ -66,6 +69,7 @@ public function register(): self $this->app->singleton(Logout::class, static fn (): Logout => new Logout()); $this->app->singleton(Provider::class, static fn (): Provider => new Provider()); $this->app->singleton(Repository::class, static fn (): Repository => new Repository()); + $this->app->singleton(ShouldUseMiddleware::class, static fn (): ShouldUseMiddleware => new ShouldUseMiddleware()); $this->app->singleton('auth0', static fn (): Auth0 => app(Auth0::class)); $this->app->singleton('auth0.guard', static fn (): Guard => app(Guard::class)); diff --git a/tests/Unit/Http/Middleware/GuardTest.php b/tests/Unit/Http/Middleware/GuardTest.php new file mode 100644 index 00000000..a3ee7f36 --- /dev/null +++ b/tests/Unit/Http/Middleware/GuardTest.php @@ -0,0 +1,95 @@ +group('middleware', 'middleware.guard'); + +beforeEach(function (): void { + $this->laravel = app('auth0'); +}); + +it('assigns the guard for route handling', function (): void { + $routeNonexistentGuard = '/' . uniqid(); + $routeMiddlewareAssignedGuard = '/' . uniqid(); + $routeMiddlewareUnassignedGuard = '/' . uniqid(); + $routeUnspecifiedGuard = '/' . uniqid(); + + $defaultGuardClass = 'Illuminate\Auth\SessionGuard'; + $sdkGuardClass = 'Auth0\Laravel\Auth\Guard'; + + config(['auth.defaults.guard' => 'web']); + + Route::get($routeUnspecifiedGuard, function (): string { + return get_class(auth()->guard()); + }); + + Route::middleware('guard:nonexistent')->get($routeNonexistentGuard, function (): string { + return get_class(auth()->guard()); + }); + + Route::middleware('guard:testGuard')->get($routeMiddlewareAssignedGuard, function (): string { + return get_class(auth()->guard()); + }); + + Route::middleware('guard')->get($routeMiddlewareUnassignedGuard, function (): string { + return get_class(auth()->guard()); + }); + + $this->get($routeUnspecifiedGuard) + ->assertStatus(Response::HTTP_OK) + ->assertSee($defaultGuardClass); + + $this->get($routeNonexistentGuard) + ->assertStatus(Response::HTTP_INTERNAL_SERVER_ERROR); + + $this->get($routeMiddlewareAssignedGuard) + ->assertStatus(Response::HTTP_OK) + ->assertSee($sdkGuardClass); + + $this->get($routeUnspecifiedGuard) + ->assertStatus(Response::HTTP_OK) + ->assertSee($sdkGuardClass); + + $this->get($routeMiddlewareUnassignedGuard) + ->assertStatus(Response::HTTP_OK) + ->assertSee($defaultGuardClass); + + $this->get($routeUnspecifiedGuard) + ->assertStatus(Response::HTTP_OK) + ->assertSee($defaultGuardClass); +}); + +it('assigns the guard for route group handling', function (): void { + $routeMiddlewareUnassignedGuard = '/' . uniqid(); + $routeUnspecifiedGuard = '/' . uniqid(); + + $defaultGuardClass = 'Illuminate\Auth\SessionGuard'; + $sdkGuardClass = 'Auth0\Laravel\Auth\Guard'; + + config(['auth.defaults.guard' => 'web']); + + Route::middleware('guard:testGuard')->group(function () use ($routeUnspecifiedGuard, $routeMiddlewareUnassignedGuard) { + Route::get($routeUnspecifiedGuard, function (): string { + return get_class(auth()->guard()); + }); + + Route::middleware('guard')->get($routeMiddlewareUnassignedGuard, function (): string { + return get_class(auth()->guard()); + }); + }); + + $this->get($routeUnspecifiedGuard) + ->assertStatus(Response::HTTP_OK) + ->assertSee($sdkGuardClass); + + $this->get($routeMiddlewareUnassignedGuard) + ->assertStatus(Response::HTTP_OK) + ->assertSee($defaultGuardClass); + + $this->get($routeUnspecifiedGuard) + ->assertStatus(Response::HTTP_OK) + ->assertSee($sdkGuardClass); +}); diff --git a/tests/Unit/ServiceProviderTest.php b/tests/Unit/ServiceProviderTest.php index 5e564ff9..08507343 100644 --- a/tests/Unit/ServiceProviderTest.php +++ b/tests/Unit/ServiceProviderTest.php @@ -6,13 +6,10 @@ use Auth0\Laravel\Auth\User\Provider; use Auth0\Laravel\Auth\User\Repository; use Auth0\Laravel\Auth0; -use Auth0\Laravel\Http\Controller\Stateful\Callback; -use Auth0\Laravel\Http\Controller\Stateful\Login; -use Auth0\Laravel\Http\Controller\Stateful\Logout; -use Auth0\Laravel\Http\Middleware\Stateful\Authenticate; -use Auth0\Laravel\Http\Middleware\Stateful\AuthenticateOptional; -use Auth0\Laravel\Http\Middleware\Stateless\Authorize; -use Auth0\Laravel\Http\Middleware\Stateless\AuthorizeOptional; +use Auth0\Laravel\Http\Controller\Stateful\{Callback, Login, Logout}; +use Auth0\Laravel\Http\Middleware\Stateful\{Authenticate, AuthenticateOptional}; +use Auth0\Laravel\Http\Middleware\Stateless\{Authorize, AuthorizeOptional}; +use Auth0\Laravel\Http\Middleware\Guard as ShouldUseMiddleware; use Auth0\Laravel\Store\LaravelSession; uses()->group('service-provider'); @@ -33,7 +30,8 @@ Login::class, Logout::class, Provider::class, - Repository::class + Repository::class, + ShouldUseMiddleware::class ]); }); From 7eb6c6b39fdb9d3a56c5fd3747475444559b68d0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 12 Apr 2023 05:10:17 -0500 Subject: [PATCH 301/525] feature: Auth middleware will now setIntendedUrl() before login redirect (#364) --- src/Http/Middleware/Stateful/Authenticate.php | 4 +++- tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Http/Middleware/Stateful/Authenticate.php b/src/Http/Middleware/Stateful/Authenticate.php index d3f12569..09fd9481 100644 --- a/src/Http/Middleware/Stateful/Authenticate.php +++ b/src/Http/Middleware/Stateful/Authenticate.php @@ -47,6 +47,8 @@ public function handle( abort(Response::HTTP_FORBIDDEN, 'Forbidden'); } - return redirect()->to(config('auth0.routes.login', 'login')); // @phpstan-ignore-line + return redirect() + ->setIntendedUrl($request->fullUrl()) + ->to(config('auth0.routes.login', 'login')); // @phpstan-ignore-line } } diff --git a/tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php b/tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php index 51f04516..03a97caa 100644 --- a/tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php +++ b/tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php @@ -67,6 +67,9 @@ $this->get($route) ->assertRedirect($config['auth0.routes.login']); + expect(redirect()->getIntendedUrl()) + ->toEqual('http://localhost/' . $route); + expect($this->guard) ->user()->toBeNull(); }); From 9a2e1b0959787f3090018df080b9017789ec0f2d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 12 Apr 2023 11:44:27 -0500 Subject: [PATCH 302/525] Cleanup CHANGELOG formatting --- CHANGELOG.ARCHIVE.md | 389 ++++++++++++++++--------------------------- CHANGELOG.md | 122 +++++++------- 2 files changed, 198 insertions(+), 313 deletions(-) diff --git a/CHANGELOG.ARCHIVE.md b/CHANGELOG.ARCHIVE.md index 6091cedc..147b9436 100644 --- a/CHANGELOG.ARCHIVE.md +++ b/CHANGELOG.ARCHIVE.md @@ -1,152 +1,120 @@ -# Changelog < 7.0.0 +# Changelog Archive -## [6.5.0](https://github.com/auth0/laravel-auth0/tree/6.5.0) (2021-10-15) +This file contains changes for all versions of this package prior to the latest major, 7.0. -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.4.1...6.5.0) +The changelog for the latest changes is [CHANGELOG.md](./CHANGELOG.md). -**Added** +## [6.5.0](https://github.com/auth0/laravel-auth0/tree/6.5.0) (2021-10-15) -- Add SDK alias methods for passwordless endpoints [\#228](https://github.com/auth0/laravel-auth0/pull/228) ([evansims](https://github.com/evansims)) +### Added -## [6.4.1](https://github.com/auth0/laravel-auth0/tree/6.4.0) (2021-08-02) +- Add SDK alias methods for passwordless endpoints [\#228](https://github.com/auth0/laravel-auth0/pull/228) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.4.0...6.4.1) +## [6.4.1](https://github.com/auth0/laravel-auth0/tree/6.4.0) (2021-08-02) -**Fixed** +### Fixed -- Use the fully qualified facade class names [\#215](https://github.com/auth0/laravel-auth0/pull/215) ([Rezouce](https://github.com/Rezouce)) -- Update auth0-PHP dependency [\#222](https://github.com/auth0/laravel-auth0/pull/222) ([evansims](https://github.com/evansims)) -- Pass api_identifier config as audience to Auth0\SDK\Auth0 [\#214](https://github.com/auth0/laravel-auth0/pull/214) ([iSerter](https://github.com/iSerter)) +- Use the fully qualified facade class names [\#215](https://github.com/auth0/laravel-auth0/pull/215) +- Update auth0-PHP dependency [\#222](https://github.com/auth0/laravel-auth0/pull/222) +- Pass api_identifier config as audience to Auth0\SDK\Auth0 [\#214](https://github.com/auth0/laravel-auth0/pull/214) ## [6.4.0](https://github.com/auth0/laravel-auth0/tree/6.4.0) (2021-03-25) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.3.0...6.4.0) - -**Changed** +### Improved -- Add support for Auth0 Organizations [\#209](https://github.com/auth0/laravel-auth0/pull/209) ([evansims](https://github.com/evansims)) +- Add support for Auth0 Organizations [\#209](https://github.com/auth0/laravel-auth0/pull/209) ## [6.3.0](https://github.com/auth0/laravel-auth0/tree/6.3.0) (2020-02-18) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.2.0...6.3.0) +### Improved -**Changed** +- Store changes made to the user object during the onLogin event hook [\#206](https://github.com/auth0/laravel-auth0/pull/206) -- Store changes made to the user object during the onLogin event hook [\#206](https://github.com/auth0/laravel-auth0/pull/206) ([evansims](https://github.com/evansims)) +### Fixed -**Fixed** - -- Avoid throwing an error when calling getUserByUserInfo() during login callback event when the supplied profile is empty/null [\#207](https://github.com/auth0/laravel-auth0/pull/207) ([evansims](https://github.com/evansims)) +- Avoid throwing an error when calling getUserByUserInfo() during login callback event when the supplied profile is empty/null [\#207](https://github.com/auth0/laravel-auth0/pull/207) ## [6.2.0](https://github.com/auth0/laravel-auth0/tree/6.2.0) (2020-01-15) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.1.0...6.2.0) - -**Added** +### Added -- Support PHP 8.0 [\#200](https://github.com/auth0/laravel-auth0/pull/200) ([evansims](https://github.com/evansims)) +- Support PHP 8.0 [\#200](https://github.com/auth0/laravel-auth0/pull/200) -**Fixed** +### Fixed -- Fix the missing `return null;` in `getUserByIdentifier` [\#201](https://github.com/auth0/laravel-auth0/pull/201) ([sebwas](https://github.com/sebwas)) +- Fix the missing `return null;` in `getUserByIdentifier` [\#201](https://github.com/auth0/laravel-auth0/pull/201) ## [6.1.0](https://github.com/auth0/laravel-auth0/tree/6.1.0) (2020-09-17) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.0.1...6.1.0) - -**Added** +### Added -- Support Laravel 8 [\#190](https://github.com/auth0/laravel-auth0/pull/190) ([giannidhooge](https://github.com/giannidhooge)) +- Support Laravel 8 [\#190](https://github.com/auth0/laravel-auth0/pull/190) -**Fixed** +### Fixed -- Fix composer.json whitespace issue [\#192](https://github.com/auth0/laravel-auth0/pull/192) ([jimmyjames](https://github.com/jimmyjames)) +- Fix composer.json whitespace issue [\#192](https://github.com/auth0/laravel-auth0/pull/192) ## [6.0.1](https://github.com/auth0/laravel-auth0/tree/6.0.1) (2020-04-28) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.0.0...6.0.1) +### Fixed -**Fixed** - -- Fix access token decoding and validation [\#183](https://github.com/auth0/laravel-auth0/pull/183) ([jimmyjames](https://github.com/jimmyjames)) +- Fix access token decoding and validation [\#183](https://github.com/auth0/laravel-auth0/pull/183) ## [6.0.0](https://github.com/auth0/laravel-auth0/tree/6.0.0) (2020-04-09) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.4.0...6.0.0) - **This is a major release and includes breaking changes!** This release also includes a major version change for the PHP SDK that it relies on. Please see the [migration guide](https://github.com/auth0/auth0-PHP/blob/master/MIGRATE-v5-TO-v7.md) for the PHP SDK for more information. -**Closed issues** +### Added - auth0-PHP 7.0 - State and nonce handling [\#163](https://github.com/auth0/laravel-auth0/issues/163) -- Cannot use actingAs unit tests functionality [\#161](https://github.com/auth0/laravel-auth0/issues/161) - -**Added** - -- Implement auth0 guard [\#166](https://github.com/auth0/laravel-auth0/pull/166) ([Tamrael](https://github.com/Tamrael)) +- Implement auth0 guard [\#166](https://github.com/auth0/laravel-auth0/pull/166) -**Changed** +### Improved -- Use array for Auth0JWTUser and add repo return types [\#176](https://github.com/auth0/laravel-auth0/pull/176) ([joshcanhelp](https://github.com/joshcanhelp)) -- Update PHP SDK to v7.0.0 [\#162](https://github.com/auth0/laravel-auth0/pull/162) ([joshcanhelp](https://github.com/joshcanhelp)) -- Bind SessionState handler interface in container [\#147](https://github.com/auth0/laravel-auth0/pull/147) ([nstapelbroek](https://github.com/nstapelbroek)) +- Use array for Auth0JWTUser and add repo return types [\#176](https://github.com/auth0/laravel-auth0/pull/176) +- Update PHP SDK to v7.0.0 [\#162](https://github.com/auth0/laravel-auth0/pull/162) +- Bind SessionState handler interface in container [\#147](https://github.com/auth0/laravel-auth0/pull/147) -**Fixed** +### Fixed -- Fix Laravel session management [\#174](https://github.com/auth0/laravel-auth0/pull/174) ([joshcanhelp](https://github.com/joshcanhelp)) +- Fix Laravel session management [\#174](https://github.com/auth0/laravel-auth0/pull/174) +- Cannot use actingAs unit tests functionality [\#161](https://github.com/auth0/laravel-auth0/issues/161) ## [5.4.0](https://github.com/auth0/laravel-auth0/tree/5.4.0) (2020-03-27) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.3.1...5.4.0) +### Added -**Closed issues** +- Laravel 7 support [\#167](https://github.com/auth0/laravel-auth0/pull/167) -- Laravel 7.0 supported release. [\#171](https://github.com/auth0/laravel-auth0/issues/171) +### Fixed -**Fixed** - -- Fixed PHPDocs [\#170](https://github.com/auth0/laravel-auth0/pull/170) ([YAhiru](https://github.com/YAhiru)) - -**Added** - -- Laravel 7 support [\#167](https://github.com/auth0/laravel-auth0/pull/167) ([giannidhooge](https://github.com/giannidhooge)) +- Laravel 7.0 supported release. [\#171](https://github.com/auth0/laravel-auth0/issues/171) +- Fixed PHPDocs [\#170](https://github.com/auth0/laravel-auth0/pull/170) ## [5.3.1](https://github.com/auth0/laravel-auth0/tree/5.3.1) (2019-11-14) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.3.0...5.3.1) - -**Closed issues** +### Fixed - Setting of state_handler in Auth0Service causes "Invalid state" error [\#154](https://github.com/auth0/laravel-auth0/issues/154) - -**Fixed** - -- Allow store and state_handler to be passed in from config [\#156](https://github.com/auth0/laravel-auth0/pull/156) ([joshcanhelp](https://github.com/joshcanhelp)) -- Add 'persist_refresh_token' key to laravel-auth0 configuration file. [\#152](https://github.com/auth0/laravel-auth0/pull/152) ([tpenaranda](https://github.com/tpenaranda)) -- Replace `setEnvironment` with `setEnvProperty` [\#145](https://github.com/auth0/laravel-auth0/pull/145) ([nstapelbroek](https://github.com/nstapelbroek)) +- Allow store and state_handler to be passed in from config [\#156](https://github.com/auth0/laravel-auth0/pull/156) +- Add 'persist_refresh_token' key to laravel-auth0 configuration file. [\#152](https://github.com/auth0/laravel-auth0/pull/152) +- Replace `setEnvironment` with `setEnvProperty` [\#145](https://github.com/auth0/laravel-auth0/pull/145) ## [5.3.0](https://github.com/auth0/laravel-auth0/tree/5.3.0) (2019-09-26) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.2.0...5.3.0) - -**Closed issues** +### Added +- Support Laravel 6 [\#139](https://github.com/auth0/laravel-auth0/pull/139) - Feature request: Add Laravel 6 support [\#138](https://github.com/auth0/laravel-auth0/issues/138) -- SessionStateHandler should use LaravelSessionStore not SessionStore [\#125](https://github.com/auth0/laravel-auth0/issues/125) -**Added** +### Fixed -- Support Laravel 6 [\#139](https://github.com/auth0/laravel-auth0/pull/139) ([FreekVR](https://github.com/FreekVR)) - -**Fixed** - -- Use LaravelSessionStore in the SessionStateHandler. [\#135](https://github.com/auth0/laravel-auth0/pull/135) ([nstapelbroek](https://github.com/nstapelbroek)) +- Use LaravelSessionStore in the SessionStateHandler. [\#135](https://github.com/auth0/laravel-auth0/pull/135) +- SessionStateHandler should use LaravelSessionStore not SessionStore [\#125](https://github.com/auth0/laravel-auth0/issues/125) ## [5.2.0](https://github.com/auth0/laravel-auth0/tree/5.2.0) (2019-06-27) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.1.0...5.2.0) - -**Closed issues** +### Added - Authenticate as a Laravel API user using the Auth0 token [\#129](https://github.com/auth0/laravel-auth0/issues/129) - Redirect to previous page after login [\#122](https://github.com/auth0/laravel-auth0/issues/122) @@ -160,316 +128,239 @@ - [Bug] Inconsistencies with the singleton Auth0Service [\#103](https://github.com/auth0/laravel-auth0/issues/103) - How do you combine Auth0 Lock with Laravel Auth0? [\#102](https://github.com/auth0/laravel-auth0/issues/102) - OnLogin callback question [\#97](https://github.com/auth0/laravel-auth0/issues/97) - -**Added** - - Add composer.lock file [\#123](https://github.com/auth0/laravel-auth0/pull/123) ([lbalmaceda](https://github.com/lbalmaceda)) -**Changed** +### Improved -- Change private properties to protected [\#132](https://github.com/auth0/laravel-auth0/pull/132) ([joshcanhelp](https://github.com/joshcanhelp)) -- Return null instead of false in Auth0UserProvider. [\#128](https://github.com/auth0/laravel-auth0/pull/128) ([afreakk](https://github.com/afreakk)) -- Change the visibility of the getter method from private to public [\#121](https://github.com/auth0/laravel-auth0/pull/121) ([irieznykov](https://github.com/irieznykov)) -- Updated required PHP version to 5.4 in composer [\#118](https://github.com/auth0/laravel-auth0/pull/118) ([dmyers](https://github.com/dmyers)) -- Changed arrays to use short array syntax [\#110](https://github.com/auth0/laravel-auth0/pull/110) ([dmyers](https://github.com/dmyers)) +- Change private properties to protected [\#132](https://github.com/auth0/laravel-auth0/pull/132) +- Return null instead of false in Auth0UserProvider. [\#128](https://github.com/auth0/laravel-auth0/pull/128) +- Change the visibility of the getter method from private to public [\#121](https://github.com/auth0/laravel-auth0/pull/121) +- Updated required PHP version to 5.4 in composer [\#118](https://github.com/auth0/laravel-auth0/pull/118) +- Changed arrays to use short array syntax [\#110](https://github.com/auth0/laravel-auth0/pull/110) -**Fixed** +### Fixed -- Fix cachehandler resolving issues [\#131](https://github.com/auth0/laravel-auth0/pull/131) ([deviouspk](https://github.com/deviouspk)) -- Added the Auth0Service as a singleton through the classname [\#107](https://github.com/auth0/laravel-auth0/pull/107) ([JCombee](https://github.com/JCombee)) -- Fixed typo [\#106](https://github.com/auth0/laravel-auth0/pull/106) ([IvanArjona](https://github.com/IvanArjona)) +- Fix cachehandler resolving issues [\#131](https://github.com/auth0/laravel-auth0/pull/131) +- Added the Auth0Service as a singleton through the classname [\#107](https://github.com/auth0/laravel-auth0/pull/107) +- Fixed typo [\#106](https://github.com/auth0/laravel-auth0/pull/106) ## [5.1.0](https://github.com/auth0/laravel-auth0/tree/5.1.0) (2018-03-20) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.0.2...5.1.0) - -**Closed issues** - -- pls change config arg name [\#95](https://github.com/auth0/laravel-auth0/issues/95) - -**Added** +### Added - AutoDiscovery [\#91](https://github.com/auth0/laravel-auth0/pull/91) ([m1guelpf](https://github.com/m1guelpf)) -- Added guzzle options to config to allow for connection options [\#88](https://github.com/auth0/laravel-auth0/pull/88) ([mjmgooch](https://github.com/mjmgooch)) +- Added guzzle options to config to allow for connection options [\#88](https://github.com/auth0/laravel-auth0/pull/88) -**Changed** +### Improved -- Change default settings file [\#96](https://github.com/auth0/laravel-auth0/pull/96) ([joshcanhelp](https://github.com/joshcanhelp)) -- Utilise Auth0->Login to ensure state validation [\#90](https://github.com/auth0/laravel-auth0/pull/90) ([cocojoe](https://github.com/cocojoe)) +- Change default settings file [\#96](https://github.com/auth0/laravel-auth0/pull/96) +- Utilise Auth0->Login to ensure state validation [\#90](https://github.com/auth0/laravel-auth0/pull/90) -**Fixed** +### Fixed -- Make code comments gender neutral [\#98](https://github.com/auth0/laravel-auth0/pull/98) ([devjack](https://github.com/devjack)) -- Fix README and CHANGELOG [\#99](https://github.com/auth0/laravel-auth0/pull/99) ([joshcanhelp](https://github.com/joshcanhelp)) +- Make code comments gender neutral [\#98](https://github.com/auth0/laravel-auth0/pull/98) +- Fix README and CHANGELOG [\#99](https://github.com/auth0/laravel-auth0/pull/99) +- pls change config arg name [\#95](https://github.com/auth0/laravel-auth0/issues/95) ## [5.0.2](https://github.com/auth0/laravel-auth0/tree/5.0.2) (2017-08-30) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.0.1...5.0.2) - -**Merged pull requests:** +### Fixed -- Use instead of to identify the Auth0 user [\#80](https://github.com/auth0/laravel-auth0/pull/80) ([glena](https://github.com/glena)) +- Use instead of to identify the Auth0 user [\#80](https://github.com/auth0/laravel-auth0/pull/80) ## [5.0.1](https://github.com/auth0/laravel-auth0/tree/5.0.1) (2017-02-23) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/5.0.0...5.0.1) - -Fixed `supported_algs` configuration name +### Fixed +- Fixed `supported_algs` configuration name ## [5.0.0](https://github.com/auth0/laravel-auth0/tree/5.0.0) (2017-02-22) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.8...5.0.0) - -**Merged pull requests:** +### Fixed -- V5: update to auth0 sdk v5 [\#69](https://github.com/auth0/laravel-auth0/pull/69) ([glena](https://github.com/glena)) +- V5: update to auth0 sdk v5 [\#69](https://github.com/auth0/laravel-auth0/pull/69) ## [4.0.8](https://github.com/auth0/laravel-auth0/tree/4.0.8) (2017-01-27) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.7...4.0.8) - -**Closed issues** +### Fixed - Allow use of RS256 Protocol [\#63](https://github.com/auth0/wp-auth0/issues/63) - Add RS256 to the list of supported algorithms [\#62](https://github.com/auth0/wp-auth0/issues/62) - -**Merged pull requests:** - -- allow to configure the algorithm supported for token verification [\#65](https://github.com/auth0/laravel-auth0/pull/65) ([glena](https://github.com/glena)) +- allow to configure the algorithm supported for token verification [\#65](https://github.com/auth0/laravel-auth0/pull/65) ## [4.0.7](https://github.com/auth0/laravel-auth0/tree/4.0.7) (2017-01-02) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.6...4.0.7) +### Fixed -**Merged pull requests:** - -- it should pass all the configs to the oauth client [\#64](https://github.com/auth0/laravel-auth0/pull/64) ([glena](https://github.com/glena)) +- it should pass all the configs to the oauth client [\#64](https://github.com/auth0/laravel-auth0/pull/64) ## [4.0.6](https://github.com/auth0/laravel-auth0/tree/4.0.6) (2016-11-29) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.5...4.0.6) - -**Merged pull requests:** +### Fixed -- Code style & docblocks [\#56](https://github.com/auth0/laravel-auth0/pull/56) ([seanmangar](https://github.com/seanmangar)) -- Adding accessor to retrieve JWT from Auth0Service [\#58](https://github.com/auth0/laravel-auth0/pull/58) ([ryantology](https://github.com/ryantology)) +- Code style & docblocks [\#56](https://github.com/auth0/laravel-auth0/pull/56) +- Adding accessor to retrieve JWT from Auth0Service [\#58](https://github.com/auth0/laravel-auth0/pull/58) ## [4.0.5](https://github.com/auth0/laravel-auth0/tree/4.0.5) (2016-11-29) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.4...4.0.5) +### Fixed -**Merged pull requests:** - -- Added flag for not encoded tokens + removed example [\#57](https://github.com/auth0/laravel-auth0/pull/57) ([glena](https://github.com/glena)) +- Added flag for not encoded tokens + removed example [\#57](https://github.com/auth0/laravel-auth0/pull/57) ## [4.0.4](https://github.com/auth0/laravel-auth0/tree/4.0.4) (2016-11-25) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.2...4.0.4) - -**Merged pull requests:** +### Fixed -- Fixing config type [\#55](https://github.com/auth0/laravel-auth0/pull/55) ([adamgoose](https://github.com/adamgoose)) +- Fixing config type [\#55](https://github.com/auth0/laravel-auth0/pull/55) ## [4.0.2](https://github.com/auth0/laravel-auth0/tree/4.0.2) (2016-10-03) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.1...4.0.2) - -**Merged pull requests:** +### Fixed -- Fixing JWTVerifier [\#54](https://github.com/auth0/laravel-auth0/pull/54) ([adamgoose](https://github.com/adamgoose)) +- Fixing JWTVerifier [\#54](https://github.com/auth0/laravel-auth0/pull/54) ## [4.0.1](https://github.com/auth0/laravel-auth0/tree/4.0.1) (2016-09-19) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/4.0.0...4.0.1) +### Fixed -**Merged pull requests:** - -- fix error becuase of contract and class with the same name [\#52](https://github.com/auth0/laravel-auth0/pull/52) ([glena](https://github.com/glena)) +- Fix error becuase of contract and class with the same name [\#52](https://github.com/auth0/laravel-auth0/pull/52) ## [4.0.0](https://github.com/auth0/laravel-auth0/tree/4.0.0) (2016-09-15) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.2.1...4.0.0) +### Improved -Better support for Laravel 5.3: Support for Laravel Passport for token verification +- Better support for Laravel 5.3: Support for Laravel Passport for token verification Support of auth0 PHP sdk v4 with JWKs cache -**Merged pull requests:** +### Fixed -- Merge pull request #50 from auth0/4.x.x-dev [\#50](https://github.com/auth0/laravel-auth0/pull/50) ([glena](https://github.com/glena)) +- Merge pull request #50 from auth0/4.x.x-dev [\#50](https://github.com/auth0/laravel-auth0/pull/50) ## [3.2.1](https://github.com/auth0/laravel-auth0/tree/3.2.1) (2016-09-12) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.2.0...3.2.1) - -**Merged pull requests:** +### Fixed -- Fix for Laravel 5.2 [\#49](https://github.com/auth0/laravel-auth0/pull/49) ([dscafati](https://github.com/dscafati)) +- Fix for Laravel 5.2 [\#49](https://github.com/auth0/laravel-auth0/pull/49) ## [3.2.0](https://github.com/auth0/laravel-auth0/tree/3.2.0) (2016-07-11) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.1.0...3.2.0) +### Fixed -**Merged pull requests:** - -- New optional jwt middleware [\#40](https://github.com/auth0/laravel-auth0/pull/40) ([glena](https://github.com/glena)) +- New optional jwt middleware [\#40](https://github.com/auth0/laravel-auth0/pull/40) ## [3.1.0](https://github.com/auth0/laravel-auth0/tree/3.1.0) (2016-05-02) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.3...3.1.0) - -**Merged pull requests:** +### Fixed -- 3.1.0 [\#36](https://github.com/auth0/laravel-auth0/pull/36) ([glena](https://github.com/glena)) +- 3.1.0 [\#36](https://github.com/auth0/laravel-auth0/pull/36) ## [3.0.3](https://github.com/auth0/laravel-auth0/tree/3.0.3) (2016-01-28) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.2...3.0.3) - -**Closed issues:** +### Fixed - Tag 2.2.2 breaks on Laravel 5.1 [\#30](https://github.com/auth0/laravel-auth0/issues/30) - -**Merged pull requests:** - -- Conform to 5.2's Authenticatable contract [\#31](https://github.com/auth0/laravel-auth0/pull/31) ([ryannjohnson](https://github.com/ryannjohnson)) +- Conform to 5.2's Authenticatable contract [\#31](https://github.com/auth0/laravel-auth0/pull/31) ## [3.0.2](https://github.com/auth0/laravel-auth0/tree/3.0.2) (2016-01-25) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.2.1...3.0.2) +### Fixed -**Merged pull requests:** - -- Added optional persistence configuration values [\#29](https://github.com/auth0/laravel-auth0/pull/29) ([carnevalle](https://github.com/carnevalle)) +- Added optional persistence configuration values [\#29](https://github.com/auth0/laravel-auth0/pull/29) ## [2.2.1](https://github.com/auth0/laravel-auth0/tree/2.2.1) (2016-01-22) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.1...2.2.1) - -**Closed issues:** +### Fixed - Create a logout route [\#25](https://github.com/auth0/laravel-auth0/issues/25) - -**Merged pull requests:** - -- Auth0 SDK checks for null values instead of false [\#27](https://github.com/auth0/laravel-auth0/pull/27) ([thijsvdanker](https://github.com/thijsvdanker)) +- Auth0 SDK checks for null values instead of false [\#27](https://github.com/auth0/laravel-auth0/pull/27) ## [3.0.1](https://github.com/auth0/laravel-auth0/tree/3.0.1) (2016-01-18) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/3.0.0...3.0.1) +### Fixed -**Merged pull requests:** - -- updated auth0-php dependency [\#24](https://github.com/auth0/laravel-auth0/pull/24) ([glena](https://github.com/glena)) +- updated auth0-php dependency [\#24](https://github.com/auth0/laravel-auth0/pull/24) ## [3.0.0](https://github.com/auth0/laravel-auth0/tree/3.0.0) (2016-01-06) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.2.0...3.0.0) - -**Closed issues:** +### Fixed - auth0/auth0-php ~1.0 requirement doesn't support latest GuzzleHttp [\#21](https://github.com/auth0/laravel-auth0/issues/21) - -**Merged pull requests:** - -- updated to be compatible with laravel 5.2 [\#23](https://github.com/auth0/laravel-auth0/pull/23) ([glena](https://github.com/glena)) +- updated to be compatible with laravel 5.2 [\#23](https://github.com/auth0/laravel-auth0/pull/23) ## [2.2.0](https://github.com/auth0/laravel-auth0/tree/2.2.0) (2015-11-30) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.4...2.2.0) - -**Merged pull requests:** +### Fixed -- updated auth0-php dependency version [\#22](https://github.com/auth0/laravel-auth0/pull/22) ([glena](https://github.com/glena)) -- Update login.blade.php [\#20](https://github.com/auth0/laravel-auth0/pull/20) ([Annyv2](https://github.com/Annyv2)) +- updated auth0-php dependency version [\#22](https://github.com/auth0/laravel-auth0/pull/22) +- Update login.blade.php [\#20](https://github.com/auth0/laravel-auth0/pull/20) ## [2.1.4](https://github.com/auth0/laravel-auth0/tree/2.1.4) (2015-10-27) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.3...2.1.4) +### Fixed -**Merged pull requests:** - -- Middleware contract has been deprecated in 5.1 [\#19](https://github.com/auth0/laravel-auth0/pull/19) ([thijsvdanker](https://github.com/thijsvdanker)) -- Fixed some typo's in the comments. [\#18](https://github.com/auth0/laravel-auth0/pull/18) ([thijsvdanker](https://github.com/thijsvdanker)) -- Removed note about unstable dependency from README [\#17](https://github.com/auth0/laravel-auth0/pull/17) ([thijsvdanker](https://github.com/thijsvdanker)) -- Update composer instructions [\#16](https://github.com/auth0/laravel-auth0/pull/16) ([iWader](https://github.com/iWader)) -- Use a tagged release of adoy/oauth2 [\#15](https://github.com/auth0/laravel-auth0/pull/15) ([thijsvdanker](https://github.com/thijsvdanker)) +- Middleware contract has been deprecated in 5.1 [\#19](https://github.com/auth0/laravel-auth0/pull/19) +- Fixed some typo's in the comments. [\#18](https://github.com/auth0/laravel-auth0/pull/18) +- Removed note about unstable dependency from README [\#17](https://github.com/auth0/laravel-auth0/pull/17) +- Update composer instructions [\#16](https://github.com/auth0/laravel-auth0/pull/16) +- Use a tagged release of adoy/oauth2 [\#15](https://github.com/auth0/laravel-auth0/pull/15) ## [2.1.3](https://github.com/auth0/laravel-auth0/tree/2.1.3) (2015-07-17) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.2...2.1.3) - -**Merged pull requests:** +### Fixed -- updated jwt dependency [\#14](https://github.com/auth0/laravel-auth0/pull/14) ([glena](https://github.com/glena)) +- updated jwt dependency [\#14](https://github.com/auth0/laravel-auth0/pull/14) ## [2.1.2](https://github.com/auth0/laravel-auth0/tree/2.1.2) (2015-05-15) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.1...2.1.2) +### Fixed -**Merged pull requests:** - -- Added override of info headers [\#13](https://github.com/auth0/laravel-auth0/pull/13) ([glena](https://github.com/glena)) +- Added override of info headers [\#13](https://github.com/auth0/laravel-auth0/pull/13) ## [2.1.1](https://github.com/auth0/laravel-auth0/tree/2.1.1) (2015-05-12) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.1.0...2.1.1) - -**Closed issues:** +### Fixed - SDK Client headers spec compliant [\#11](https://github.com/auth0/laravel-auth0/issues/11) - Support for Laravel 5? [\#6](https://github.com/auth0/laravel-auth0/issues/6) - -**Merged pull requests:** - -- SDK Client headers spec compliant \#11 [\#12](https://github.com/auth0/laravel-auth0/pull/12) ([glena](https://github.com/glena)) +- SDK Client headers spec compliant \#11 [\#12](https://github.com/auth0/laravel-auth0/pull/12) ## [2.1.0](https://github.com/auth0/laravel-auth0/tree/2.1.0) (2015-05-07) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/2.0.0...2.1.0) - -**Merged pull requests:** +### Fixed -- Upgrade to auth-php 1.0.0: Added support to API V2 [\#10](https://github.com/auth0/laravel-auth0/pull/10) ([glena](https://github.com/glena)) +- Upgrade to auth-php 1.0.0: Added support to API V2 [\#10](https://github.com/auth0/laravel-auth0/pull/10) ## [2.0.0](https://github.com/auth0/laravel-auth0/tree/2.0.0) (2015-04-20) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.8...2.0.0) +### Fixed -**Merged pull requests:** - -- Package V2 for Laravel5 [\#9](https://github.com/auth0/laravel-auth0/pull/9) ([glena](https://github.com/glena)) +- Package V2 for Laravel5 [\#9](https://github.com/auth0/laravel-auth0/pull/9) ## [1.0.8](https://github.com/auth0/laravel-auth0/tree/1.0.8) (2015-04-14) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.7...1.0.8) +- [Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.7...1.0.8) ## [1.0.7](https://github.com/auth0/laravel-auth0/tree/1.0.7) (2015-04-13) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.6...1.0.7) - -**Merged pull requests:** +### Fixed -- Fixed the way the access token is pased to the A0User [\#7](https://github.com/auth0/laravel-auth0/pull/7) ([glena](https://github.com/glena)) -- Update README.md [\#5](https://github.com/auth0/laravel-auth0/pull/5) ([pose](https://github.com/pose)) +- Fixed the way the access token is pased to the A0User [\#7](https://github.com/auth0/laravel-auth0/pull/7) +- Update README.md [\#5](https://github.com/auth0/laravel-auth0/pull/5) ## [1.0.6](https://github.com/auth0/laravel-auth0/tree/1.0.6) (2014-08-01) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.5...1.0.6) +- [Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.5...1.0.6) ## [1.0.5](https://github.com/auth0/laravel-auth0/tree/1.0.5) (2014-08-01) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.4...1.0.5) - -**Closed issues:** +### Fixed - Problem with normal laravel user table [\#4](https://github.com/auth0/laravel-auth0/issues/4) - -**Merged pull requests:** - -- Update README.md [\#3](https://github.com/auth0/laravel-auth0/pull/3) ([patekuru](https://github.com/patekuru)) +- Update README.md [\#3](https://github.com/auth0/laravel-auth0/pull/3) ## [1.0.4](https://github.com/auth0/laravel-auth0/tree/1.0.4) (2014-05-07) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.3...1.0.4) +- [Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.3...1.0.4) ## [1.0.3](https://github.com/auth0/laravel-auth0/tree/1.0.3) (2014-04-21) + +- [Full Changelog](https://github.com/auth0/laravel-auth0/compare/1.0.0...1.0.3) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c107a2d..fe492bed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,15 +2,35 @@ ## [Unreleased] +### Added + +- `Auth0\Laravel\Http\Middleware\Guard`, new middleware that forces Laravel to route requests through a group using a specific Guard. ([\#362](https://github.com/auth0/laravel-auth0/pull/362)) + +### Improved + +- `Auth0\Laravel\Http\Middleware\Stateful\Authenticate` now remembers the intended route (using `redirect()->setIntendedUrl()`) before kicking off authentication flow redirect. Users will be returned to the memorized intended route after completing their authentication flow. ([\#364](https://github.com/auth0/laravel-auth0/pull/364)) + +### Fixed + +- legacyGuardUserMethod behavior should use `$session`, not `$token` ([\#353](https://github.com/auth0/laravel-auth0/pull/365)) + +## [7.6.0](https://github.com/auth0/laravel-auth0/tree/7.6.0) (2023-04-10) + +### Added + +### Fixed + +- legacyGuardUserMethod behavior should use `$session`, not `$token` ([\#353](https://github.com/auth0/laravel-auth0/pull/365)) + ## [7.5.2](https://github.com/auth0/laravel-auth0/tree/7.5.2) (2023-04-10) -**Fixed** +### Fixed - Relaxed response types from middleware to use low-level `Symfony\Component\HttpFoundation\Response` class, allowing for broader and custom response types. ## [7.5.1](https://github.com/auth0/laravel-auth0/tree/7.5.1) (2023-04-04) -**Fixed** +### Fixed - Resolved an issue wherein custom user repositories could fail to be instantiated under certain circumstances. @@ -18,13 +38,13 @@ This release includes support for Laravel 10, and major improvements to the internal state handling mechanisms of the SDK. -**Added** +### Added - Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) - New `Auth0\Laravel\Traits\Imposter` trait to allow for easier testing. [Example usage](./tests/Unit/Traits/ImpersonateTest.php) - New Exception types have been added for more precise error catching. -**Changed** +### Improved The following changes have no effect on the external API of this package, but may affect internal usage. - `Guard` will now more reliably detect changes in the underlying Auth0-PHP SDK session state. @@ -35,114 +55,88 @@ The following changes have no effect on the external API of this package, but ma - The HTTP middleware have been refactored to more clearly differentiate between token and session based identities. - The `authenticate`, `authenticate.optional` and `authorize.optional` HTTP middleware now support scope filtering, as `authorize` already did. -**Fixed** +- Upgraded test suite to use PEST 2.0 framework. +- Updated test coverage to 100%. + +### Fixed - A 'Session store not set on request' error could occur when downstream applications implemented unit testing that use the Guard. This should be resolved now. - `Guard` would not always honor the `provider` configuration value in `config/auth.php`. - `Guard` is no longer defined as a Singleton to better support applications that need multi-guard configurations. -**Maintenance** +### Notes -- Upgraded test suite to use PEST 2.0 framework. -- Updated test coverage to 100%. - -**Important Notes** - -**1. Changes to `user()` behavior** +#### Changes to `user()` behavior This release includes a significant behavior change around the `user()` method of the Guard. Previously, by simply invoking the method, the SDK would search for any available credential (access token, device session, etc.) and automatically assign the user within the Guard. The HTTP middleware have been upgraded to handle the user assignment step, and `user()` now only returns the current state of user assignment without altering it. A new property has been added to the `config/auth0.php` configuration file: `behavior`. This is an array. At this time, there is a single option: `legacyGuardUserMethod`, a bool. If this value is set to true, or if the key is missing, the previously expected behavior will be applied, and `user()` will behave as it did before this release. The property defaults to `false`. -**2. Changes to Guard and Provider driver aliases** +#### Changes to Guard and Provider driver aliases We identified an issue with using identical alias naming for both the Guard and Provider singletons under Laravel 10, which has required us to rename these aliases. As previous guidance had been to instantiate these using their class names, this should not be a breaking change in most cases. However, if you had used `auth0` as the name for either the Guard or the Provider drivers, kindly note that these have changed. Please use `auth0.guard` for the Guard driver, and `auth0.provider` for the Provider driver. This is a regrettable change, but was necessary for adequate Laravel 10 support. -Thanks to our contributors for this release: [taida957789](https://github.com/taida957789) - ## [7.4.0](https://github.com/auth0/laravel-auth0/tree/7.4.0) (2022-12-12) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.3.0...7.4.0) - -**Added** +### Added -- feat: Add `Auth0\Laravel\Event\Middleware\...` event hooks [\#340](https://github.com/auth0/laravel-auth0/pull/340) ([evansims](https://github.com/evansims)) -- feat: Add `Auth0\Laravel\Event\Configuration\Building` event hook [\#339](https://github.com/auth0/laravel-auth0/pull/339) ([evansims](https://github.com/evansims)) +- feat: Add `Auth0\Laravel\Event\Middleware\...` event hooks [\#340](https://github.com/auth0/laravel-auth0/pull/340) +- feat: Add `Auth0\Laravel\Event\Configuration\Building` event hook [\#339](https://github.com/auth0/laravel-auth0/pull/339) ## [7.3.0](https://github.com/auth0/laravel-auth0/tree/7.3.0) (2022-11-07) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.2.2...7.3.0) +### Added -**Added** +- add: Raise additional Laravel Auth Events [\#331](https://github.com/auth0/laravel-auth0/pull/331) -- add: Raise additional Laravel Auth Events [\#331](https://github.com/auth0/laravel-auth0/pull/331) ([evansims](https://github.com/evansims)) +### Fixed -**Fixed** - -- fix: `env()` incorrectly assigns `cookieExpires` to a `string` value [\#332](https://github.com/auth0/laravel-auth0/pull/332) ([evansims](https://github.com/evansims)) -- fix: Auth0\Laravel\Cache\LaravelCachePool::createItem returning a cache miss [\#329](https://github.com/auth0/laravel-auth0/pull/329) ([pkivits-litebit](https://github.com/pkivits-litebit)) +- fix: `env()` incorrectly assigns `cookieExpires` to a `string` value [\#332](https://github.com/auth0/laravel-auth0/pull/332) +- fix: Auth0\Laravel\Cache\LaravelCachePool::createItem returning a cache miss [\#329](https://github.com/auth0/laravel-auth0/pull/329) ## [7.2.2](https://github.com/auth0/laravel-auth0/tree/7.2.2) (2022-10-19) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.2.1...7.2.2) - -**Fixed** +### Fixed -- [SDK-3720] Restore `php artisan vendor:publish` command [\#321](https://github.com/auth0/laravel-auth0/pull/321) ([evansims](https://github.com/evansims)) -- [SDK-3721] Bump minimum `auth0/auth0-php` version to `^8.3.4` [\#322](https://github.com/auth0/laravel-auth0/pull/322) ([evansims](https://github.com/evansims)) +- Restore `php artisan vendor:publish` command [\#321](https://github.com/auth0/laravel-auth0/pull/321) +- Bump minimum `auth0/auth0-php` version to `^8.3.4` [\#322](https://github.com/auth0/laravel-auth0/pull/322) ## [7.2.1](https://github.com/auth0/laravel-auth0/tree/7.2.1) (2022-10-13) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.2.0...7.2.1) - -**Fixed** +### Fixed -- `Auth0\Laravel\Auth0` no longer requires a session configuration for stateless strategies, restoring previous behavior. [\#317](https://github.com/auth0/laravel-auth0/pull/317) ([evansims](https://github.com/evansims)) -- The SDK now requires `^3.0` of the `psr/cache` dependency, to accomodate breaking changes made in the upstream interface (typed parameters and return types) for PHP 8.0+. [\#316](https://github.com/auth0/laravel-auth0/pull/316) ([evansims](https://github.com/evansims)) +- `Auth0\Laravel\Auth0` no longer requires a session configuration for stateless strategies, restoring previous behavior. [\#317](https://github.com/auth0/laravel-auth0/pull/317) +- The SDK now requires `^3.0` of the `psr/cache` dependency, to accomodate breaking changes made in the upstream interface (typed parameters and return types) for PHP 8.0+. [\#316](https://github.com/auth0/laravel-auth0/pull/316) ## [7.2.0](https://github.com/auth0/laravel-auth0/tree/7.2.0) (2022-10-10) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.1.0...7.2.0) +### Improved -Thank you to [tonyfox-disguise](https://github.com/tonyfox-disguise), [jeovajr](https://github.com/jeovajr) and [nie7321](https://github.com/nie7321) for their contributions to this release. - -**Changed** - -- `Auth0\Laravel\Store\LaravelSession` has been added as the default `sessionStorage` and `transientStorage` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Session APIs](https://laravel.com/docs/9.x/session) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims))¹ -- `Auth0\Laravel\Cache\LaravelCachePool` and `Auth0\Laravel\Cache\LaravelCacheItem` have been added as the default `tokenCache` and `managementTokenCache` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Cache APIs](https://laravel.com/docs/9.x/cache) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) ([evansims](https://github.com/evansims)) -- `Auth0\Laravel\Auth\Guard` now supports the `viaRemember` method. [\#306](https://github.com/auth0/laravel-auth0/pull/306) ([tonyfox-disguise](https://github.com/tonyfox-disguise)) -- `Auth0\Laravel\Http\Middleware\Stateless\Authorize` now returns a 401 status instead of 403 for unauthenticated users. [\#304](https://github.com/auth0/laravel-auth0/issues/304) ([jeovajr](https://github.com/jeovajr)) +- `Auth0\Laravel\Store\LaravelSession` has been added as the default `sessionStorage` and `transientStorage` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Session APIs](https://laravel.com/docs/9.x/session) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307)¹ +- `Auth0\Laravel\Cache\LaravelCachePool` and `Auth0\Laravel\Cache\LaravelCacheItem` have been added as the default `tokenCache` and `managementTokenCache` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Cache APIs](https://laravel.com/docs/9.x/cache) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) +- `Auth0\Laravel\Auth\Guard` now supports the `viaRemember` method. [\#306](https://github.com/auth0/laravel-auth0/pull/306) +- `Auth0\Laravel\Http\Middleware\Stateless\Authorize` now returns a 401 status instead of 403 for unauthenticated users. [\#304](https://github.com/auth0/laravel-auth0/issues/304) - PHP 8.0 is now the minimum supported runtime version. Please review the [README](README.md) for more information on support windows. ¹ This change may require your application's users to re-authenticate. You can avoid this by changing the `sessionStorage` and `transientStorage` options in your SDK configuration to their previous default instances of `Auth0\SDK\Store\CookieStore`, but it is recommended you migrate to the new `LaravelSession` default. ## [7.1.0](https://github.com/auth0/laravel-auth0/tree/7.1.0) (2022-08-08) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.0.1...7.1.0) +### Improved -**Changed** +- Return interfaces instead of concrete classes [\#296](https://github.com/auth0/laravel-auth0/pull/296) +- change: Use class names for app() calls [\#291](https://github.com/auth0/laravel-auth0/pull/291) -- [SDK-3576] Return interfaces instead of concrete classes [\#296](https://github.com/auth0/laravel-auth0/pull/296) ([evansims](https://github.com/evansims)) -- change: Use class names for app() calls [\#291](https://github.com/auth0/laravel-auth0/pull/291) ([evansims](https://github.com/evansims)) +### Fixed -**Fixed** - -- [SDK-3585] Fix: `Missing Code` error on Callback Route for Octane Customers [\#297](https://github.com/auth0/laravel-auth0/pull/297) ([evansims](https://github.com/evansims)) +- Fix: `Missing Code` error on Callback Route for Octane Customers [\#297](https://github.com/auth0/laravel-auth0/pull/297) ## [7.0.1](https://github.com/auth0/laravel-auth0/tree/7.0.1) (2022-06-01) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.0.0...7.0.1) - -**Fixed** +### Fixed -- Fixed an issue in `Auth0\Laravel\Http\Controller\Stateful\Callback` where `$errorDescription`'s value was assigned an incorrect value when an error was encountered. [\#266](https://github.com/auth0/laravel-auth0/pull/288) ([evansims](https://github.com/evansims)) - -**Closed Issues** - -- Resolves [\#287](https://github.com/auth0/laravel-auth0/issues/287) ([piljac1](https://github.com/piljac1)) +- Fixed an issue in `Auth0\Laravel\Http\Controller\Stateful\Callback` where `$errorDescription`'s value was assigned an incorrect value when an error was encountered. [\#266](https://github.com/auth0/laravel-auth0/pull/288) ## [7.0.0](https://github.com/auth0/laravel-auth0/tree/7.0.0) (2022-03-21) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/6.5.0...7.0.0) - Auth0 Laravel SDK v7 includes many significant changes over previous versions: - Support for Laravel 9. @@ -153,7 +147,7 @@ Auth0 Laravel SDK v7 includes many significant changes over previous versions: As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes. Please review the [upgrade guide](UPGRADE.md) thoroughly to understand the changes required to migrate your application to v7. -**Breaking Changes Summary** +### Breaking Changes - Namespace has been updated from `Auth0\Login` to `Auth0\Laravel` - Auth0-PHP SDK dependency updated to V8 From 99102f7bea4e8519ce7056fa40136ab90d9b81d3 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 12 Apr 2023 11:44:59 -0500 Subject: [PATCH 303/525] Cleanup CHANGELOG formatting --- CHANGELOG.ARCHIVE.md | 3 ++- CHANGELOG.md | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.ARCHIVE.md b/CHANGELOG.ARCHIVE.md index 147b9436..23d2762d 100644 --- a/CHANGELOG.ARCHIVE.md +++ b/CHANGELOG.ARCHIVE.md @@ -171,6 +171,7 @@ The changelog for the latest changes is [CHANGELOG.md](./CHANGELOG.md). ## [5.0.1](https://github.com/auth0/laravel-auth0/tree/5.0.1) (2017-02-23) ### Fixed + - Fixed `supported_algs` configuration name ## [5.0.0](https://github.com/auth0/laravel-auth0/tree/5.0.0) (2017-02-22) @@ -229,7 +230,7 @@ The changelog for the latest changes is [CHANGELOG.md](./CHANGELOG.md). ### Improved - Better support for Laravel 5.3: Support for Laravel Passport for token verification -Support of auth0 PHP sdk v4 with JWKs cache + Support of auth0 PHP sdk v4 with JWKs cache ### Fixed diff --git a/CHANGELOG.md b/CHANGELOG.md index fe492bed..f1e59956 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ This release includes support for Laravel 10, and major improvements to the inte - New Exception types have been added for more precise error catching. ### Improved + The following changes have no effect on the external API of this package, but may affect internal usage. - `Guard` will now more reliably detect changes in the underlying Auth0-PHP SDK session state. @@ -67,11 +68,13 @@ The following changes have no effect on the external API of this package, but ma ### Notes #### Changes to `user()` behavior + This release includes a significant behavior change around the `user()` method of the Guard. Previously, by simply invoking the method, the SDK would search for any available credential (access token, device session, etc.) and automatically assign the user within the Guard. The HTTP middleware have been upgraded to handle the user assignment step, and `user()` now only returns the current state of user assignment without altering it. A new property has been added to the `config/auth0.php` configuration file: `behavior`. This is an array. At this time, there is a single option: `legacyGuardUserMethod`, a bool. If this value is set to true, or if the key is missing, the previously expected behavior will be applied, and `user()` will behave as it did before this release. The property defaults to `false`. #### Changes to Guard and Provider driver aliases + We identified an issue with using identical alias naming for both the Guard and Provider singletons under Laravel 10, which has required us to rename these aliases. As previous guidance had been to instantiate these using their class names, this should not be a breaking change in most cases. However, if you had used `auth0` as the name for either the Guard or the Provider drivers, kindly note that these have changed. Please use `auth0.guard` for the Guard driver, and `auth0.provider` for the Provider driver. This is a regrettable change, but was necessary for adequate Laravel 10 support. ## [7.4.0](https://github.com/auth0/laravel-auth0/tree/7.4.0) (2022-12-12) From 394e2649a8c02112cd9a743202c531dd9af282a5 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 12 Apr 2023 11:46:23 -0500 Subject: [PATCH 304/525] Cleanup CHANGELOG formatting --- CHANGELOG.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1e59956..bded945b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,14 +14,6 @@ - legacyGuardUserMethod behavior should use `$session`, not `$token` ([\#353](https://github.com/auth0/laravel-auth0/pull/365)) -## [7.6.0](https://github.com/auth0/laravel-auth0/tree/7.6.0) (2023-04-10) - -### Added - -### Fixed - -- legacyGuardUserMethod behavior should use `$session`, not `$token` ([\#353](https://github.com/auth0/laravel-auth0/pull/365)) - ## [7.5.2](https://github.com/auth0/laravel-auth0/tree/7.5.2) (2023-04-10) ### Fixed From e299f3eedb66b8c593d15f3bf9871a8b55ec625b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 12 Apr 2023 18:30:53 -0500 Subject: [PATCH 305/525] Release 7.6.0 (#367) --- .github/ISSUE_TEMPLATE/Bug Report.yml | 1 + CHANGELOG.md | 2 +- src/Auth0.php | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index 0bfc8fb6..dd05816e 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -22,6 +22,7 @@ body: label: SDK Version description: What version of our Laravel plugin are you running? (`composer show | grep auth0/login`) options: + - SDK 7.6 - SDK 7.5 - SDK 7.4 - SDK 7.3 diff --git a/CHANGELOG.md b/CHANGELOG.md index bded945b..d352d1ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [Unreleased] +## [7.6.0](https://github.com/auth0/laravel-auth0/tree/7.6.0) (2023-04-12) ### Added diff --git a/src/Auth0.php b/src/Auth0.php index cf4872dc..c72c6f35 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -25,7 +25,7 @@ final class Auth0 implements ServiceContract * * @var string */ - public const VERSION = '7.5.2'; + public const VERSION = '7.6.0'; public function __construct( private ?SDKContract $sdk = null, From ae4b1f7953132d854807ec53c04a7b9f627628db Mon Sep 17 00:00:00 2001 From: mikebrandl Date: Thu, 13 Apr 2023 17:57:30 +0100 Subject: [PATCH 306/525] Remove Incorrect Opening Brace (#368) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 708bc4d0..41005b1c 100644 --- a/README.md +++ b/README.md @@ -219,7 +219,7 @@ Route::get('/api/private', function () { 'authorized' => Auth::check(), 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, ], 200, [], JSON_PRETTY_PRINT); -})->middleware(['auth0.authorize'); +})->middleware('auth0.authorize'); ``` **`auth0.authorize` can further require access tokens to have a specific scope.** If the scope is not present for the token, it will return a `403 Forbidden` response. From 7326cfb52a1e6cd133c6a2b46ff6f11326722457 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Apr 2023 09:54:55 -0500 Subject: [PATCH 307/525] feature: Add `management()` to SDK service as a Management API convenience method (#376) --- src/Auth0.php | 6 ++++++ src/Contract/Auth0.php | 6 ++++++ tests/Unit/Auth0Test.php | 7 ++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Auth0.php b/src/Auth0.php index c72c6f35..0826d6c6 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -10,6 +10,7 @@ use Auth0\Laravel\Store\LaravelSession; use Auth0\SDK\Auth0 as SDK; use Auth0\SDK\Configuration\SdkConfiguration as Configuration; +use Auth0\SDK\Contract\API\ManagementInterface; use Auth0\SDK\Contract\Auth0Interface as SDKContract; use Auth0\SDK\Utility\HttpTelemetry; @@ -115,6 +116,11 @@ public function getSdk(): SDKContract return $this->setSdk(new SDK($this->getConfiguration())); } + public function management(): ManagementInterface + { + return $this->getSdk()->management(); + } + public function reset(): self { unset($this->sdk, $this->configuration); diff --git a/src/Contract/Auth0.php b/src/Contract/Auth0.php index 79c73271..6a944a0f 100644 --- a/src/Contract/Auth0.php +++ b/src/Contract/Auth0.php @@ -5,6 +5,7 @@ namespace Auth0\Laravel\Contract; use Auth0\SDK\Configuration\SdkConfiguration as Configuration; +use Auth0\SDK\Contract\API\ManagementInterface; use Auth0\SDK\Contract\Auth0Interface as SDK; interface Auth0 @@ -19,6 +20,11 @@ public function getConfiguration(): Configuration; */ public function getSdk(): SDK; + /** + * Returns an instance of the Management API class. + */ + public function management(): ManagementInterface; + /** * Resets and cleans up the internal state of the SDK. */ diff --git a/tests/Unit/Auth0Test.php b/tests/Unit/Auth0Test.php index 07842f27..d5af54a0 100644 --- a/tests/Unit/Auth0Test.php +++ b/tests/Unit/Auth0Test.php @@ -3,12 +3,17 @@ declare(strict_types=1); use Auth0\SDK\Contract\Auth0Interface as SdkContract; -use Auth0\Laravel\Auth0; use Auth0\SDK\Auth0 as SDKAuth0; use Auth0\SDK\Configuration\SdkConfiguration; +use Auth0\SDK\Contract\API\ManagementInterface; uses()->group('auth0'); +it('returns a Management API class', function (): void { + $laravel = app('auth0'); + expect($laravel->management())->toBeInstanceOf(ManagementInterface::class); +}); + it('can get/set the configuration', function (): void { $laravel = app('auth0'); expect($laravel->getConfiguration())->toBeInstanceOf(SdkConfiguration::class); From e4c3eeccc924cfe9ec115b6bfa3357378f319155 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Apr 2023 09:55:15 -0500 Subject: [PATCH 308/525] feature: Add `refreshUser()` method to Guard (#375) --- src/Auth/Guard.php | 21 ++++++++++ src/Contract/Auth/Guard.php | 5 +++ tests/Unit/Auth/GuardStatefulTest.php | 58 +++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 307fcc61..bf08443a 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -16,6 +16,7 @@ use Auth0\SDK\Contract\Auth0Interface; use Auth0\SDK\Exception\InvalidTokenException; use Auth0\SDK\Token; +use Auth0\SDK\Utility\HttpResponse; use Exception; use Illuminate\Auth\Events\{Login, Logout}; use Illuminate\Contracts\Auth\{Authenticatable, UserProvider}; @@ -559,6 +560,26 @@ public function setUser( $this->pushState($credential); } + public function refreshUser(): void { + if ($this->check()) { + $response = $this->getSdk()->authentication()->userInfo($this->getCredential()->getAccessToken()); + + if (HttpResponse::wasSuccessful($response)) { + $response = HttpResponse::decodeContent($response); + $user = $this->getProvider()->retrieveByCredentials($response); + + $this->pushState(CredentialConcrete::create( + user: $user, + idToken: $this->getCredential()->getIdToken(), + accessToken: $this->getCredential()->getAccessToken(), + accessTokenScope: $this->getCredential()->getAccessTokenScope(), + accessTokenExpiration: $this->getCredential()->getAccessTokenExpiration(), + refreshToken: $this->getCredential()->getRefreshToken(), + )); + } + } + } + /** * @codeCoverageIgnore */ diff --git a/src/Contract/Auth/Guard.php b/src/Contract/Auth/Guard.php index fa41415d..592cbfad 100644 --- a/src/Contract/Auth/Guard.php +++ b/src/Contract/Auth/Guard.php @@ -139,6 +139,11 @@ public function setUser( Authenticatable $user, ): void; + /** + * Query the /userinfo endpoint and update the currently authenticated user for the guard. + */ + public function refreshUser(): void; + /** * Returns the currently authenticated user for the guard, if available. */ diff --git a/tests/Unit/Auth/GuardStatefulTest.php b/tests/Unit/Auth/GuardStatefulTest.php index 36575e4d..736e1d38 100644 --- a/tests/Unit/Auth/GuardStatefulTest.php +++ b/tests/Unit/Auth/GuardStatefulTest.php @@ -6,8 +6,13 @@ use Auth0\Laravel\Entities\Credential; use Auth0\Laravel\Model\Stateful\User; use Auth0\SDK\Configuration\SdkConfiguration; +use Auth0\SDK\Exception\NetworkException; use Illuminate\Http\Response; use Illuminate\Support\Facades\Route; +use PsrMock\Psr18\Client as MockHttpClient; +use PsrMock\Psr17\RequestFactory as MockRequestFactory; +use PsrMock\Psr17\ResponseFactory as MockResponseFactory; +use PsrMock\Psr17\StreamFactory as MockStreamFactory; use function Pest\Laravel\getJson; @@ -199,6 +204,59 @@ ->get('refreshToken')->toBe($changedRefreshToken); }); +it('queries the /userinfo endpoint for refreshUser()', function (): void { + $identifier = uniqid('auth0|'); + $idToken = uniqid('id-token-'); + $accessToken = uniqid('access-token-'); + $accessTokenScope = [uniqid('access-token-scope-')]; + $accessTokenExpiration = time() + 60; + + $this->session->set('user', ['sub' => $identifier]); + $this->session->set('idToken', $idToken); + $this->session->set('accessToken', $accessToken); + $this->session->set('accessTokenScope', $accessTokenScope); + $this->session->set('accessTokenExpiration', $accessTokenExpiration); + + $found = $this->guard->find(Guard::SOURCE_SESSION); + $this->guard->login($found, Guard::SOURCE_SESSION); + + expect($this->session) + ->get('user')->toBe(['sub' => $identifier]); + + $requestFactory = new MockRequestFactory; + $responseFactory = new MockResponseFactory; + $streamFactory = new MockStreamFactory; + + $response = $responseFactory->createResponse(200); + $response->getBody()->write(json_encode( + [ + 'sub' => $identifier, + 'name' => 'John Doe', + 'email' => '...', + ], + JSON_PRETTY_PRINT + )); + + $client = new MockHttpClient(fallbackResponse: $response); + + $this->config->setHttpRequestFactory($requestFactory); + $this->config->setHttpResponseFactory($responseFactory); + $this->config->setHttpStreamFactory($streamFactory); + $this->config->setHttpClient($client); + + $this->guard->refreshUser(); + + $userAttributes = $this->guard->user()->getAttributes(); + + expect($userAttributes) + ->toBeArray() + ->toHaveKeys(['sub', 'name', 'email']) + ->toHaveCount(3) + ->sub->toEqual($identifier) + ->name->toEqual('John Doe') + ->email->toEqual('...'); +}); + it('immediately invalidates an expired session when a refresh token is not available', function (): void { $this->session->set('accessTokenExpiration', time() - 1000); From 1076e9b6ce19dee36d23f5342dc061ff77f1eff2 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Apr 2023 10:12:32 -0500 Subject: [PATCH 309/525] Apply fixes for broken tests --- src/Auth/Guard.php | 53 +++++++++++++++++++++++-------------- src/Contract/Auth/Guard.php | 10 +++---- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index bf08443a..a8b5dd0b 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -532,6 +532,39 @@ public function processToken( } } + public function refreshUser(): void + { + if ($this->check()) { + $credential = $this->getCredential(); + $accessToken = $credential?->getAccessToken(); + + if (! $credential instanceof \Auth0\Laravel\Contract\Entities\Credential || null === $accessToken) { + return; + } + + $response = $this->getSdk()->authentication()->userInfo($accessToken); + + if (HttpResponse::wasSuccessful($response)) { + $response = HttpResponse::decodeContent($response); + + if (! is_array($response)) { + return; + } + + $user = $this->getProvider()->retrieveByCredentials($response); + + $this->pushState(CredentialConcrete::create( + user: $user, + idToken: $credential->getIdToken(), + accessToken: $credential->getAccessToken(), + accessTokenScope: $credential->getAccessTokenScope(), + accessTokenExpiration: $credential->getAccessTokenExpiration(), + refreshToken: $credential->getRefreshToken(), + )); + } + } + } + public function setCredential( ?Credential $credential = null, ?int $source = null, @@ -560,26 +593,6 @@ public function setUser( $this->pushState($credential); } - public function refreshUser(): void { - if ($this->check()) { - $response = $this->getSdk()->authentication()->userInfo($this->getCredential()->getAccessToken()); - - if (HttpResponse::wasSuccessful($response)) { - $response = HttpResponse::decodeContent($response); - $user = $this->getProvider()->retrieveByCredentials($response); - - $this->pushState(CredentialConcrete::create( - user: $user, - idToken: $this->getCredential()->getIdToken(), - accessToken: $this->getCredential()->getAccessToken(), - accessTokenScope: $this->getCredential()->getAccessTokenScope(), - accessTokenExpiration: $this->getCredential()->getAccessTokenExpiration(), - refreshToken: $this->getCredential()->getRefreshToken(), - )); - } - } - } - /** * @codeCoverageIgnore */ diff --git a/src/Contract/Auth/Guard.php b/src/Contract/Auth/Guard.php index 592cbfad..ab10c48e 100644 --- a/src/Contract/Auth/Guard.php +++ b/src/Contract/Auth/Guard.php @@ -110,6 +110,11 @@ public function processToken( string $token, ): ?array; + /** + * Query the /userinfo endpoint and update the currently authenticated user for the guard. + */ + public function refreshUser(): void; + /** * Sets the Guard's currently configured Credential and source. * @@ -139,11 +144,6 @@ public function setUser( Authenticatable $user, ): void; - /** - * Query the /userinfo endpoint and update the currently authenticated user for the guard. - */ - public function refreshUser(): void; - /** * Returns the currently authenticated user for the guard, if available. */ From c60326c461513cabe2c7382d6ba04b2acf0fbb69 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Apr 2023 10:25:05 -0500 Subject: [PATCH 310/525] documentation: Add Management API reference doc (#377) --- docs/Management API.md | 1315 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1315 insertions(+) create mode 100644 docs/Management API.md diff --git a/docs/Management API.md b/docs/Management API.md new file mode 100644 index 00000000..3b393d93 --- /dev/null +++ b/docs/Management API.md @@ -0,0 +1,1315 @@ +# Management API + +The Auth0 Laravel SDK provides easy-to-use methods to access Auth0's Management API endpoints. Nearly every endpoint of the Management API is available to use with your Laravel application. For more information about any of these endpoints, see the [Management API Explorer](https://auth0.com/docs/api/management/v2). + +## Accessing the Management API + +The Management API class can be accessed through the `management()` method on the Auth0 Laravel SDK service. You can pull the Auth0 SDK instance from the Laravel service container using dependency injection, or use the `Auth0` facade. Once you have an instance, you can call any of the [available endpoints](#available-endpoints). + +```php +$management = app('auth0')->management(); +``` + +## Available endpoints + +- [Actions](#actions) +- [Attack Protection](#attack-protection) +- [Blacklists](#blacklists) +- [ClientGrants](#client-grants) +- [Clients](#clients) +- [Connections](#connections) +- [Device Credentials](#device-credentials) +- [Emails](#emails) +- [Email Templates](#email-templates) +- [Grants](#grants) +- [Guardian](#guardian) +- [Jobs](#jobs) +- [Logs](#logs) +- [Log Streams](#log-streams) +- [Organizations](#organizations) +- [Resource Servers](#resource-servers) +- [Roles](#roles) +- [Rules](#rules) +- [Stats](#stats) +- [Tenants](#tenants) +- [Tickets](#tickets) +- [User Blocks](#user-blocks) +- [Users](#users) +- [Users by Email](#users-by-email) + +### Actions + +The [/api/v2/actions](https://auth0.com/docs/api/management/v2#!/Actions) endpoint class is accessible from the `actions()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| -------- | --------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | +| `GET` | […/actions/actions](https://auth0.com/docs/api/management/v2#!/Actions/get_actions) | `getAll()` | +| `POST` | […/actions/actions](https://auth0.com/docs/api/management/v2#!/Actions/post_action) | `create(body: [])` | +| `GET` | […/actions/actions/{id}](https://auth0.com/docs/api/management/v2#!/Actions/get_action) | `get(id: '...')` | +| `PATCH` | […/actions/actions/{id}](https://auth0.com/docs/api/management/v2#!/Actions/patch_action) | `update(id: '...', body: [])` | +| `DELETE` | […/actions/actions/{id}](https://auth0.com/docs/api/management/v2#!/Actions/delete_action) | `delete(id: '...')` | +| `POST` | […/actions/actions/{id}/test](https://auth0.com/docs/api/management/v2#!/Actions/post_test_action) | `test(id: '...')` | +| `POST` | […/actions/actions/{id}/deploy](https://auth0.com/docs/api/management/v2#!/Actions/post_deploy_action) | `deploy(id: '...')` | +| `GET` | […/actions/actions/{actionId}/versions](https://auth0.com/docs/api/management/v2#!/Actions/get_action_versions) | `getVersions(actionId: '...')` | +| `GET` | […/actions/actions/{actionId}/versions/{id}](https://auth0.com/docs/api/management/v2#!/Actions/get_action_version) | `getVersion(id: '...', actionId: '...')` | +| `POST` | […/actions/actions/{actionId}/versions/{id}/deploy](https://auth0.com/docs/api/management/v2#!/Actions/post_deploy_draft_version) | `rollbackVersion(id: '...', actionId: '...')` | +| `GET` | […/actions/executions/{id}](https://auth0.com/docs/api/management/v2#!/Actions/get_execution) | `getExecution(id: '...')` | +| `GET` | […/actions/triggers](https://auth0.com/docs/api/management/v2#!/Actions/get_triggers) | `getTriggers()` | +| `GET` | […/actions/triggers/{triggerId}/bindings](https://auth0.com/docs/api/management/v2#!/Actions/get_bindings) | `getTriggerBindings(triggerId: '...')` | +| `PATCH` | […/actions/triggers/{triggerId}/bindings](https://auth0.com/docs/api/management/v2#!/Actions/patch_bindings) | `updateTriggerBindings(triggerId: '...', body: [])` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Actions class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Actions.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$actions = $management->actions(); + +// Retrieves the first batch of results results. +$results = $actions->getAll(); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($actions->getResponsePaginator() as $action) { + // Do something with the action. +} +``` + +### Attack Protection + +The [/api/v2/attack-protection](https://auth0.com/docs/api/management/v2#!/Attack_Protection) endpoint class is accessible from the `attackProtection()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | +| `GET` | […/attack-protection/breached-password-detection](https://auth0.com/docs/api/management/v2#!/Attack_Protection/get_breached_password_detection) | `getBreachedPasswordDetection()` | +| `PATCH` | […/attack-protection/breached-password-detection](https://auth0.com/docs/api/management/v2#!/Attack_Protection/patch_breached_password_detection) | `updateBreachedPasswordDetection(body: [])` | +| `GET` | […/attack-protection/brute-force-protection](https://auth0.com/docs/api/management/v2#!/Attack_Protection/get_brute_force_protection) | `getBruteForceProtection()` | +| `PATCH` | […/attack-protection/brute-force-protection](https://auth0.com/docs/api/management/v2#!/Attack_Protection/patch_brute_force_protection) | `updateBruteForceProtection(body: [])` | +| `GET` | […/attack-protection/suspicious-ip-throttling](https://auth0.com/docs/api/management/v2#!/Attack_Protection/get_suspicious_ip_throttling) | `getSuspiciousIpThrottling()` | +| `PATCH` | […/attack-protection/suspicious-ip-throttling](https://auth0.com/docs/api/management/v2#!/Attack_Protection/patch_suspicious_ip_throttling) | `updateSuspiciousIpThrottling(body: [])` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\AttackProtection class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/AttackProtection.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$attackProtection = $management->attackProtection(); + +// Get the current configuration. +$response = $attackProtection->getBreachedPasswordDetection(); + +// Print the response body. +dd(HttpResponse::decode($response)); + +// { +// "enabled": true, +// "shields": [ +// "block", +// "admin_notification" +// ], +// "admin_notification_frequency": [ +// "immediately", +// "weekly" +// ], +// "method": "standard", +// "stage": { +// "pre-user-registration": { +// "shields": [ +// "block", +// "admin_notification" +// ] +// } +// } +// } +``` + +### Blacklists + +The [/api/v2/blacklists](https://auth0.com/docs/api/management/v2#!/Blacklists) endpoint class is accessible from the `blacklists()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| ------ | ---------------------------------------------------------------------------------------- | -------------------- | +| `GET` | […/blacklists/tokens](https://auth0.com/docs/api/management/v2#!/Blacklists/get_tokens) | `get()` | +| `POST` | […/blacklists/tokens](https://auth0.com/docs/api/management/v2#!/Blacklists/post_tokens) | `create(jti: '...')` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Blacklists class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Blacklists.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$blacklists = $management->blacklists(); + +$response = $blacklists->create('some-jti'); + +if ($response->getStatusCode() === 201) { + // Token was successfully blacklisted. + + // Retrieve all blacklisted tokens. + $results = $blacklists->get(); + + // You can then iterate (and auto-paginate) through all available results. + foreach ($blacklists->getResponsePaginator() as $blacklistedToken) { + // Do something with the blacklisted token. + } + + // Or, just work with the initial batch from the response. + dd(HttpResponse::decode($results)); + + // [ + // { + // "aud": "...", + // "jti": "some-jti" + // } + // ] +} +``` + +### Client Grants + +The [/api/v2/client-grants](https://auth0.com/docs/api/management/v2#!/Client_Grants) endpoint class is accessible from the `clientGrants()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| -------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------ | +| `GET` | […/client-grants](https://auth0.com/docs/api/management/v2#!/Client_Grants/get_client_grants) | `getAll()` | +| `GET` | […/client-grants](https://auth0.com/docs/api/management/v2#!/Client_Grants/get_client_grants) | `getAllByAudience(audience: '...')` | +| `GET` | […/client-grants](https://auth0.com/docs/api/management/v2#!/Client_Grants/get_client_grants) | `getAllByClientId(clientId: '...')` | +| `POST` | […/client-grants](https://auth0.com/docs/api/management/v2#!/Client_Grants/post_client_grants) | `create(clientId: '...', audience: '...')` | +| `PATCH` | […/client-grants/{id}](https://auth0.com/docs/api/management/v2#!/Client_Grants/patch_client_grants_by_id) | `update(grantId: '...')` | +| `DELETE` | […/client-grants/{id}](https://auth0.com/docs/api/management/v2#!/Client_Grants/delete_client_grants_by_id) | `delete(grantId: '...')` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\ClientGrants class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/ClientGrants.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$clientGrants = $management->clientGrants(); + +// Retrieves the first batch of results results. +$results = $clientGrants->getAll(); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($clientGrants->getResponsePaginator() as $clientGrant) { + // Do something with the client grant. +} + +// Or, just work with the initial batch from the response. +dd(HttpResponse::decode($results)); + +// [ +// { +// "id": "", +// "client_id": "", +// "audience": "", +// "scope": [ +// "" +// ] +// } +// ] +``` + +### Clients + +The [/api/v2/clients](https://auth0.com/docs/api/management/v2#!/Clients) endpoint class is accessible from the `clients()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| -------- | ----------------------------------------------------------------------------------------- | --------------------- | +| `GET` | […/clients](https://auth0.com/docs/api/management/v2#!/Clients/get_clients) | `getAll()` | +| `POST` | […/clients](https://auth0.com/docs/api/management/v2#!/Clients/post_clients) | `create(name: '...')` | +| `GET` | […/clients/{id}](https://auth0.com/docs/api/management/v2#!/Clients/get_clients_by_id) | `get(id: '...')` | +| `PATCH` | […/clients/{id}](https://auth0.com/docs/api/management/v2#!/Clients/patch_clients_by_id) | `update(id: '...')` | +| `DELETE` | […/clients/{id}](https://auth0.com/docs/api/management/v2#!/Clients/delete_clients_by_id) | `delete(id: '...')` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Clients class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Clients.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$clients = $management->clients(); + +// Retrieves the first batch of results results. +$results = $clients->getAll(); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($clients->getResponsePaginator() as $client) { + // Do something with the client. +} + +// Or, just work with the initial batch from the response. +dd(HttpResponse::decode($results)); + +// [ +// { +// "client_id": "", +// "tenant": "", +// "name": "", +// ... +// } +// ] +``` + +### Connections + +The [/api/v2/connections](https://auth0.com/docs/api/management/v2#!/Connections) endpoint class is accessible from the `connections()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| -------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------- | +| `GET` | […/connections](https://auth0.com/docs/api/management/v2#!/Connections/get_connections) | `getAll()` | +| `POST` | […/connections](https://auth0.com/docs/api/management/v2#!/Connections/post_connections) | `create(name: '...', strategy: '...')` | +| `GET` | […/connections/{id}](https://auth0.com/docs/api/management/v2#!/Connections/get_connections_by_id) | `get(id: '...')` | +| `PATCH` | […/connections/{id}](https://auth0.com/docs/api/management/v2#!/Connections/patch_connections_by_id) | `update(id: '...')` | +| `DELETE` | […/connections/{id}](https://auth0.com/docs/api/management/v2#!/Connections/delete_connections_by_id) | `delete(id: '...')` | +| `DELETE` | […/connections/{id}/users](https://auth0.com/docs/api/management/v2#!/Connections/delete_users_by_email) | `deleteUser(id: '...', email: '...')` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Connections class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Connections.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$connections = $management->connections(); + +// Retrieves the first batch of results results. +$results = $connections->getAll(); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($connections->getResponsePaginator() as $connection) { + // Do something with the connection. +} + +// Or, just work with the initial batch from the response. +dd(HttpResponse::decode($results)); + +// [ +// { +// "name": "", +// "display_name": "", +// "options": {}, +// "id": "", +// "strategy": "", +// "realms": [ +// "" +// ], +// "is_domain_connection": false, +// "metadata": {} +// } +// ] +``` + +### Device Credentials + +The [/api/v2/device-credentials](https://auth0.com/docs/api/management/v2#!/Device_Credentials) endpoint class is accessible from the `deviceCredentials()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| -------- | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | +| `GET` | […/device-credentials](https://auth0.com/docs/api/management/v2#!/Device_Credentials/get_device_credentials) | `get(userId: '...')` | +| `POST` | […/device-credentials](https://auth0.com/docs/api/management/v2#!/Device_Credentials/post_device_credentials) | `create(deviceName: '...', type: '...', value: '...', deviceId: '...')` | +| `DELETE` | […/device-credentials/{id}](https://auth0.com/docs/api/management/v2#!/Device_Credentials/delete_device_credential_by_id) | `delete(id: '...')` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\DeviceCredentials class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/DeviceCredentials.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$deviceCredentials = $management->deviceCredentials(); + +// Retrieves the first batch of results results. +$results = $deviceCredentials->get('user_id'); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($deviceCredentials->getResponsePaginator() as $deviceCredential) { + // Do something with the device credential. +} + +// Or, just work with the initial batch from the response. +dd(HttpResponse::decode($results)); + +// [ +// { +// "id": "", +// "device_name": "", +// "device_id": "", +// "type": "", +// "user_id": "", +// "client_id": "" +// } +// ] +``` + +### Emails + +The [/api/v2/emails](https://auth0.com/docs/api/management/v2#!/Emails) endpoint class is accessible from the `emails()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| -------- | -------------------------------------------------------------------------------------- | ---------------------------------------------- | +| `GET` | […/emails/provider](https://auth0.com/docs/api/management/v2#!/Emails/get_provider) | `getProvider()` | +| `POST` | […/emails/provider](https://auth0.com/docs/api/management/v2#!/Emails/post_provider) | `createProvider(name: '...', credentials: [])` | +| `PATCH` | […/emails/provider](https://auth0.com/docs/api/management/v2#!/Emails/patch_provider) | `updateProvider(name: '...', credentials: [])` | +| `DELETE` | […/emails/provider](https://auth0.com/docs/api/management/v2#!/Emails/delete_provider) | `deleteProvider()` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Emails class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Emails.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$endpoint = $management->emails(); + +// Configure the email provider. +$endpoint->createProvider( + name: 'smtp', + credentials: [ + 'smtp_host' => '...', + 'smtp_port' => 587, + 'smtp_user' => '...', + 'smtp_pass' => '...', + ], + body: [ + 'enabled' => true, + 'default_from_address' => 'sender@auth0.com', + ] +) + +// Retrieves the configuration of the email provider. +$provider = $endpoint->getProvider(); + +// Print the configuration. +dd(HttpResponse::decode($provider)); + +// { +// "name": "smtp", +// "enabled": true, +// "default_from_address": "sender@auth0.com", +// "credentials": { +// 'smtp_host' => '...', +// 'smtp_port' => 587, +// 'smtp_user' => '...', +// 'smtp_pass' => '...', +// }, +// "settings": {} +// } +``` + +### Email Templates + +The [/api/v2/email-templates](https://auth0.com/docs/api/management/v2#!/Email_Templates) endpoint class is accessible from the `emailTemplates()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| ------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- | +| `POST` | […/email-templates](https://auth0.com/docs/api/management/v2#!/Email_Templates/post_email_templates) | `create(template: '...', body: '...', from: '...', subject: '...', syntax: '...', enabled: true)` | +| `GET` | […/email-templates/{templateName}](https://auth0.com/docs/api/management/v2#!/Email_Templates/get_email_templates_by_templateName) | `get(templateName: '...')` | +| `PATCH` | […/email-templates/{templateName}](https://auth0.com/docs/api/management/v2#!/Email_Templates/patch_email_templates_by_templateName) | `update(templateName: '...', body: [])` | +| `PUT` | […/email-templates/{templateName}](https://auth0.com/docs/api/management/v2#!/Email_Templates/put_email_templates_by_templateName) | `update(templateName: '...', body: [])` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\EmailTemplates class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/EmailTemplates.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$templates = $management->emailTemplates(); + +// Create a new email template. +$templates->create( + template: 'verify_email', + body: '...', + from: 'sender@auth0.com', + subject: '...', + syntax: 'liquid', + enabled: true, +); + +// Retrieves the configuration of the email template. +$template = $templates->get(templateName: 'verify_email'); + +// Print the configuration. +dd(HttpResponse::decode($template)); + +// { +// "template": "verify_email", +// "body": "", +// "from": "sender@auth0.com", +// "resultUrl": "", +// "subject": "", +// "syntax": "liquid", +// "urlLifetimeInSeconds": 0, +// "includeEmailInRedirect": false, +// "enabled": false +// } +``` + +### Grants + +The [/api/v2/grants](https://auth0.com/docs/api/management/v2#!/Grants) endpoint class is accessible from the `grants()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| -------- | -------------------------------------------------------------------------------------- | ----------------------------------- | +| `GET` | […/grants](https://auth0.com/docs/api/management/v2#!/Grants/get_grants) | `getAll()` | +| `GET` | […/grants](https://auth0.com/docs/api/management/v2#!/Grants/get_grants) | `getAllByAudience(audience: '...')` | +| `GET` | […/grants](https://auth0.com/docs/api/management/v2#!/Grants/get_grants) | `getAllByClientId(clientId: '...')` | +| `GET` | […/grants](https://auth0.com/docs/api/management/v2#!/Grants/get_grants) | `getAllByUserId(userId: '...')` | +| `DELETE` | […/grants/{id}](https://auth0.com/docs/api/management/v2#!/Grants/delete_grants_by_id) | `delete(id: '...')` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Grants class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Grants.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$grants = $management->grants(); + +// Retrieves the first batch of grant results. +$results = $grants->getAll(); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($grants->getResponsePaginator() as $grant) { + // Do something with the device credential. +} + +// Or, just work with the initial batch from the response. +dd(HttpResponse::decode($results)); + +// [ +// { +// "id": "...", +// "clientID": "...", +// "user_id": "...", +// "audience": "...", +// "scope": [ +// "..." +// ], +// } +// ] +``` + +### Guardian + +The [/api/v2/guardian](https://auth0.com/docs/api/management/v2#!/Guardian) endpoint class is accessible from the `guardian()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| -------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------- | +| `GET` | […/guardian/enrollments/{id}](https://auth0.com/docs/api/management/v2#!/Guardian/get_enrollments_by_id) | `getEnrollment(id: '...')` | +| `DELETE` | […/guardian/enrollments/{id}](https://auth0.com/docs/api/management/v2#!/Guardian/delete_enrollments_by_id) | `deleteEnrollment(id: '...')` | +| `GET` | […/guardian/factors](https://auth0.com/docs/api/management/v2#!/Guardian/get_factors) | `getFactors()` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Guardian class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Guardian.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$guardian = $management->guardian(); + +// Retrieves the first batch of factor results. +$results = $guardian->getFactors(); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($guardian->getResponsePaginator() as $factor) { + // Do something with the device credential. + dump($factor); + + // { + // "enabled": true, + // "trial_expired": true, + // "name": "..." + // } +} + +// Or, just work with the initial batch from the response. +dd(HttpResponse::decode($results)); + +// [ +// { +// "enabled": true, +// "trial_expired": true, +// "name": "..." +// } +// ] +``` + +### Jobs + +The [/api/v2/jobs](https://auth0.com/docs/api/management/v2#!/Jobs) endpoint class is accessible from the `jobs()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| ------ | ---------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | +| `GET` | […/jobs/{id}](https://auth0.com/docs/api/management/v2#!/Jobs/get_jobs_by_id) | `get(id: '...')` | +| `GET` | […/jobs/{id}/errors](https://auth0.com/docs/api/management/v2#!/Jobs/get_errors) | `getErrors(id: '...')` | +| `POST` | […/jobs/users-exports](https://auth0.com/docs/api/management/v2#!/Jobs/post_users_exports) | `createExportUsersJob(body: [])` | +| `POST` | […/jobs/users-imports](https://auth0.com/docs/api/management/v2#!/Jobs/post_users_imports) | `createImportUsers(filePath: '...', connectionId: '...')` | +| `POST` | […/jobs/verification-email](https://auth0.com/docs/api/management/v2#!/Jobs/post_verification_email) | `createSendVerificationEmail(userId: '...')` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Jobs class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Jobs.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$connections = $management->connections(); +$jobs = $management->jobs(); + +// Create a connection. +$connection = $connections->create([ + 'name' => 'Test Connection', + 'strategy' => 'auth0', +]); + +if (! HttpResponse::wasSuccessful($job)) { + throw new \Exception('Connection creation failed.'); +} + +$connection = HttpResponse::decode($connection); + +// Create a new user export job. +$response = $jobs->createExportUsersJob([ + 'format' => 'json', + 'fields' => [ + ['name' => 'user_id'], + ['name' => 'name'], + ['name' => 'email'], + ['name' => 'identities[0].connection', "export_as": "provider"], + ['name' => 'user_metadata.some_field'], + ], + 'connection_id' => $connection['id'], +]); + +if ($response->getStatusCode() === 201) { + // The job was created successfully. Retrieve it's ID. + $jobId = HttpResponse::decode($response)['id']; + $job = null; + + while (true) { + // Get the job status. + $job = $jobs->get($jobId); + + if (! HttpResponse::wasSuccessful($job)) { + $job = null; + break; + } + + $job = HttpResponse::decode($job); + + // If the job is complete, break out of the loop. + if ($job['status'] === 'completed') { + break; + } + + // If the job has failed, break out of the loop. + if ($job['status'] === 'failed') { + $job = null + break; + } + + // Wait 1 second before checking the job status again. + sleep(1); + } + + if ($job === null) { + // The job failed. + $errors = $jobs->getErrors($jobId); + dd($errors); + } + + // The job completed successfully. Do something with the job. + dd($job); + + // Delete the connection. + $connections->delete($connection['id']); +} +``` + +### Logs + +The [/api/v2/logs](https://auth0.com/docs/api/management/v2#!/Logs) endpoint class is accessible from the `logs()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| ------ | ----------------------------------------------------------------------------- | ---------------- | +| `GET` | […/logs](https://auth0.com/docs/api/management/v2#!/Logs/get_logs) | `getAll()` | +| `GET` | […/logs/{id}](https://auth0.com/docs/api/management/v2#!/Logs/get_logs_by_id) | `get(id: '...')` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Logs class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Logs.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$logs = $management->logs(); + +// Retrieves the first batch of log results. +$results = $logs->getAll(); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($logs->getResponsePaginator() as $log) { + // Do something with the log. + dump($log); + + // { + // "date": "...", + // "type": "...", + // "description": "..." + // } +} + +// Or, just work with the initial batch from the response. +dd(HttpResponse::decode($results)); + +// [ +// { +// "date": "...", +// "type": "...", +// "description": "..." +// } +// ] +``` + +### Log Streams + +The [/api/v2/log-streams](https://auth0.com/docs/api/management/v2#!/Log_Streams) endpoint class is accessible from the `logStreams()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| -------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------- | +| `GET` | […/log-streams](https://auth0.com/docs/api/management/v2#!/Log_Streams/get_log_streams) | `getAll()` | +| `POST` | […/log-streams](https://auth0.com/docs/api/management/v2#!/Log_Streams/post_log_streams) | `create(type: '...', sink: '...')` | +| `GET` | […/log-streams/{id}](https://auth0.com/docs/api/management/v2#!/Log_Streams/get_log_streams_by_id) | `get(id: '...')` | +| `PATCH` | […/log-streams/{id}](https://auth0.com/docs/api/management/v2#!/Log_Streams/patch_log_streams_by_id) | `update(id: '...', body: [])` | +| `DELETE` | […/log-streams/{id}](https://auth0.com/docs/api/management/v2#!/Log_Streams/delete_log_streams_by_id) | `delete(id: '...')` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\LogStreams class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/LogStreams.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$logStreams = $management->logStreams(); + +// Create a new log stream. +$logStreams->create( + type: '...', + sink: [ + 'name' => '...', + ] +); + +// Get the first batch of log streams. +$results = $logStreams->getAll(); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($logStreams->getResponsePaginator() as $logStream) { + // Do something with the log stream. + dump($logStream); + + // { + // "id": "...", + // "name": "...", + // "type": "...", + // "status": "..." + // } +} + +// Or, just work with the initial batch from the response. +dd(HttpResponse::decode($results)); + +// [ +// { +// "id": "...", +// "name": "...", +// "type": "...", +// "status": "..." +// } +// ] +``` + +### Organizations + +The [/api/v2/organizations](https://auth0.com/docs/api/management/v2#!/Organizations) endpoint class is accessible from the `organizations()` method on the Management API class. + +| Method | Endpoint | SDK Method | +| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | +| `GET` | […/organizations](https://auth0.com/docs/api/management/v2#!/Organizations/get_organizations) | `getAll()` | +| `POST` | […/organizations](https://auth0.com/docs/api/management/v2#!/Organizations/post_organizations) | `create(name: '...', displayName: '...')` | +| `GET` | […/organizations/{id}](https://auth0.com/docs/api/management/v2#!/Organizations/get_organizations_by_id) | `get(id: '...')` | +| `PATCH` | […/organizations/{id}](https://auth0.com/docs/api/management/v2#!/Organizations/patch_organizations_by_id) | `update(id: '...', name: '...', displayName: '...')` | +| `DELETE` | […/organizations/{id}](https://auth0.com/docs/api/management/v2#!/Organizations/delete_organizations_by_id) | `delete(id: '...')` | +| `GET` | […/organizations/name/{name}](https://auth0.com/docs/api/management/v2#!/Organizations/get_name_by_name) | `getByName(name: '...')` | +| `GET` | […/organizations/{id}/members](https://auth0.com/docs/api/management/v2#!/Organizations/get_members) | `getMembers(id: '...')` | +| `POST` | […/organizations/{id}/members](https://auth0.com/docs/api/management/v2#!/Organizations/post_members) | `addMembers(id: '...', members: [])` | +| `DELETE` | […/organizations/{id}/members](https://auth0.com/docs/api/management/v2#!/Organizations/delete_members) | `removeMembers(id: '...', members: [])` | +| `GET` | […/organizations/{id}/invitations](https://auth0.com/docs/api/management/v2#!/Organizations/get_invitations) | `getInvitations(id: '...')` | +| `POST` | […/organizations/{id}/invitations](https://auth0.com/docs/api/management/v2#!/Organizations/post_invitations) | `createInvitation(id: '...', clientId: '...', inviter: '...', invitee: '...')` | +| `GET` | […/organizations/{id}/invitations/{invitationId}](https://auth0.com/docs/api/management/v2#!/Organizations/get_invitations_by_invitation_id) | `getInvitation(id: '...', invitationId: '...')` | +| `DELETE` | […/organizations/{id}/invitations/{invitationId}](https://auth0.com/docs/api/management/v2#!/Organizations/delete_invitations_by_invitation_id) | `deleteInvitation(id: '...', invitationId: '...')` | +| `GET` | […/organizations/{id}/enabled_connections](https://auth0.com/docs/api/management/v2#!/Organizations/get_enabled_connections) | `getEnabledConnections(id: '...')` | +| `POST` | […/organizations/{id}/enabled_connections](https://auth0.com/docs/api/management/v2#!/Organizations/post_enabled_connections) | `addEnabledConnection(id: '...', connectionId: '...', body: [])` | +| `GET` | […/organizations/{id}/enabled_connections/{connectionId}](https://auth0.com/docs/api/management/v2#!/Organizations/get_enabled_connections_by_connectionId) | `getEnabledConnection(id: '...', connectionId: '...')` | +| `PATCH` | […/organizations/{id}/enabled_connections/{connectionId}](https://auth0.com/docs/api/management/v2#!/Organizations/patch_enabled_connections_by_connectionId) | `updateEnabledConnection(id: '...' connectionId: '...', body: [])` | +| `DELETE` | […/organizations/{id}/enabled_connections/{connectionId}](https://auth0.com/docs/api/management/v2#!/Organizations/delete_enabled_connections_by_connectionId) | `removeEnabledConnection(id: '...', connectionId: '...')` | +| `GET` | […/organizations/{id}/members/{userId}/roles](https://auth0.com/docs/api/management/v2#!/Organizations/get_organization_member_roles) | `getMemberRoles(id: '...'. userId: '...')` | +| `POST` | […/organizations/{id}/members/{userId}/roles](https://auth0.com/docs/api/management/v2#!/Organizations/post_organization_member_roles) | `addMemberRoles(id: '...'. userId: '...', roles: [])` | +| `DELETE` | […/organizations/{id}/members/{userId}/roles](https://auth0.com/docs/api/management/v2#!/Organizations/delete_organization_member_roles) | `removeMemberRoles(id: '...'. userId: '...', roles: [])` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Organizations class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Organizations.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$organizations = $management->organizations(); + +// Get all organizations. +$results = $organizations->getAll(); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($logStreams->getResponsePaginator() as $logStream) { + // Do something with the log stream. + dump($logStream); + + // { + // "id": "", + // "name": "...", + // "display_name": "...", + // } +} + +// Or, just work with the initial batch from the response. +dd(HttpResponse::decode($results)); + +// [ +// { +// "id": "", +// "name": "...", +// "display_name": "...", +// ] + +// Get a single organization. +$results = $organizations->get('org_id'); + +// Create a new organization. +$results = $organizations->create('name', 'display_name'); + +// Update an existing organization. +$results = $organizations->update('org_id', 'name', 'display_name'); + +// Delete an organization. +$results = $organizations->delete('org_id'); + +// Get all members of an organization. +$results = $organizations->getMembers('org_id'); + +// Add members to an organization. +$results = $organizations->addMembers('org_id', ['user_id_1', 'user_id_2']); + +// Remove members from an organization. +$results = $organizations->removeMembers('org_id', ['user_id_1', 'user_id_2']); + +// Get all invitations for an organization. +$results = $organizations->getInvitations('org_id'); + +// Create a new invitation for an organization. +$results = $organizations->createInvitation('org_id', 'client_id', 'inviter_user_id', 'invitee_email'); + +// Get a single invitation for an organization. +$results = $organizations->getInvitation('org_id', 'invitation_id'); + +// Delete an invitation for an organization. +$results = $organizations->deleteInvitation('org_id', 'invitation_id'); + +// Get all enabled connections for an organization. +$results = $organizations->getEnabledConnections('org_id'); + +// Add a connection to an organization. +$results = $organizations->addEnabledConnection('org_id', 'connection_id', ['assign_membership_on_login' => true]); + +// Get a single enabled connection for an organization. +$results = $organizations->getEnabledConnection('org_id', 'connection_id'); + +// Update an enabled connection for an organization. +$results = $organizations->updateEnabledConnection('org_id', 'connection_id', ['assign_membership_on_login' => false]); + +// Remove a connection from an organization. +$results = $organizations->removeEnabledConnection('org_id', 'connection_id'); + +// Get all roles for a member of an organization. +$results = $organizations->getMemberRoles('org_id', 'user_id'); + +// Add roles to a member of an organization. +$results = $organizations->addMemberRoles('org_id', 'user_id', ['role_id_1', 'role_id_2']); + +// Remove roles from a member of an organization. +$results = $organizations->removeMemberRoles('org_id', 'user_id', ['role_id_1', 'role_id_2']); +``` + +### Resource Servers + +The [/api/v2/resource-servers](https://auth0.com/docs/api/management/v2#!/Resource_Servers) endpoint class is accessible from the `resourceServers()` method on the Management API class. + +| Method | Endpoint | PHP Method | +| -------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | +| `GET` | […/resource-servers](https://auth0.com/docs/api/management/v2#!/Resource_Servers/get_resource_servers) | `getAll()` | +| `POST` | […/resource-servers](https://auth0.com/docs/api/management/v2#!/Resource_Servers/post_resource_servers) | `create(identifier: '...', body: [])` | +| `GET` | […/resource-servers/{id}](https://auth0.com/docs/api/management/v2#!/Resource_Servers/get_resource_servers_by_id) | `get(id: '...')` | +| `PATCH` | […/resource-servers/{id}](https://auth0.com/docs/api/management/v2#!/Resource_Servers/patch_resource_servers_by_id) | `update(id: '...', body: '...')` | +| `DELETE` | […/resource-servers/{id}](https://auth0.com/docs/api/management/v2#!/Resource_Servers/delete_resource_servers_by_id) | `delete(id: '...')` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\ResourceServers class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/ResourceServers.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$resourceServers = $management->resourceServers(); + +// Create a new resource server. +$resourceServers->create( + identifier: 'https://my-resource-server.auth0.com/', + body: [ + 'name' => 'My Example API', + 'scopes' => [ + [ + 'value' => 'read:messages', + 'description' => 'Read messages', + ], + [ + 'value' => 'write:messages', + 'description' => 'Write messages', + ], + ], + ] +); + +// Get all resource servers. +$results = $resourceServers->getAll(); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($logStreams->getResponsePaginator() as $logStream) { + // Do something with the log stream. + dump($logStream); + + // { + // "id": "", + // "name": "", + // "is_system": false, + // "identifier": "", + // "scopes": [ + // "object" + // ], + // "signing_alg": "", + // "signing_secret": "", + // "allow_offline_access": false, + // "skip_consent_for_verifiable_first_party_clients": false, + // "token_lifetime": 0, + // "token_lifetime_for_web": 0, + // "enforce_policies": false, + // "token_dialect": "", + // "client": {} + // } +} + +// Or, just work with the initial batch from the response. +dd(HttpResponse::decode($results)); + +// [ +// { +// "id": "", +// "name": "", +// "is_system": false, +// "identifier": "", +// "scopes": [ +// "object" +// ], +// "signing_alg": "", +// "signing_secret": "", +// "allow_offline_access": false, +// "skip_consent_for_verifiable_first_party_clients": false, +// "token_lifetime": 0, +// "token_lifetime_for_web": 0, +// "enforce_policies": false, +// "token_dialect": "", +// "client": {} +// } +// ] +``` + +### Roles + +The [/api/v2/roles](https://auth0.com/docs/api/management/v2#!/Roles) endpoint class is accessible from the `roles()` method on the Management API class. + +| Method | Endpoint | PHP Method | +| -------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | +| `GET` | […/roles](https://auth0.com/docs/api/management/v2#!/Roles/get_roles) | `getAll()` | +| `POST` | […/roles](https://auth0.com/docs/api/management/v2#!/Roles/post_roles) | `create(name: '...', body: [])` | +| `GET` | […/roles/{id}](https://auth0.com/docs/api/management/v2#!/Roles/get_roles_by_id) | `get(id: '...')` | +| `PATCH` | […/roles/{id}](https://auth0.com/docs/api/management/v2#!/Roles/patch_roles_by_id) | `update(id: '...', body: [])` | +| `DELETE` | […/roles/{id}](https://auth0.com/docs/api/management/v2#!/Roles/delete_roles_by_id) | `delete(id: '...')` | +| `GET` | […/roles/{id}/users](https://auth0.com/docs/api/management/v2#!/Roles/get_role_user) | `getUsers(id: '...')` | +| `POST` | […/roles/{id}/users](https://auth0.com/docs/api/management/v2#!/Roles/post_role_users) | `addUsers(id: '...', users: [])` | +| `GET` | […/roles/{id}/permissions](https://auth0.com/docs/api/management/v2#!/Roles/get_role_permission) | `getPermissions(id: '...')` | +| `POST` | […/roles/{id}/permissions](https://auth0.com/docs/api/management/v2#!/Roles/post_role_permission_assignment) | `addPermissions(id: '...', permissions: [])` | +| `DELETE` | […/roles/{id}/permissions](https://auth0.com/docs/api/management/v2#!/Roles/delete_role_permission_assignment) | `removePermissions(id: '...', permissions: [])` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Roles class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Roles.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$roles = $management->roles(); + +// Create a new role. +$roles->create( + name: 'My Example Role', + body: [ + 'description' => 'This is an example role.', + ] +); + +// Get all roles. +$results = $roles->getAll(); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($logStreams->getResponsePaginator() as $logStream) { + // Do something with the log stream. + dump($logStream); + + // { + // "id": "", + // "name": "", + // "description": "", + // } +} + +// Or, just work with the initial batch from the response. +dd(HttpResponse::decode($results)); + +// [ +// { +// "id": "", +// "name": "", +// "description": "", +// } +// ] +``` + +### Rules + +The [/api/v2/rules](https://auth0.com/docs/api/management/v2#!/Rules) endpoint class is accessible from the `rules()` method on the Management API class. + +| Method | Endpoint | PHP Method | +| -------- | ----------------------------------------------------------------------------------- | ------------------------------------ | +| `GET` | […/rules](https://auth0.com/docs/api/management/v2#!/Rules/get_rules) | `getAll()` | +| `POST` | […/rules](https://auth0.com/docs/api/management/v2#!/Rules/post_rules) | `create(name: '...', script: '...')` | +| `GET` | […/rules/{id}](https://auth0.com/docs/api/management/v2#!/Rules/get_rules_by_id) | `get(id: '...')` | +| `PATCH` | […/rules/{id}](https://auth0.com/docs/api/management/v2#!/Rules/patch_rules_by_id) | `update(id: '...', body: [])` | +| `DELETE` | […/rules/{id}](https://auth0.com/docs/api/management/v2#!/Rules/delete_rules_by_id) | `delete(id: '...')` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Rules class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Rules.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$rules = $management->rules(); + +// Create a new rule. +$rules->create( + name: 'My Example Rule', + script: 'function (user, context, callback) { callback(null, user, context); }' +); + +// Get all rules. +$results = $rules->getAll(); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($logStreams->getResponsePaginator() as $logStream) { + // Do something with the log stream. + dump($logStream); + + // { + // "id": "", + // "name": "", + // "script": "", + // "enabled": true, + // "order": 0, + // "stage": "login_success", + // } +} + +// Or, just work with the initial batch from the response. +dd(HttpResponse::decode($results)); + +// [ +// { +// "id": "", +// "name": "", +// "script": "", +// "enabled": true, +// "order": 0, +// "stage": "login_success", +// } +// ] +``` + +### Stats + +The [/api/v2/stats](https://auth0.com/docs/api/management/v2#!/Stats) endpoint class is accessible from the `stats()` method on the Management API class. + +| Method | Endpoint | PHP Method | +| ------ | ----------------------------------------------------------------------------------------- | --------------------------------- | +| `GET` | […/stats/active-users](https://auth0.com/docs/api/management/v2#!/Stats/get_active_users) | `getActiveUsers()` | +| `GET` | […/stats/daily](https://auth0.com/docs/api/management/v2#!/Stats/get_active_users) | `getDaily(from: '...', to: '...)` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Stats class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Stats.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$stats = $management->stats(); + +// Retrieve the number of logins, signups and breached-password detections (subscription required) that occurred each day within a specified date range. +$results = $stats->getDaily(); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($stats->getResponsePaginator() as $metrics) { + // Do something with the log stream. + dump($logStream); + + // { + // "date": "...", + // "logins": 0, + // "signups": 0, + // "leaked_passwords": 0, + // "updated_at": "...", + // "created_at": "..." + // } +} + +// Or, just work with the initial batch from the response. +dd(HttpResponse::decode($results)); + +// [ +// { +// "date": "...", +// "logins": 0, +// "signups": 0, +// "leaked_passwords": 0, +// "updated_at": "...", +// "created_at": "..." +// } +// ] +``` + +### Tenants + +The [/api/v2/tenants](https://auth0.com/docs/api/management/v2#!/Tenants) endpoint class is accessible from the `tenants()` method on the Management API class. + +| Method | Endpoint | PHP Method | +| ------- | --------------------------------------------------------------------------------------- | -------------------------- | +| `GET` | […/tenants/settings](https://auth0.com/docs/api/management/v2#!/Tenants/get_settings) | `getSettings()` | +| `PATCH` | […/tenants/settings](https://auth0.com/docs/api/management/v2#!/Tenants/patch_settings) | `updateSettings(body: [])` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Tenants class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Tenants.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$tenants = $management->tenants(); + +// Retrieve the current tenant settings. +$results = $tenants->getSettings(); + +dd(HttpResponse::decode($results)); + +// { +// "change_password": { +// "enabled": false, +// "html": "" +// }, +// ... +// ... +// ... +// } +``` + +### Tickets + +The [/api/v2/tickets](https://auth0.com/docs/api/management/v2#!/Tickets) endpoint class is accessible from the `tickets()` method on the Management API class. + +| Method | Endpoint | PHP Method | +| ------ | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------- | +| `POST` | […/tickets/password-change](https://auth0.com/docs/api/management/v2#!/Tickets/post_password_change) | `createPasswordChange(body: [])` | +| `POST` | […/tickets/email-verification](https://auth0.com/docs/api/management/v2#!/Tickets/post_email_verification) | `createEmailVerification(userId: '...')` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\Tickets class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/Tickets.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$tickets = $management->tickets(); + +// Create a password change ticket. +$results = $tickets->createPasswordChange([ + 'result_url' => 'https://example.com/', + 'user_id' => '...', + 'client_id' => '...', + 'organization_id' => '...', + 'connection_id' => '...', + 'email' => '...', + 'ttl_sec' => 3600, + 'mark_email_as_verified' => true, + 'includeEmailInRedirect' => true, +]); + +dd(HttpResponse::decode($results)); + +// { +// "ticket": "https://login.auth0.com/lo/reset?..." +// } +``` + +### User Blocks + +The [/api/v2/user-blocks](https://auth0.com/docs/api/management/v2#!/User_Blocks) endpoint class is accessible from the `userBlocks()` method on the Management API class. + +| Method | Endpoint | PHP Method | +| -------- | ----------------------------------------------------------------------------------------------------- | --------------------------------------- | +| `GET` | […/user-blocks](https://auth0.com/docs/api/management/v2#!/User_Blocks/get_user_blocks) | `get(id: '...')` | +| `DELETE` | […/user-blocks](https://auth0.com/docs/api/management/v2#!/User_Blocks/delete_user_blocks) | `delete(id: '...')` | +| `GET` | […/user-blocks/{id}](https://auth0.com/docs/api/management/v2#!/User_Blocks/get_user_blocks_by_id) | `getByIdentifier(identifier: '...')` | +| `DELETE` | […/user-blocks/{id}](https://auth0.com/docs/api/management/v2#!/User_Blocks/delete_user_blocks_by_id) | `deleteByIdentifier(identifier: '...')` | + +For full usage reference of the available API methods please [review the Auth0\SDK\API\Management\UserBlocks class.](https://github.com/auth0/auth0-PHP/blob/main/src/API/Management/UserBlocks.php) + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$userBlocks = $management->userBlocks(); + +// Retrieve a list of all user blocks. +$results = $userBlocks->get('...'); + +dd(HttpResponse::decode($results)); + +// { +// "blocked_for": [ +// { +// "identifier": "...", +// "ip": "..." +// } +// ] +// } +``` + +### Users + +The [/api/v2/users](https://auth0.com/docs/api/management/v2#!/Users) endpoint class is accessible from the `users()` method on the Management API class. + +| Method | Endpoint | PHP Method | +| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | +| `GET` | […/users](https://auth0.com/docs/api/management/v2#!/Users/get_users) | `getAll()` | +| `POST` | […/users](https://auth0.com/docs/api/management/v2#!/Users/post_users) | `create(connection: '...', body: [])` | +| `GET` | […/users/{id}](https://auth0.com/docs/api/management/v2#!/Users/get_users_by_id) | `get(id: '...')` | +| `PATCH` | […/users/{id}](https://auth0.com/docs/api/management/v2#!/Users/patch_users_by_id) | `update(id: '...', body: [])` | +| `DELETE` | […/users/{id}](https://auth0.com/docs/api/management/v2#!/Users/delete_users_by_id) | `delete(id: '...')` | +| `GET` | […/users/{id}/enrollments](https://auth0.com/docs/api/management/v2#!/Users/get_enrollments) | `getEnrollments(id: '...')` | +| `GET` | […/users/{user}/authentication-methods](https://auth0.com/docs/api/management/v2#!/Users/get_authentication_methods) | `getAuthenticationMethods(user: '...')` | +| `DELETE` | […/users/{user}/authentication-methods](https://auth0.com/docs/api/management/v2#!/Users/delete_authentication_methods) | `deleteAuthenticationMethods(user: '...')` | +| `POST` | […/users/{user}/authentication-methods](https://auth0.com/docs/api/management/v2#!/Users/post_authentication_methods) | `createAuthenticationMethod(user: '...', body: [])` | +| `GET` | […/users/{id}/authentication-methods/{method}](https://auth0.com/docs/api/management/v2#!/Users/get_authentication_methods_by_authentication_method_id) | `getAuthenticationMethod(id: '...', method: '...')` | +| `PATCH` | […/users/{id}/authentication-methods/{method}](https://auth0.com/docs/api/management/v2#!/Users/patch_authentication_methods_by_authentication_method_id) | `updateAuthenticationMethod(id: '...', method: '...', body: [])` | +| `DELETE` | […/users/{id}/authentication-methods/{method}](https://auth0.com/docs/api/management/v2#!/Users/delete_authentication_methods_by_authentication_method_id) | `deleteAuthenticationMethod(id: '...', method: '...')` | +| `GET` | […/users/{id}/organizations](https://auth0.com/docs/api/management/v2#!/Users/get_user_organizations) | `getOrganizations(id: '...')` | +| `GET` | […/users/{id}/logs](https://auth0.com/docs/api/management/v2#!/Users/get_logs_by_user) | `getLogs(id: '...')` | +| `GET` | […/users/{id}/roles](https://auth0.com/docs/api/management/v2#!/Users/get_user_roles) | `getRoles(id: '...')` | +| `POST` | […/users/{id}/roles](https://auth0.com/docs/api/management/v2#!/Users/post_user_roles) | `addRoles(id: '...', roles: [])` | +| `DELETE` | […/users/{id}/roles](https://auth0.com/docs/api/management/v2#!/Users/delete_user_roles) | `removeRoles(id: '...', roles: [])` | +| `GET` | […/users/{id}/permissions](https://auth0.com/docs/api/management/v2#!/Users/get_permissions) | `getPermissions(id: '...')` | +| `POST` | […/users/{id}/permissions](https://auth0.com/docs/api/management/v2#!/Users/post_permissions) | `addPermissions(id: '...', permissions: [])` | +| `DELETE` | […/users/{id}/permissions](https://auth0.com/docs/api/management/v2#!/Users/delete_permissions) | `removePermissions(id: '...', permissions: [])` | +| `DELETE` | […/users/{id}/multifactor/{provider}](https://auth0.com/docs/api/management/v2#!/Users/delete_multifactor_by_provider) | `deleteMultifactorProvider(id: '...', provider: '...')` | +| `POST` | […/users/{id}/identities](https://auth0.com/docs/api/management/v2#!/Users/post_identities) | `linkAccount(id: '...', body: [])` | +| `DELETE` | […/users/{id}/identities/{provider}/{identityId}](https://auth0.com/docs/api/management/v2#!/Users/delete_provider_by_user_id) | `unlinkAccount(id: '...', provider: '...', identityId: '...')` | +| `POST` | […/users/{id}/recovery-code-regeneration](https://auth0.com/docs/api/management/v2#!/Users/post_recovery_code_regeneration) | `createRecoveryCode(id: '...')` | +| `POST` | […/users/{id}/multifactor/actions/invalidate-remember-browser](https://auth0.com/docs/api/management/v2#!/Users/post_invalidate_remember_browser) | `invalidateBrowsers(id: '...')` | + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$users = $management->users(); + +// Create a new user. +$users->create( + connection: 'Username-Password-Authentication', + body: [ + 'email' => '...', + 'password' => '...', + 'email_verified' => true, + ] +); + +// Get a single user. +$result = $users->get('auth0|...'); + +dump(HttpResponse::decodedBody($result)); + +// Get all users. +$results = $users->getAll(); + +// You can then iterate (and auto-paginate) through all available results. +foreach ($users->getResponsePaginator() as $user) { + dump($user); + +// { +// "user_id": "...", +// "email": "...", +// "email_verified": true, +// ... +// } +} + +// Or, just work with the initial batch from the response. +dd(HttpResponse::decode($results)); + +// [ +// { +// "user_id": "...", +// "email": "...", +// "email_verified": true, +// ... +// } +// ] +``` + +# Users by Email + +The `Auth0\SDK\API\Management\UsersByEmail` class provides methods to access the [Users by Email endpoint](https://auth0.com/docs/api/management/v2#!/Users_By_Email) of the v2 Management API. + +| Method | Endpoint | PHP Method | +| ------ | ------------------------------------------------------------------------------------------------ | ---------- | +| `GET` | […/users-by-email](https://auth0.com/docs/api/management/v2#!/Users_By_Email/get_users_by_email) | `get()` | + +```php +use Auth0\SDK\Utility\HttpResponse; + +$management = app('auth0')->management(); +$usersByEmail = $management->usersByEmail(); + +// Get a single user by email. +$result = $usersByEmail->get('...'); + +dump(HttpResponse::decodedBody($result)); + +// { +// "user_id": "...", +// "email": "...", +// "email_verified": true, +// ... +// } +``` From 2d3d7ee40211ecb64c940993181dfc50b6356565 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Apr 2023 10:25:25 -0500 Subject: [PATCH 311/525] documentation: Add Events reference doc (#378) Co-authored-by: Rita Zerrizuela --- docs/Events.md | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 docs/Events.md diff --git a/docs/Events.md b/docs/Events.md new file mode 100644 index 00000000..85d80a50 --- /dev/null +++ b/docs/Events.md @@ -0,0 +1,84 @@ +# Events + +**The SDK raises events during the authentication process.** Your application can listen to these events and respond to them if desired. For example, you might want to log the user's information to a database when they log in. + +To listen for events, you must first create a listener class. These usually live in your application's `app/Listeners` directory. The following example shows how to listen to the `lluminate\Auth\Events\Login` event: + +```php +namespace App\Listeners; + +use Illuminate\Auth\Events\Login; + +final class LogSuccessfulLogin +{ + public function handle(Login $event): void + { + // Log the event to a database. + } +} +``` + +Be sure to register your event listeners in your `app/Providers/EventServiceProvider.php` file, for example: + +```php +use Illuminate\Auth\Events\Login; +use App\Listeners\LogSuccessfulLogin; +use Illuminate\Support\Facades\Event; + +public function boot(): void +{ + Event::listen( + Login::class, + [LogSuccessfulLogin::class, 'handle'] + ); +} +``` + +You can learn more about working with the Laravel event system in the [Laravel documentation](https://laravel.com/docs/events). + +## Login Controller Events + +During login with the `Auth0\Laravel\Http\Controller\Stateful\Login` controller, the following events may be raised: + +| Event | Description | +| ------------------------------ | ----------------------------------------------------------------------------------- | +| `Illuminate\Auth\Events\Login` | Raised when a user is logging in. The model of the user is provided with the event. | + +## Callback Controller Events + +During callback with the `Auth0\Laravel\Http\Controller\Stateful\Callback` controller, the following events may be raised: + +| Event | Description | +| --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Illuminate\Auth\Events\Attempting` | Raised when a user is returned to the application after authenticating with Auth0. This is raised before verification of the authentication process begins. | +| `Illuminate\Auth\Events\Failed` | Raised when authentication with Auth0 failed. The reason is provided with the event as an array. | +| `Auth0\Laravel\Event\Stateful\AuthenticationFailed` | Raised when authentication with Auth0 failed. This provides an opportunity to intercept the exception thrown by the middleware, by using the event's `setThrowException()` method to `false`. You can also customize the type of exception thrown using `setException()`. | +| `Illuminate\Auth\Events\Illuminate\Auth\Events\Validated` | Raised when authentication was successful, but immediately before the user's session is established. | +| `Auth0\Laravel\Event\Stateful\AuthenticationSucceeded` | Raised when authentication was successful. The model of the authenticated user is provided with the event. | + +## Logout Controller Events + +During logout with the `Auth0\Laravel\Http\Controller\Stateful\Logout` controller, the following events may be raised: + +| Event | Description | +| ------------------------------- | ------------------------------------------------------------------------------------ | +| `Illuminate\Auth\Events\Logout` | Raised when a user is logging out. The model of the user is provided with the event. | + +## Authentication Middleware Events + +During request handling with any `Auth0\Laravel\Http\Middleware\Stateful` middleware, the following events may be raised: + +| Event | Description | +| ------------------------------------------------ | ---------------------------------------------------------------------------------- | +| `Auth0\Laravel\Event\Middleware\StatefulRequest` | Raised when a request is being handled by a session-based ('stateful') middleware. | + +## Authorization Middleware Events + +During request handling with any `Auth0\Laravel\Http\Controller\Stateless` middleware, the following events may be raised: + +| Event | Description | +| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | +| `Auth0\Laravel\Event\Middleware\StatelessRequest` | Raised when a request is being handled by an access token-based ('stateless') middleware. | +| `Auth0\Laravel\Event\Stateless\TokenVerificationAttempting` | Raised before an access token is attempted to be verified. The encoded token string is provided with the event. | +| `Auth0\Laravel\Event\Stateless\TokenVerificationSucceeded` | Raised when an access token is successfully verified. The decoded token contents are provided with the event. | +| `Auth0\Laravel\Event\Stateless\TokenVerificationFailed` | Raised when an access token cannot be verified. The reason (as a string) is provided with the event. | From a5697d46de7a0eba7c13379c6b6ce43f977884a3 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Apr 2023 10:25:44 -0500 Subject: [PATCH 312/525] documentation: Add User Models and Repositories reference doc (#379) Co-authored-by: Rita Zerrizuela --- docs/User Models and Repositories.md | 141 +++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 docs/User Models and Repositories.md diff --git a/docs/User Models and Repositories.md b/docs/User Models and Repositories.md new file mode 100644 index 00000000..78757d76 --- /dev/null +++ b/docs/User Models and Repositories.md @@ -0,0 +1,141 @@ +# User Models and Repositories + +The Auth0 Laravel SDK uses the repository pattern to allow the abstraction of potential database operations. This pattern is useful for building completely custom integrations that fit your application's needs. + +Let's assume you've configured the SDK's user provider in application's `config/auth.php` like this: + +```php +/** + * Register the SDK's User Provider with your application. + * You should not remove any other entries from this array. + */ +'providers' => [ + 'my-example-provider' => [ + 'driver' => 'auth0.provider', + 'repository' => \Auth0\Laravel\Auth\User\Repository::class + ], +], +``` + +Note the `repository` property — this tells the SDK what class to use for storing and retrieving users. The SDK provides a default implementation, but this does not persist users to an application database. You can add this functionality by using the default implementation as a starting point for building a custom repository of your own. + +## Creating a User Repository + +Creating a repository is simple: it must implement the `Auth0\Laravel\Contract\Auth\User\Repository` interface, and include two methods: + +- `fromSession()` is used to retrieve a user from the application's session. +- `fromAccessToken` is used to retrieve a user from an access token. + +The default implementation looks like this: + +```php + $user['sub'], + ], [ + 'name' => $user['name'], + 'email' => $user['email'], + 'email_verified' => $user['email_verified'], + ]); + + return $user; + } + + public function fromSession(array $user): ?Authenticatable + { + return User::where('auth0_id', $user['sub'])->first(); + } +} +``` + +## Creating a User Model + +The repository is responsible for retrieving and storing users, but it does not define the user model itself. The SDK provides an abstract user model class that can be extended for building your own implementations, `Auth0\Laravel\Model\User`. + +- User models must implement the `Illuminate\Contracts\Auth\Authenticatable` interface, which is required for Laravel's authentication system. +- User models must also implement the `Auth0\Laravel\Contract\Model\User` interface, which is required by the Laravel SDK. + +Because the abstract model already fulfills the requirements of these interfaces, you can use it as-is if you do not need to add any additional functionality. Here's an example customer user model that extends the SDK's abstract user model class to support Eloquent: + +```php + [ + 'my-example-provider' => [ + 'driver' => 'auth0.provider', + 'repository' => \App\Repositories\UserRepository::class, + ], +], From 29225d57f27c38ad1eb172c15aa320ea8ff0266e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Apr 2023 11:14:29 -0500 Subject: [PATCH 313/525] Update README.md --- README.md | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 41005b1c..85caa72a 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,14 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. ## Documentation -- Quickstart Demonstrations +- Quickstarts - [Application using Sessions (Stateful)](https://auth0.com/docs/quickstart/laravel/php) — Traditional web application that uses sessions and supports logging in, logging out, and querying user profiles. [The complete source code is also available.](https://github.com/auth0-samples/auth0-laravel-php-web-app) - [API using Access Tokens (Stateless)](https://auth0.com/docs/quickstart/backend/laravel) — Backend service that authorizes endpoints using access tokens provided by a frontend client and returns JSON responses. [The complete source code is also available.](https://github.com/auth0-samples/auth0-laravel-api-samples) -- [Laravel Examples](./EXAMPLES.md) — Code samples for common scenarios. +- Documentation + - [Examples](./EXAMPLES.md) — Cookbook offering example solutions for common scenarios and questions. + - [Events](./docs/Events.md) — Hooking into [events](https://laravel.com/docs/10.x/events) raised by the SDK to customize behavior. + - [Management API](./docs/Management%20API.md) — Making API calls to [Auth0 Management API endpoints](https://auth0.com/docs/api/management/v2). + - [User Models and Repositories](./docs/User%20Models%20and%20Repositories.md) — Extending the SDK to support database storage, [Eloquent](https://laravel.com/docs/10.x/eloquent), and other scenarios. - [Documentation Hub](https://www.auth0.com/docs) — Learn more about integrating Auth0. ## Getting Started @@ -34,7 +38,7 @@ Our examples use the [Auth0 CLI](https://github.com/auth0/auth0-cli) to help get Open a shell to the root of your Laravel application's root directory, and import the SDK using [Composer](https://getcomposer.org/): ```bash -composer require auth0/login +composer require auth0/login:^7.0 --with-all-dependencies ``` Next, generate the `config/auth0.php` configuration file for your application: @@ -43,6 +47,12 @@ Next, generate the `config/auth0.php` configuration file for your application: php artisan vendor:publish --tag=auth0-config ``` +Now is also a good time to clear your application caches: + +```bash +php artisan optimize:clear +``` + ### Determine Your Application Type Before we begin configuring your application, it's important to understand the difference between "stateful" and "stateless" applications, and which one is appropriate for your use case. @@ -74,7 +84,7 @@ auth0 apps create \ --type "regular" \ --auth-method "post" \ --callbacks "http://localhost:8000/callback" \ - --logout-urls "http://localhost:8000/login" \ + --logout-urls "http://localhost:8000/" \ --reveal-secrets \ --no-input ``` @@ -109,17 +119,21 @@ Please make a note of your new API's **identifier**. This will be required in th Open the `.env` file within your Laravel application's root directory, append the lines below to it, and fill in the missing values: ```ini +# In previous steps we configured our application callbacks use to port 8000, +# which is consistent running the app using `php artisan serve`. +APP_URL=http://localhost:8000 + # Use the `domain` you noted earlier during application creation. -AUTH0_DOMAIN= +AUTH0_DOMAIN={yourDomain} # Use the `client id` you noted earlier during application creation. -AUTH0_CLIENT_ID= +AUTH0_CLIENT_ID={yourClientId} # Use the `client_secret` you noted earlier during application creation. -AUTH0_CLIENT_SECRET= +AUTH0_CLIENT_SECRET={yourClientSecret} # Use the `identifier` you noted earlier during API creation. -AUTH0_AUDIENCE= +AUTH0_AUDIENCE={yourApiIdentifier} # This should be any sufficiently long, random string. # You can use `openssl rand -hex 32` to generate an adequate string. From a6718978018193ee2209d3e6ae4b679ecb6d4e16 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Apr 2023 11:38:42 -0500 Subject: [PATCH 314/525] Update EXAMPLES.md --- EXAMPLES.md | 176 ++++++++++++++++++---------------------------------- 1 file changed, 61 insertions(+), 115 deletions(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index 63c9e961..52499dd6 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -1,127 +1,29 @@ -# Auth0 Laravel SDK Examples +# Examples Cookbook -- [Extending the SDK with Custom User Models and Repositories](#extending-the-sdk-with-custom-user-models-and-repositories) - - [Creating a Custom User Model](#creating-a-custom-user-model) - - [Creating a Custom User Repository](#creating-a-custom-user-repository) - - [Using a Custom User Repository](#using-a-custom-user-repository) -- [Authorizing HTTP Tests](#authorizing-http-tests) -- [Protecting Routes with Scope Filtering](#protecting-routes-with-scope-filtering) +This document provides example solutions for common integration questions. -## Extending the SDK with Custom User Models and Repositories +- [Users](#users) + - [Custom Models and Repositories](#custom-user-models-and-repositories) +- [Management API](#management-api) +- [Middleware](#middleware) + - [Scope Filtering](#scope-filtering) +- [Events](#events) +- [Testing](#testing) + - [Authorizing HTTP Tests](#authorizing-http-tests) -In Laravel, a User Repository is an interface that sits between your authentication source (Auth0) and core Laravel authentication services. It allows you to shape and manipulate the user model and it's data as you need to. +## Users -For example, Auth0's unique identifier is a `string` in the format `auth0|123456abcdef`. If you were to attempt to persist a user to many traditional databases you'd likely encounter an error as, by default, a unique identifier is often expected to be an `integer` rather than a `string` type. A custom user model and repository is a great way to address integration challenges like this. +### Custom User Models and Repositories -### Creating a Custom User Model +[docs/User Models and Repositories](./docs/User%20Models%20and%20Repositories.md) covers extending the SDK to support database storage, [Eloquent](https://laravel.com/docs/10.x/eloquent), and other scenarios. -Let's setup a custom user model for our application. To do this, let's create a file at `app/Auth/Models/User.php` within our Laravel project. This new class needs to implement the `Illuminate\Contracts\Auth\Authenticatable` interface to be compatible with Laravel's Guard API and this SDK. It must also implement either `Auth0\Laravel\Contract\Model\Stateful\User` or `Auth0\Laravel\Contract\Model\Stateless\User` depending on your application's needs. For example: +## Management API -```php - - */ - protected $fillable = [ - 'id', - 'name', - 'email', - ]; - - /** - * The attributes that should be hidden for serialization. - * - * @var array - */ - protected $hidden = []; - - /** - * The attributes that should be cast. - * - * @var array - */ - protected $casts = []; -} -``` - -### Creating a Custom User Repository - -Now let's create a custom user repository for your application which will return the new new custom model. To do this, create the file `app/Auth/CustomUserRepository.php`. This new class must implement the `Auth0\Laravel\Contract\Auth\User\Repository` interface. This new repository takes in user data returned from Auth0's API, applies it to the `App\Models\User` custom user model created in the previous step, and returns it for use throughout your application. - -```php - 'just_a_random_example|' . $user['sub'] ?? $user['user_id'] ?? null, - 'name' => $user['name'], - 'email' => $user['email'] - ]); - } - - public function fromAccessToken( - array $user - ): ?\Illuminate\Contracts\Auth\Authenticatable { - // Similar to above. Used for stateless application types. - return null; - } -} -``` - -### Using a Custom User Repository - -Finally, update your application's `config/auth.php` file. Within the Auth0 provider, assign a custom `repository` value pointing to your new custom user provider class. For example: - -```php - 'providers' => [ - //... - - 'auth0' => [ - 'driver' => 'auth0.provider', - 'repository' => \App\Auth\CustomUserRepository::class - ], - ], -``` +[docs/Management API](./docs/Management%20API.md) covers making API calls to [Auth0 Management API endpoints](https://auth0.com/docs/api/management/v2). -## Authorizing HTTP Tests +## Middleware -If your application does contain HTTP tests which access routes that are protected by the `auth0.authorize` middleware, you can use the trait `Auth0\Laravel\Traits\ActingAsAuth0User` in your tests, which will give you a helper method `actingAsAuth0User(array $attributes=[])` similar to Laravel's `actingAs` method, that allows you to impersonate an authenticated state suitable for the middleware. - -The argument `attributes` is optional and you can use it to set any auth0 specific user attributes like scope, sub, azp, iap and so on. If no attributes are set, some default values are used. - -## Protecting Routes with Scope Filtering +### Scope Filtering Let's assume you have a route like the following, that is protected by the scope `read:messages`: @@ -157,3 +59,47 @@ it('can access a private scoped endpoint', function () { ->assertJson(['message' => 'Hello from a private endpoint!']); }); ``` + +## Events + +[docs/Events](./docs/Events.md) covers hooking into [events](https://laravel.com/docs/10.x/events) raised by the SDK to customize behavior. + +## Testing + +### Authorizing HTTP Tests + +When writing unit tests for your application that include HTTP requests to routes protected by the SDK's middleware, you can use the "Imposter" trait to simplify fulfilling the request by mocking a user session. The following example is writen in [PEST syntax](https://pestphp.com), but the trait can be used in an identical manner with test-case classes in PHPUnit: + +> **Note** +> If you're using custom user repositories or models, you may need to adjust how `$imposter` is shaping the `user` property to match your integration. + +```php +get('/example', function () use ($route): string { + return response()->json('Hello World'); + }); + + $imposter = Credential::create( + user: new User(['sub' => uniqid()]), + idToken: uniqid(), + accessToken: uniqid(), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600 + ); + + $this->impersonate($imposter) + ->getJson('./example') + ->assertStatus(Response::HTTP_OK); +}); +``` From 2ca90bf71f0fe05309f58b1c863383144aa80b40 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Apr 2023 11:41:00 -0500 Subject: [PATCH 315/525] Update EXAMPLES.md --- EXAMPLES.md | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index 52499dd6..f0cb5d6a 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -9,7 +9,7 @@ This document provides example solutions for common integration questions. - [Scope Filtering](#scope-filtering) - [Events](#events) - [Testing](#testing) - - [Authorizing HTTP Tests](#authorizing-http-tests) + - [Impersonation](#impersonation) ## Users @@ -37,36 +37,13 @@ Route::get('/api/private-scoped', function () { })->middleware(['auth0.authorize:read:messages']); ``` -To be able to test the route from above, the implementation of your test would have to look like this: - -```php -use Auth0\Laravel\Contract\StateInstance; -use Auth0\Laravel\Model\Credential; -use Auth0\Laravel\Model\Stateless\User; -use Auth0\Laravel\Trait\Impersonate; -use Illuminate\Http\Response; - -it('can access a private scoped endpoint', function () { - $impersonating = Credential::create( - user: new User(['sub' => 'auth0|123456abcdef']), - accessTokenScope: ['read:messages'], - source: StateInstance::CONST_SOURCE_TOKEN, - ); - - $this->impersonate($impersonating) - ->getJson('/api/private-scoped') - ->assertStatus(Response::HTTP_OK) - ->assertJson(['message' => 'Hello from a private endpoint!']); -}); -``` - ## Events [docs/Events](./docs/Events.md) covers hooking into [events](https://laravel.com/docs/10.x/events) raised by the SDK to customize behavior. ## Testing -### Authorizing HTTP Tests +### Impersonation When writing unit tests for your application that include HTTP requests to routes protected by the SDK's middleware, you can use the "Imposter" trait to simplify fulfilling the request by mocking a user session. The following example is writen in [PEST syntax](https://pestphp.com), but the trait can be used in an identical manner with test-case classes in PHPUnit: From 7f5dd2d834c6ea83c911f4ed7bee37a053bc545e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Apr 2023 11:43:49 -0500 Subject: [PATCH 316/525] Update EXAMPLES.md --- EXAMPLES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/EXAMPLES.md b/EXAMPLES.md index f0cb5d6a..b497cf26 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -11,6 +11,9 @@ This document provides example solutions for common integration questions. - [Testing](#testing) - [Impersonation](#impersonation) +> **Note** +> The [README](./README.md) also covers many integration questions. Please review that document if your question is not answered here. + ## Users ### Custom User Models and Repositories From 84d94c2ac8f62163811fa7409ad23dfdac5efe0e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Apr 2023 11:56:02 -0500 Subject: [PATCH 317/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 85caa72a..40af202e 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ Open the `.env` file within your Laravel application's root directory, append th ```ini # In previous steps we configured our application callbacks use to port 8000, -# which is consistent running the app using `php artisan serve`. +# which is consistent for running your app using `php artisan serve`. APP_URL=http://localhost:8000 # Use the `domain` you noted earlier during application creation. From 148ff289cd357bf9690f7b7208c8a980e9025cde Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 25 Apr 2023 22:57:45 -0500 Subject: [PATCH 318/525] Update tests --- src/Auth0.php | 6 +- tests/Pest.php | 2 + tests/TestCase.php | 3 - tests/Unit/Auth/GuardStatefulTest.php | 126 ++++++++++++++++-- tests/Unit/Auth/GuardStatelessTest.php | 32 +++-- tests/Unit/Auth/User/ProviderTest.php | 21 ++- tests/Unit/Auth0Test.php | 96 +++++++------ tests/Unit/Entities/CredentialTest.php | 23 ++-- .../Http/Controller/Stateful/CallbackTest.php | 43 +++--- .../Http/Controller/Stateful/LoginTest.php | 33 +++-- .../Http/Controller/Stateful/LogoutTest.php | 37 +++-- .../Stateful/AuthenticateOptionalTest.php | 29 ++-- .../Middleware/Stateful/AuthenticateTest.php | 29 ++-- .../Stateless/AuthorizeOptionalTest.php | 42 +++--- .../Middleware/Stateless/AuthorizeTest.php | 42 +++--- tests/Unit/Traits/ActingAsAuth0UserTest.php | 22 +-- tests/Unit/Traits/ImpersonateTest.php | 22 +-- 17 files changed, 365 insertions(+), 243 deletions(-) diff --git a/src/Auth0.php b/src/Auth0.php index 0826d6c6..3aacf6b0 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -109,11 +109,11 @@ public function getCredentials(): ?object public function getSdk(): SDKContract { - if ($this->sdk instanceof SDKContract) { - return $this->sdk; + if (! $this->sdk instanceof SDKContract) { + $this->setSdk(new SDK($this->getConfiguration())); } - return $this->setSdk(new SDK($this->getConfiguration())); + return $this->sdk; } public function management(): ManagementInterface diff --git a/tests/Pest.php b/tests/Pest.php index 6318bd5c..beca627f 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -35,6 +35,8 @@ }); })->in(__DIR__); +uses()->compact(); + /* |-------------------------------------------------------------------------- | Expectations diff --git a/tests/TestCase.php b/tests/TestCase.php index 6fbae36d..bdd75619 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -48,9 +48,6 @@ protected function getEnvironmentSetUp($app): void ], ]); - // Default to no strategy for testing - $app['config']->set('auth0.strategy', 'none'); - // Set a random key for testing $app['config']->set('app.key', 'base64:' . base64_encode(random_bytes(32))); diff --git a/tests/Unit/Auth/GuardStatefulTest.php b/tests/Unit/Auth/GuardStatefulTest.php index 736e1d38..30c95c9f 100644 --- a/tests/Unit/Auth/GuardStatefulTest.php +++ b/tests/Unit/Auth/GuardStatefulTest.php @@ -19,21 +19,24 @@ uses()->group('auth', 'auth.guard', 'auth.guard.stateful'); beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.clientSecret' => $this->secret, + 'auth0.cookieSecret' => uniqid(), + 'auth0.routes.home' => '/' . uniqid(), + ]); + $this->laravel = app('auth0'); $this->guard = $guard = auth('testGuard'); $this->sdk = $this->laravel->getSdk(); $this->config = $this->sdk->configuration(); $this->session = $this->config->getSessionStorage(); - $this->transient = $this->config->getTransientStorage(); - $this->user = new User(['sub' => uniqid('auth0|')]); - - $this->secret = uniqid(); - $this->config->setDomain('my-domain.auth0.com'); - $this->config->setClientId('my_client_id'); - $this->config->setClientSecret($this->secret); - $this->config->setCookieSecret('my_cookie_secret'); - $this->config->setStrategy(SdkConfiguration::STRATEGY_REGULAR); + $this->user = new User(['sub' => uniqid('auth0|')]); $this->session->set('user', ['sub' => 'hello|world']); $this->session->set('idToken', uniqid()); @@ -42,6 +45,7 @@ $this->session->set('accessTokenExpiration', time() + 60); $this->route = '/' . uniqid(); + $guard = $this->guard; Route::get($this->route, function () use ($guard) { $credential = $guard->find(Guard::SOURCE_SESSION); @@ -250,11 +254,105 @@ expect($userAttributes) ->toBeArray() - ->toHaveKeys(['sub', 'name', 'email']) - ->toHaveCount(3) - ->sub->toEqual($identifier) - ->name->toEqual('John Doe') - ->email->toEqual('...'); + ->toMatchArray([ + 'sub' => $identifier, + 'name' => 'John Doe', + 'email' => '...', + ]); +}); + +it('does not query the /userinfo endpoint for refreshUser() if an access token is not available', function (): void { + $identifier = uniqid('auth0|'); + $idToken = uniqid('id-token-'); + $accessTokenScope = [uniqid('access-token-scope-')]; + $accessTokenExpiration = time() + 60; + + $this->session->set('user', ['sub' => $identifier]); + $this->session->set('idToken', $idToken); + $this->session->set('accessToken', null); + $this->session->set('accessTokenScope', $accessTokenScope); + $this->session->set('accessTokenExpiration', $accessTokenExpiration); + + $found = $this->guard->find(Guard::SOURCE_SESSION); + $this->guard->login($found, Guard::SOURCE_SESSION); + + expect($this->session) + ->get('user')->toBe(['sub' => $identifier]); + + $requestFactory = new MockRequestFactory; + $responseFactory = new MockResponseFactory; + $streamFactory = new MockStreamFactory; + + $response = $responseFactory->createResponse(200); + $response->getBody()->write(json_encode( + [ + 'sub' => $identifier, + 'name' => 'John Doe', + 'email' => '...', + ], + JSON_PRETTY_PRINT + )); + + $client = new MockHttpClient(fallbackResponse: $response, requestLimit: 0); + + $this->config->setHttpRequestFactory($requestFactory); + $this->config->setHttpResponseFactory($responseFactory); + $this->config->setHttpStreamFactory($streamFactory); + $this->config->setHttpClient($client); + + $this->guard->refreshUser(); + + $userAttributes = $this->guard->user()->getAttributes(); + + expect($userAttributes) + ->toBeArray() + ->toMatchArray([ + 'sub' => $identifier, + ]); +}); + +it('rejects bad responses from the /userinfo endpoint for refreshUser()', function (): void { + $identifier = uniqid('auth0|'); + $idToken = uniqid('id-token-'); + $accessToken = uniqid('access-token-'); + $accessTokenScope = [uniqid('access-token-scope-')]; + $accessTokenExpiration = time() + 60; + + $this->session->set('user', ['sub' => $identifier]); + $this->session->set('idToken', $idToken); + $this->session->set('accessToken', $accessToken); + $this->session->set('accessTokenScope', $accessTokenScope); + $this->session->set('accessTokenExpiration', $accessTokenExpiration); + + $found = $this->guard->find(Guard::SOURCE_SESSION); + $this->guard->login($found, Guard::SOURCE_SESSION); + + expect($this->session) + ->get('user')->toBe(['sub' => $identifier]); + + $requestFactory = new MockRequestFactory; + $responseFactory = new MockResponseFactory; + $streamFactory = new MockStreamFactory; + + $response = $responseFactory->createResponse(200); + $response->getBody()->write(json_encode('bad response', JSON_PRETTY_PRINT)); + + $client = new MockHttpClient(fallbackResponse: $response); + + $this->config->setHttpRequestFactory($requestFactory); + $this->config->setHttpResponseFactory($responseFactory); + $this->config->setHttpStreamFactory($streamFactory); + $this->config->setHttpClient($client); + + $this->guard->refreshUser(); + + $userAttributes = $this->guard->user()->getAttributes(); + + expect($userAttributes) + ->toBeArray() + ->toMatchArray([ + 'sub' => $identifier, + ]); }); it('immediately invalidates an expired session when a refresh token is not available', function (): void { diff --git a/tests/Unit/Auth/GuardStatelessTest.php b/tests/Unit/Auth/GuardStatelessTest.php index 18c41c0b..4b88483f 100644 --- a/tests/Unit/Auth/GuardStatelessTest.php +++ b/tests/Unit/Auth/GuardStatelessTest.php @@ -15,27 +15,31 @@ uses()->group('auth', 'auth.guard', 'auth.guard.stateless'); beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.audience' => ['https://example.com/health-api'], + 'auth0.clientSecret' => $this->secret, + 'auth0.tokenAlgorithm' => Token::ALGO_HS256, + 'auth0.routes.home' => '/' . uniqid(), + ]); + $this->laravel = app('auth0'); - $this->guard = $guard = auth('testGuard'); + $this->guard = auth('testGuard'); $this->sdk = $this->laravel->getSdk(); $this->config = $this->sdk->configuration(); - $this->secret = uniqid(); - - $this->config->setDomain('my-domain.auth0.com'); - $this->config->setClientSecret($this->secret); - $this->config->setAudience(['https://example.com/health-api']); - $this->config->setTokenAlgorithm(Token::ALGO_HS256); - $this->config->setStrategy(SdkConfiguration::STRATEGY_API); - $this->token = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => "https://my-domain.auth0.com/", + "iss" => 'https://' . config('auth0.domain') . '/', "sub" => "auth0|123456", "aud" => [ - "https://example.com/health-api", - "https://my-domain.auth0.com/userinfo" + config('auth0.audience')[0], + "https://my-domain.auth0.com/userinfo" ], - "azp" => "my_client_id", + "azp" => config('auth0.clientId'), "exp" => time() + 60, "iat" => time(), "scope" => "openid profile read:patients read:admin" @@ -43,6 +47,8 @@ $this->bearerToken = ['Authorization' => 'Bearer ' . $this->token->toString()]; $this->route = '/' . uniqid(); + $guard = $this->guard; + Route::get($this->route, function () use ($guard) { $credential = $guard->find(Guard::SOURCE_TOKEN); diff --git a/tests/Unit/Auth/User/ProviderTest.php b/tests/Unit/Auth/User/ProviderTest.php index ee771e1e..5cc306c1 100644 --- a/tests/Unit/Auth/User/ProviderTest.php +++ b/tests/Unit/Auth/User/ProviderTest.php @@ -5,17 +5,34 @@ use Auth0\Laravel\Auth\User\Provider; use Auth0\Laravel\Auth\User\Repository; use Auth0\Laravel\Model\Stateful\User; +use Auth0\SDK\Configuration\SdkConfiguration; use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Http\Response; use Illuminate\Support\Facades\Route; uses()->group('auth', 'auth.user', 'auth.user.provider'); +beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.clientSecret' => $this->secret, + 'auth0.cookieSecret' => uniqid(), + 'auth0.routes.home' => '/' . uniqid(), + ]); + + $this->laravel = app('auth0'); + $this->guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); +}); + test('retrieveByToken() returns null when an incompatible guard token is used', function (): void { config([ 'auth.defaults.guard' => 'web', - 'auth.guards.testGuard' => null, - 'auth0.routes.home' => '/testing' + 'auth.guards.testGuard' => null ]); $route = '/' . uniqid(); diff --git a/tests/Unit/Auth0Test.php b/tests/Unit/Auth0Test.php index d5af54a0..31ac32e2 100644 --- a/tests/Unit/Auth0Test.php +++ b/tests/Unit/Auth0Test.php @@ -2,89 +2,97 @@ declare(strict_types=1); +use Auth0\Laravel\Auth0; +use Auth0\Laravel\Cache\LaravelCachePool; +use Auth0\Laravel\Store\LaravelSession; use Auth0\SDK\Contract\Auth0Interface as SdkContract; use Auth0\SDK\Auth0 as SDKAuth0; use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\SDK\Contract\API\ManagementInterface; +use Auth0\SDK\Store\MemoryStore; +use Psr\Cache\CacheItemPoolInterface; uses()->group('auth0'); +beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.clientSecret' => $this->secret, + 'auth0.cookieSecret' => uniqid(), + 'auth0.routes.home' => '/' . uniqid(), + ]); + + $this->laravel = app('auth0'); + $this->guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + $this->session = $this->config->getSessionStorage(); +}); + it('returns a Management API class', function (): void { - $laravel = app('auth0'); - expect($laravel->management())->toBeInstanceOf(ManagementInterface::class); + expect($this->laravel->management())->toBeInstanceOf(ManagementInterface::class); }); it('can get/set the configuration', function (): void { - $laravel = app('auth0'); - expect($laravel->getConfiguration())->toBeInstanceOf(SdkConfiguration::class); + expect($this->laravel->getConfiguration())->toBeInstanceOf(SdkConfiguration::class); $configuration = new SdkConfiguration(['strategy' => 'none', 'domain' => uniqid() . '.auth0.test']); - $laravel->setConfiguration($configuration); - expect($laravel->getConfiguration())->toBe($configuration); + $this->laravel->setConfiguration($configuration); + expect($this->laravel->getConfiguration())->toBe($configuration); $domain = uniqid() . '.auth0.test'; $configuration->setDomain($domain); - expect($laravel->getConfiguration()->getDomain())->toBe($domain); + expect($this->laravel->getConfiguration()->getDomain())->toBe($domain); $configuration = new SdkConfiguration(['strategy' => 'none', 'domain' => uniqid() . '.auth0.test']); - $laravel->setConfiguration($configuration); - expect($laravel->getConfiguration())->toBe($configuration); + $this->laravel->setConfiguration($configuration); + expect($this->laravel->getConfiguration())->toBe($configuration); - $sdk = $laravel->getSdk(); + $sdk = $this->laravel->getSdk(); $configuration = new SdkConfiguration(['strategy' => 'none', 'domain' => uniqid() . '.auth0.test']); - $laravel->setConfiguration($configuration); - expect($laravel->getConfiguration())->toBe($configuration); + $this->laravel->setConfiguration($configuration); + expect($this->laravel->getConfiguration())->toBe($configuration); expect($sdk->configuration())->toBe($configuration); }); it('can get the sdk credentials', function (): void { - $laravel = app('auth0'); - - expect($laravel->getCredentials()) + expect($this->laravel->getCredentials()) ->toBeNull(); - $sdk = $laravel->getSdk(); - $config = $sdk->configuration(); - $session = $config->getSessionStorage(); - - $config->setDomain('my-domain.auth0.com'); - $config->setClientId('my_client_id'); - $config->setClientSecret('my_client_secret'); - $config->setCookieSecret('my_cookie_secret'); - $config->setStrategy(SdkConfiguration::STRATEGY_REGULAR); - - $session->set('user', ['sub' => 'hello|world']); - $session->set('idToken', uniqid()); - $session->set('accessToken', uniqid()); - $session->set('accessTokenScope', [uniqid()]); - $session->set('accessTokenExpiration', time() - 1000); + $this->session->set('user', ['sub' => 'hello|world']); + $this->session->set('idToken', uniqid()); + $this->session->set('accessToken', uniqid()); + $this->session->set('accessTokenScope', [uniqid()]); + $this->session->set('accessTokenExpiration', time() - 1000); // As we manually set the session values, we need to refresh the SDK state to ensure it's in sync. - $sdk->refreshState(); + $this->sdk->refreshState(); - expect($laravel->getCredentials()) + expect($this->laravel->getCredentials()) ->toBeObject() - ->toHaveProperty('accessToken', $session->get('accessToken')) - ->toHaveProperty('accessTokenScope', $session->get('accessTokenScope')) - ->toHaveProperty('accessTokenExpiration', $session->get('accessTokenExpiration')) - ->toHaveProperty('idToken', $session->get('idToken')) - ->toHaveProperty('user', $session->get('user')); + ->toHaveProperty('accessToken', $this->session->get('accessToken')) + ->toHaveProperty('accessTokenScope', $this->session->get('accessTokenScope')) + ->toHaveProperty('accessTokenExpiration', $this->session->get('accessTokenExpiration')) + ->toHaveProperty('idToken', $this->session->get('idToken')) + ->toHaveProperty('user', $this->session->get('user')); }); it('can get/set the SDK', function (): void { - $laravel = app('auth0'); - expect($laravel->getSdk())->toBeInstanceOf(SdkContract::class); + expect($this->laravel->getSdk())->toBeInstanceOf(SdkContract::class); $sdk = new SDKAuth0(['strategy' => 'none']); - $laravel->setSdk($sdk); - expect($laravel->getSdk())->toBeInstanceOf(SdkContract::class); + $this->laravel->setSdk($sdk); + expect($this->laravel->getSdk())->toBeInstanceOf(SdkContract::class); }); it('can reset the internal static state', function (): void { - $laravel = app('auth0'); - $cache = spl_object_id($laravel->getSdk()); + $cache = spl_object_id($this->laravel->getSdk()); - unset($laravel); // Force the object to be destroyed. Static state will remain. + unset($this->laravel); // Force the object to be destroyed. Static state will remain. $laravel = app('auth0'); $updated = spl_object_id($laravel->getSdk()); diff --git a/tests/Unit/Entities/CredentialTest.php b/tests/Unit/Entities/CredentialTest.php index bc5c3399..fb736776 100644 --- a/tests/Unit/Entities/CredentialTest.php +++ b/tests/Unit/Entities/CredentialTest.php @@ -10,20 +10,21 @@ uses()->group('stateful', 'model', 'model.credential'); beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.audience' => [uniqid()], + 'auth0.clientSecret' => $this->secret, + 'auth0.tokenAlgorithm' => Token::ALGO_HS256, + 'auth0.routes.home' => '/' . uniqid(), + ]); + $this->laravel = app('auth0'); $this->guard = auth('testGuard'); $this->sdk = $this->laravel->getSdk(); - $this->config = $this->sdk->configuration(); - $this->session = $this->config->getSessionStorage(); - $this->transient = $this->config->getTransientStorage(); - $this->secret = uniqid(); - - $this->config->setDomain('my-domain.auth0.com'); - $this->config->setClientId('my_client_id'); - $this->config->setClientSecret($this->secret); - $this->config->setCookieSecret('my_cookie_secret'); - $this->config->setTokenAlgorithm(Token::ALGO_HS256); - $this->config->setStrategy(SdkConfiguration::STRATEGY_API); $this->user = new User(['sub' => uniqid('auth0|')]); $this->idToken = uniqid(); diff --git a/tests/Unit/Http/Controller/Stateful/CallbackTest.php b/tests/Unit/Http/Controller/Stateful/CallbackTest.php index b1bed41c..95dab2da 100644 --- a/tests/Unit/Http/Controller/Stateful/CallbackTest.php +++ b/tests/Unit/Http/Controller/Stateful/CallbackTest.php @@ -23,21 +23,23 @@ uses()->group('stateful', 'controller', 'controller.stateful', 'controller.stateful.callback'); beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.clientSecret' => $this->secret, + 'auth0.cookieSecret' => uniqid(), + 'auth0.routes.home' => '/' . uniqid(), + ]); + $this->laravel = app('auth0'); $this->guard = auth('testGuard'); $this->sdk = $this->laravel->getSdk(); $this->config = $this->sdk->configuration(); - $this->session = $this->config->getSessionStorage(); - $this->transient = $this->config->getTransientStorage(); - $this->user = new User(['sub' => uniqid('auth0|')]); - $this->secret = uniqid(); - - $this->config->setDomain('my-domain.auth0.com'); - $this->config->setClientId('my_client_id'); - $this->config->setClientSecret($this->secret); - $this->config->setCookieSecret('my_cookie_secret'); - $this->config->setStrategy(SdkConfiguration::STRATEGY_REGULAR); + $this->user = new User(['sub' => uniqid('auth0|')]); Route::get('/auth0/callback', Callback::class)->name('callback'); }); @@ -46,12 +48,11 @@ config([ 'auth.defaults.guard' => 'web', 'auth.guards.testGuard' => null, - 'auth0.routes.home' => '/testing' ]); getJson('/auth0/callback') ->assertFound() - ->assertLocation('/testing'); + ->assertLocation(config('auth0.routes.home')); }); it('accepts code and state parameters', function (): void { @@ -89,10 +90,6 @@ }); it('returns a user and sets up a session', function (): void { - config([ - 'auth0.routes.home' => '/testing' - ]); - $this->config->setTokenAlgorithm(Token::ALGO_HS256); $state = uniqid(); @@ -101,21 +98,21 @@ $verifier = uniqid(); $accessToken = Generator::create($this->secret, Token::ALGO_HS256, [ - 'iss' => 'https://my-domain.auth0.com/', + "iss" => 'https://' . config('auth0.domain') . '/', 'sub' => 'hello|world', - 'aud' => 'my_client_id', + 'aud' => config('auth0.clientId'), 'exp' => time() + 60, 'iat' => time(), 'email' => 'john.doe@somewhere.teset' ], []); $idToken = Generator::create($this->secret, Token::ALGO_HS256, [ - 'iss' => 'https://my-domain.auth0.com/', + "iss" => 'https://' . config('auth0.domain') . '/', 'sub' => 'hello|world', - 'aud' => 'my_client_id', + 'aud' => config('auth0.clientId'), 'iat' => time(), 'exp' => time() + 60, - 'azp' => 'my_client_id', + 'azp' => config('auth0.clientId'), 'scope' => 'openid profile email', 'nonce' => $nonce, ], []); @@ -130,7 +127,7 @@ ])); $client = $this->config->getHttpClient(); - $client->addResponse('POST', 'https://my-domain.auth0.com/oauth/token', $response); + $client->addResponse('POST', 'https://' . config('auth0.domain') . '/oauth/token', $response); $this->withSession([ 'auth0_transient_state' => $state, @@ -139,7 +136,7 @@ 'auth0_transient_code_verifier' => $verifier ])->getJson('/auth0/callback?code=code&state=' . $state) ->assertFound() - ->assertLocation('/testing'); + ->assertLocation(config('auth0.routes.home')); $this->assertDispatched(Attempting::class, 1); $this->assertDispatched(Validated::class, 1); diff --git a/tests/Unit/Http/Controller/Stateful/LoginTest.php b/tests/Unit/Http/Controller/Stateful/LoginTest.php index 0a8820ae..4475d3ff 100644 --- a/tests/Unit/Http/Controller/Stateful/LoginTest.php +++ b/tests/Unit/Http/Controller/Stateful/LoginTest.php @@ -9,22 +9,22 @@ uses()->group('stateful', 'controller', 'controller.stateful', 'controller.stateful.login'); beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.clientSecret' => $this->secret, + 'auth0.cookieSecret' => uniqid(), + 'auth0.routes.home' => '/' . uniqid(), + ]); + $this->laravel = app('auth0'); $this->guard = auth('testGuard'); $this->sdk = $this->laravel->getSdk(); - $this->config = $this->sdk->configuration(); - $this->session = $this->config->getSessionStorage(); - $this->transient = $this->config->getTransientStorage(); - $this->secret = uniqid(); - - $this->config->setDomain('my-domain.auth0.com'); - $this->config->setClientId('my_client_id'); - $this->config->setClientSecret($this->secret); - $this->config->setCookieSecret('my_cookie_secret'); - $this->config->setStrategy(SdkConfiguration::STRATEGY_REGULAR); - - $this->templates['validSession'] = [ + $this->validSession = [ 'auth0_session_user' => ['sub' => 'hello|world'], 'auth0_session_idToken' => uniqid(), 'auth0_session_accessToken' => uniqid(), @@ -39,21 +39,20 @@ config($config = [ 'auth.defaults.guard' => 'web', 'auth.guards.testGuard' => null, - 'auth0.routes.home' => '/' . uniqid(), ]); $this->get('/login') - ->assertRedirect($config['auth0.routes.home']); + ->assertRedirect(config('auth0.routes.home')); }); it('redirects to the home route when a user is already logged in', function (): void { config($config = [ - 'auth0.routes.home' => '/' . uniqid(), + 'auth0.routes.home' => '/' . uniqid() ]); - $this->withSession($this->templates['validSession']) + $this->withSession($this->validSession) ->get('/login') - ->assertRedirect($config['auth0.routes.home']); + ->assertRedirect(config('auth0.routes.home')); }); it('redirects to the Universal Login Page', function (): void { diff --git a/tests/Unit/Http/Controller/Stateful/LogoutTest.php b/tests/Unit/Http/Controller/Stateful/LogoutTest.php index eed805b2..b18f365d 100644 --- a/tests/Unit/Http/Controller/Stateful/LogoutTest.php +++ b/tests/Unit/Http/Controller/Stateful/LogoutTest.php @@ -9,22 +9,22 @@ uses()->group('stateful', 'controller', 'controller.stateful', 'controller.stateful.logout'); beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.clientSecret' => $this->secret, + 'auth0.cookieSecret' => uniqid(), + 'auth0.routes.home' => '/' . uniqid(), + ]); + $this->laravel = app('auth0'); $this->guard = auth('testGuard'); $this->sdk = $this->laravel->getSdk(); - $this->config = $this->sdk->configuration(); - $this->session = $this->config->getSessionStorage(); - $this->transient = $this->config->getTransientStorage(); - - $this->secret = uniqid(); - $this->config->setDomain('my-domain.auth0.com'); - $this->config->setClientId('my_client_id'); - $this->config->setClientSecret($this->secret); - $this->config->setCookieSecret('my_cookie_secret'); - $this->config->setStrategy(SdkConfiguration::STRATEGY_REGULAR); - - $this->templates['validSession'] = [ + $this->validSession = [ 'auth0_session_user' => ['sub' => 'hello|world'], 'auth0_session_idToken' => uniqid(), 'auth0_session_accessToken' => uniqid(), @@ -38,25 +38,20 @@ it('redirects to the home route if an incompatible guard is active', function (): void { config($config = [ 'auth.defaults.guard' => 'web', - 'auth.guards.testGuard' => null, - 'auth0.routes.home' => '/' . uniqid(), + 'auth.guards.testGuard' => null ]); $this->get('/logout') - ->assertRedirect($config['auth0.routes.home']); + ->assertRedirect(config('auth0.routes.home')); }); it('redirects to the home route when a user is not already logged in', function (): void { - config($config = [ - 'auth0.routes.home' => '/' . uniqid(), - ]); - $this->get('/logout') - ->assertRedirect($config['auth0.routes.home']); + ->assertRedirect(config('auth0.routes.home')); }); it('redirects to the Auth0 logout endpoint', function (): void { - $this->withSession($this->templates['validSession']) + $this->withSession($this->validSession) ->get('/logout') ->assertRedirectContains('/v2/logout'); }); diff --git a/tests/Unit/Http/Middleware/Stateful/AuthenticateOptionalTest.php b/tests/Unit/Http/Middleware/Stateful/AuthenticateOptionalTest.php index c91772bf..494d4096 100644 --- a/tests/Unit/Http/Middleware/Stateful/AuthenticateOptionalTest.php +++ b/tests/Unit/Http/Middleware/Stateful/AuthenticateOptionalTest.php @@ -10,22 +10,21 @@ uses()->group('stateful', 'middleware', 'middleware.stateful', 'middleware.stateful.authenticate_optional'); beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.clientSecret' => $this->secret, + 'auth0.cookieSecret' => uniqid(), + ]); + $this->laravel = app('auth0'); $this->guard = auth('testGuard'); $this->sdk = $this->laravel->getSdk(); - $this->config = $this->sdk->configuration(); - $this->session = $this->config->getSessionStorage(); - $this->transient = $this->config->getTransientStorage(); - - $this->secret = uniqid(); - - $this->config->setDomain('my-domain.auth0.com'); - $this->config->setClientId('my_client_id'); - $this->config->setClientSecret($this->secret); - $this->config->setCookieSecret('my_cookie_secret'); - $this->config->setStrategy(SdkConfiguration::STRATEGY_REGULAR); - $this->templates['validSession'] = [ + $this->validSession = [ 'auth0_session_user' => ['sub' => 'hello|world'], 'auth0_session_idToken' => uniqid(), 'auth0_session_accessToken' => uniqid(), @@ -75,7 +74,7 @@ return $route; }); - $this->withSession($this->templates['validSession']) + $this->withSession($this->validSession) ->get($route) ->assertStatus(Response::HTTP_OK) ->assertSee($route); @@ -91,7 +90,7 @@ return $route; }); - $this->withSession($this->templates['validSession']) + $this->withSession($this->validSession) ->get($route) ->assertStatus(Response::HTTP_OK) ->assertSee($route); @@ -107,7 +106,7 @@ return $route; }); - $this->withSession($this->templates['validSession']) + $this->withSession($this->validSession) ->get($route) ->assertStatus(Response::HTTP_OK) ->assertSee($route); diff --git a/tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php b/tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php index 03a97caa..fba4e642 100644 --- a/tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php +++ b/tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php @@ -10,22 +10,21 @@ uses()->group('stateful', 'middleware', 'middleware.stateful', 'middleware.stateful.authenticate'); beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.clientSecret' => $this->secret, + 'auth0.cookieSecret' => uniqid(), + ]); + $this->laravel = app('auth0'); $this->guard = auth('testGuard'); $this->sdk = $this->laravel->getSdk(); - $this->config = $this->sdk->configuration(); - $this->session = $this->config->getSessionStorage(); - $this->transient = $this->config->getTransientStorage(); - - $this->secret = uniqid(); - - $this->config->setDomain('my-domain.auth0.com'); - $this->config->setClientId('my_client_id'); - $this->config->setClientSecret($this->secret); - $this->config->setCookieSecret('my_cookie_secret'); - $this->config->setStrategy(SdkConfiguration::STRATEGY_REGULAR); - $this->templates['validSession'] = [ + $this->validSession = [ 'auth0_session_user' => ['sub' => 'hello|world'], 'auth0_session_idToken' => uniqid(), 'auth0_session_accessToken' => uniqid(), @@ -81,7 +80,7 @@ return $route; }); - $this->withSession($this->templates['validSession']) + $this->withSession($this->validSession) ->get($route) ->assertStatus(Response::HTTP_OK) ->assertSee($route); @@ -97,7 +96,7 @@ return $route; }); - $this->withSession($this->templates['validSession']) + $this->withSession($this->validSession) ->get($route) ->assertStatus(Response::HTTP_OK) ->assertSee($route); @@ -113,7 +112,7 @@ return $route; }); - $this->withSession($this->templates['validSession']) + $this->withSession($this->validSession) ->get($route) ->assertStatus(Response::HTTP_FORBIDDEN); diff --git a/tests/Unit/Http/Middleware/Stateless/AuthorizeOptionalTest.php b/tests/Unit/Http/Middleware/Stateless/AuthorizeOptionalTest.php index 90f1eeaf..aded9fa6 100644 --- a/tests/Unit/Http/Middleware/Stateless/AuthorizeOptionalTest.php +++ b/tests/Unit/Http/Middleware/Stateless/AuthorizeOptionalTest.php @@ -12,21 +12,21 @@ uses()->group('stateful', 'middleware', 'middleware.stateless', 'middleware.stateless.authorize'); beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.audience' => [uniqid()], + 'auth0.clientSecret' => $this->secret, + 'auth0.cookieSecret' => uniqid(), + 'auth0.tokenAlgorithm' => Token::ALGO_HS256, + ]); + $this->laravel = app('auth0'); $this->guard = auth('testGuard'); $this->sdk = $this->laravel->getSdk(); - $this->config = $this->sdk->configuration(); - $this->session = $this->config->getSessionStorage(); - $this->transient = $this->config->getTransientStorage(); - - $this->secret = uniqid(); - - $this->config->setDomain('my-domain.auth0.com'); - $this->config->setClientId('my_client_id'); - $this->config->setClientSecret($this->secret); - $this->config->setCookieSecret('my_cookie_secret'); - $this->config->setTokenAlgorithm(Token::ALGO_HS256); - $this->config->setStrategy(SdkConfiguration::STRATEGY_API); }); it('does not assign a user when an incompatible guard is used', function (): void { @@ -72,14 +72,14 @@ }); $token = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => "https://my-domain.auth0.com/", + "iss" => 'https://' . config('auth0.domain') . '/', "sub" => "auth0|123456", "aud" => [ "https://example.com/health-api", "https://my-domain.auth0.com/userinfo", - "my_client_id" + config('auth0.clientId') ], - "azp" => "my_client_id", + "azp" => config('auth0.clientId'), "exp" => time() + 60, "iat" => time(), "scope" => "openid profile read:patients read:admin" @@ -101,14 +101,14 @@ }); $token = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => "https://my-domain.auth0.com/", + "iss" => 'https://' . config('auth0.domain') . '/', "sub" => "auth0|123456", "aud" => [ "https://example.com/health-api", "https://my-domain.auth0.com/userinfo", - "my_client_id" + config('auth0.clientId') ], - "azp" => "my_client_id", + "azp" => config('auth0.clientId'), "exp" => time() + 60, "iat" => time(), "scope" => "openid profile read:patients read:admin" @@ -130,14 +130,14 @@ }); $token = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => "https://my-domain.auth0.com/", + "iss" => 'https://' . config('auth0.domain') . '/', "sub" => "auth0|123456", "aud" => [ "https://example.com/health-api", "https://my-domain.auth0.com/userinfo", - "my_client_id" + config('auth0.clientId') ], - "azp" => "my_client_id", + "azp" => config('auth0.clientId'), "exp" => time() + 60, "iat" => time(), "scope" => "openid profile read:patients read:admin" diff --git a/tests/Unit/Http/Middleware/Stateless/AuthorizeTest.php b/tests/Unit/Http/Middleware/Stateless/AuthorizeTest.php index 2a0b2963..e59131f2 100644 --- a/tests/Unit/Http/Middleware/Stateless/AuthorizeTest.php +++ b/tests/Unit/Http/Middleware/Stateless/AuthorizeTest.php @@ -12,21 +12,21 @@ uses()->group('stateful', 'middleware', 'middleware.stateless', 'middleware.stateless.authorize'); beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.audience' => [uniqid()], + 'auth0.clientSecret' => $this->secret, + 'auth0.cookieSecret' => uniqid(), + 'auth0.tokenAlgorithm' => Token::ALGO_HS256, + ]); + $this->laravel = app('auth0'); $this->guard = auth('testGuard'); $this->sdk = $this->laravel->getSdk(); - $this->config = $this->sdk->configuration(); - $this->session = $this->config->getSessionStorage(); - $this->transient = $this->config->getTransientStorage(); - - $this->secret = uniqid(); - - $this->config->setDomain('my-domain.auth0.com'); - $this->config->setClientId('my_client_id'); - $this->config->setClientSecret($this->secret); - $this->config->setCookieSecret('my_cookie_secret'); - $this->config->setTokenAlgorithm(Token::ALGO_HS256); - $this->config->setStrategy(SdkConfiguration::STRATEGY_API); }); it('does not assign a user when an incompatible guard is used', function (): void { @@ -71,14 +71,14 @@ }); $token = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => "https://my-domain.auth0.com/", + "iss" => 'https://' . config('auth0.domain') . '/', "sub" => "auth0|123456", "aud" => [ "https://example.com/health-api", "https://my-domain.auth0.com/userinfo", - "my_client_id" + config('auth0.clientId') ], - "azp" => "my_client_id", + "azp" => config('auth0.clientId'), "exp" => time() + 60, "iat" => time(), "scope" => "openid profile read:patients read:admin" @@ -100,14 +100,14 @@ }); $token = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => "https://my-domain.auth0.com/", + "iss" => 'https://' . config('auth0.domain') . '/', "sub" => "auth0|123456", "aud" => [ "https://example.com/health-api", "https://my-domain.auth0.com/userinfo", - "my_client_id" + config('auth0.clientId') ], - "azp" => "my_client_id", + "azp" => config('auth0.clientId'), "exp" => time() + 60, "iat" => time(), "scope" => "openid profile read:patients read:admin" @@ -129,14 +129,14 @@ }); $token = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => "https://my-domain.auth0.com/", + "iss" => 'https://' . config('auth0.domain') . '/', "sub" => "auth0|123456", "aud" => [ "https://example.com/health-api", "https://my-domain.auth0.com/userinfo", - "my_client_id" + config('auth0.clientId') ], - "azp" => "my_client_id", + "azp" => config('auth0.clientId'), "exp" => time() + 60, "iat" => time(), "scope" => "openid profile read:patients read:admin" diff --git a/tests/Unit/Traits/ActingAsAuth0UserTest.php b/tests/Unit/Traits/ActingAsAuth0UserTest.php index 35b4243f..5b5f7a7b 100644 --- a/tests/Unit/Traits/ActingAsAuth0UserTest.php +++ b/tests/Unit/Traits/ActingAsAuth0UserTest.php @@ -14,19 +14,21 @@ uses(ActingAsAuth0User::class); beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.audience' => [uniqid()], + 'auth0.clientSecret' => $this->secret, + 'auth0.cookieSecret' => uniqid(), + 'auth0.tokenAlgorithm' => Token::ALGO_HS256, + ]); + $this->laravel = app('auth0'); $this->guard = auth('testGuard'); $this->sdk = $this->laravel->getSdk(); - $this->config = $this->sdk->configuration(); - $this->session = $this->config->getSessionStorage(); - $this->transient = $this->config->getTransientStorage(); - $this->secret = uniqid(); - $this->config->setDomain('my-domain.auth0.com'); - $this->config->setClientId('my_client_id'); - $this->config->setClientSecret($this->secret); - $this->config->setCookieSecret('my_cookie_secret'); - $this->config->setTokenAlgorithm(Token::ALGO_HS256); - $this->config->setStrategy(SdkConfiguration::STRATEGY_API); $this->user = ['sub' => uniqid(), 'scope' => 'openid profile email read:messages']; }); diff --git a/tests/Unit/Traits/ImpersonateTest.php b/tests/Unit/Traits/ImpersonateTest.php index 94194874..29c85213 100644 --- a/tests/Unit/Traits/ImpersonateTest.php +++ b/tests/Unit/Traits/ImpersonateTest.php @@ -16,19 +16,21 @@ uses(Impersonate::class); beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.audience' => [uniqid()], + 'auth0.clientSecret' => $this->secret, + 'auth0.cookieSecret' => uniqid(), + 'auth0.tokenAlgorithm' => Token::ALGO_HS256, + ]); + $this->laravel = app('auth0'); $this->guard = auth('testGuard'); $this->sdk = $this->laravel->getSdk(); - $this->config = $this->sdk->configuration(); - $this->session = $this->config->getSessionStorage(); - $this->transient = $this->config->getTransientStorage(); - $this->secret = uniqid(); - $this->config->setDomain('my-domain.auth0.com'); - $this->config->setClientId('my_client_id'); - $this->config->setClientSecret($this->secret); - $this->config->setCookieSecret('my_cookie_secret'); - $this->config->setTokenAlgorithm(Token::ALGO_HS256); - $this->config->setStrategy(SdkConfiguration::STRATEGY_API); $this->impersonating = Credential::create( user: new User(['sub' => uniqid()]), From 9bc0c684a8ea0574268492d2c21c0e2ef01e7fe0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 25 Apr 2023 22:58:01 -0500 Subject: [PATCH 319/525] Bump development dependencies --- composer.json | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/composer.json b/composer.json index fedf6a34..b9141aea 100644 --- a/composer.json +++ b/composer.json @@ -45,20 +45,21 @@ "psr/cache": "^2.0 || ^3.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.14", - "infection/infection": "^0.26", - "mockery/mockery": "^1.5", - "nunomaduro/larastan": "^2.5", - "orchestra/testbench": "^7.19 || ^8.0", + "friendsofphp/php-cs-fixer": "^3.16", + "infection/infection": "^0.26.20", + "mockery/mockery": "^1.5.1", + "nunomaduro/larastan": "^2.6.0", + "orchestra/testbench": "^7.19 || ^8.5.1", + "pestphp/pest": "^2.5.3", "pestphp/pest-plugin-laravel": "^2.0", - "pestphp/pest": "^2.0", - "phpstan/phpstan-strict-rules": "^1.5", - "phpstan/phpstan": "^1.10", + "phpstan/phpstan": "^1.10.14", + "phpstan/phpstan-strict-rules": "^1.5.1", "psalm/plugin-laravel": "^2.8", "psr-mock/http": "^1.0", - "rector/rector": "^0.15", - "vimeo/psalm": "^5.8", - "wikimedia/composer-merge-plugin": "^2.0" + "rector/rector": "^0.15.25", + "symfony/cache": "^6.2.8", + "vimeo/psalm": "^5.9", + "wikimedia/composer-merge-plugin": "^2.1.0" }, "minimum-stability": "dev", "prefer-stable": true, @@ -108,8 +109,10 @@ }, "scripts": { "mutate": "@php ./vendor/bin/infection --test-framework=pest --show-mutations", - "pest:coverage": "@php vendor/bin/pest --order-by random --compact --coverage --parallel", - "pest": "@php vendor/bin/pest --order-by random --compact --parallel", + "pest:coverage": "@php vendor/bin/pest --coverage --parallel --no-progress", + "pest:debug": "@php vendor/bin/pest --log-events-verbose-text pest.log --fail-on-risky --stop-on-error", + "pest:profile": "@php vendor/bin/pest --profile", + "pest": "@php vendor/bin/pest --order-by random --fail-on-risky", "phpcs:fix": "@php vendor/bin/php-cs-fixer fix", "phpcs": "@php vendor/bin/php-cs-fixer fix --dry-run --diff", "phpstan": "@php vendor/bin/phpstan analyze", From 9cd469f38b44b0799b1e98aefff64368f20b8182 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 25 Apr 2023 22:58:05 -0500 Subject: [PATCH 320/525] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c23d02f8..e5790a6d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ composer.local.json_ .php-cs-fixer.cache composer.local.old .vscode +pest.log From 24565bf4d56f859a0a0f398db407586a3f7db8f6 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 25 Apr 2023 22:58:07 -0500 Subject: [PATCH 321/525] Update php_pest.yml --- .github/workflows/php_pest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php_pest.yml b/.github/workflows/php_pest.yml index d6cf1ad5..fd966476 100644 --- a/.github/workflows/php_pest.yml +++ b/.github/workflows/php_pest.yml @@ -32,7 +32,7 @@ jobs: - run: composer install --no-progress --prefer-dist --optimize-autoloader - - run: vendor/bin/pest --order-by random --compact --parallel + - run: vendor/bin/pest --order-by random --parallel - uses: codecov/codecov-action@v3 with: From ee3cd1905c07f0321e57523cc0a5d9d53038a467 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 25 Apr 2023 22:59:10 -0500 Subject: [PATCH 322/525] Update phpunit.xml.dist --- phpunit.xml.dist | 52 +++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index bbb4fa0c..95b55956 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,29 +1,27 @@ - - - - ./src/ - - - - ./src/Event/ - ./src/Contract/ - ./src/Exception/ - - - - - - - - - - - tests/Unit - - - - - - + + + + + + + + + + tests/Unit + + + + + + + + ./src/ + + + ./src/Event/ + ./src/Contract/ + ./src/Exception/ + + From 887df74f70f6c35112bf89dfa7233b5bdecf283b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 25 Apr 2023 23:42:35 -0500 Subject: [PATCH 323/525] Update php_phpstan.yml --- .github/workflows/php_phpstan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php_phpstan.yml b/.github/workflows/php_phpstan.yml index beff1f1e..851f59db 100644 --- a/.github/workflows/php_phpstan.yml +++ b/.github/workflows/php_phpstan.yml @@ -31,4 +31,4 @@ jobs: - run: composer install --no-progress --prefer-dist --optimize-autoloader - - run: vendor/bin/phpstan analyze + - run: vendor/bin/phpstan analyze clear-result-cache && vendor/bin/phpstan analyze --no-ansi --no-progress --debug From 80b62a2a490d7dd9ee7b71965402e85afb159b44 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 25 Apr 2023 23:43:24 -0500 Subject: [PATCH 324/525] Update php_phpstan.yml --- .github/workflows/php_phpstan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php_phpstan.yml b/.github/workflows/php_phpstan.yml index 851f59db..0a22278f 100644 --- a/.github/workflows/php_phpstan.yml +++ b/.github/workflows/php_phpstan.yml @@ -31,4 +31,4 @@ jobs: - run: composer install --no-progress --prefer-dist --optimize-autoloader - - run: vendor/bin/phpstan analyze clear-result-cache && vendor/bin/phpstan analyze --no-ansi --no-progress --debug + - run: vendor/bin/phpstan analyze --no-ansi --no-progress --debug From 363703256cf8001617d721640ca93aa65fbc2ae5 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 25 Apr 2023 23:44:33 -0500 Subject: [PATCH 325/525] Update Auth0.php --- src/Auth0.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Auth0.php b/src/Auth0.php index 3aacf6b0..e760b3fc 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -110,7 +110,7 @@ public function getCredentials(): ?object public function getSdk(): SDKContract { if (! $this->sdk instanceof SDKContract) { - $this->setSdk(new SDK($this->getConfiguration())); + return $this->setSdk(new SDK($this->getConfiguration())); } return $this->sdk; From 6f23b16110cc57ff60a459aec4decc25b291d16b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 26 Apr 2023 06:18:16 -0500 Subject: [PATCH 326/525] Release 7.7.0 (#383) --- .github/ISSUE_TEMPLATE/Bug Report.yml | 1 + CHANGELOG.md | 14 ++++++++++++++ src/Auth0.php | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index dd05816e..d5b9e6ca 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -22,6 +22,7 @@ body: label: SDK Version description: What version of our Laravel plugin are you running? (`composer show | grep auth0/login`) options: + - SDK 7.7 - SDK 7.6 - SDK 7.5 - SDK 7.4 diff --git a/CHANGELOG.md b/CHANGELOG.md index d352d1ae..6beee8d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [7.7.0](https://github.com/auth0/laravel-auth0/tree/7.7.0) (2023-04-26) + +### Added + +- `Auth0\Laravel\Auth0` now has a `management()` shortcut method for issuing Management API calls. ([\#376](https://github.com/auth0/laravel-auth0/pull/376)) + +- `Auth0\Laravel\Auth0\Guard` now has a `refreshUser()` method for querying `/userinfo` endpoint and refreshing the authenticated user's cached profile data. ([\#375](https://github.com/auth0/laravel-auth0/pull/375)) + +- `Auth0\Laravel\Http\Controller\Stateful\Login` now raises a `LoginAttempting` event, offering an opportunity to customize the authorization parameters before the login redirect is issued. ([\#382](https://github.com/auth0/laravel-auth0/pull/382)) + +### Improved + +- The `tokenCache`, `managementTokenCache`, `sessionStorage` and `transientStorage` configuration values now support `false` or `string` values pointing to class names (e.g. `\Some\Cache::class`) or class aliases (e.g. `cache.psr6`) registered with Laravel. ([\#381](https://github.com/auth0/laravel-auth0/pull/381)) + ## [7.6.0](https://github.com/auth0/laravel-auth0/tree/7.6.0) (2023-04-12) ### Added diff --git a/src/Auth0.php b/src/Auth0.php index e760b3fc..48f216e6 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -26,7 +26,7 @@ final class Auth0 implements ServiceContract * * @var string */ - public const VERSION = '7.6.0'; + public const VERSION = '7.7.0'; public function __construct( private ?SDKContract $sdk = null, From 29fbb0aae07b56eef12d59e3f4f6993f3da6fc19 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 26 Apr 2023 09:57:54 -0500 Subject: [PATCH 327/525] Expand Configuration Properties (and Refactor Config Builder) (#381) --- src/Auth0.php | 184 +++++++++++++++++++++++++++++++-------- tests/Unit/Auth0Test.php | 104 ++++++++++++++++++++++ 2 files changed, 253 insertions(+), 35 deletions(-) diff --git a/src/Auth0.php b/src/Auth0.php index 48f216e6..310bb6ed 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -11,10 +11,12 @@ use Auth0\SDK\Auth0 as SDK; use Auth0\SDK\Configuration\SdkConfiguration as Configuration; use Auth0\SDK\Contract\API\ManagementInterface; -use Auth0\SDK\Contract\Auth0Interface as SDKContract; +use Auth0\SDK\Contract\{Auth0Interface as SDKContract, StoreInterface}; use Auth0\SDK\Utility\HttpTelemetry; +use Psr\Cache\CacheItemPoolInterface; use function in_array; +use function is_string; /** * Service that provides access to the Auth0 SDK. @@ -31,9 +33,144 @@ final class Auth0 implements ServiceContract public function __construct( private ?SDKContract $sdk = null, private ?Configuration $configuration = null, + private ?CacheItemPoolInterface $tokenCachePool = null, + private ?CacheItemPoolInterface $managementTokenCachePool = null, ) { } + private function bootManagementTokenCache(array $config): array + { + $managementTokenCache = $config['managementTokenCache'] ?? null; + + if (false === $managementTokenCache) { + unset($config['managementTokenCache']); + + return $config; + } + + if (null === $managementTokenCache) { + $managementTokenCache = $this->getManagementTokenCachePool(); + } + + if (is_string($managementTokenCache)) { + $managementTokenCache = app(trim($managementTokenCache)); + } + + $config['managementTokenCache'] = $managementTokenCache instanceof CacheItemPoolInterface ? $managementTokenCache : null; + + return $config; + } + + private function bootSessionStorage(array $config): array + { + $sessionStorage = $config['sessionStorage'] ?? null; + $sessionStorageId = $config['sessionStorageId'] ?? 'auth0_session'; + + if (false === $sessionStorage) { + unset($config['sessionStorage']); + + return $config; + } + + if (null === $sessionStorage) { + $sessionStorage = app(LaravelSession::class, [ + 'prefix' => $sessionStorageId, + ]); + } + + if (is_string($sessionStorage)) { + $sessionStorage = app(trim($sessionStorage), [ + 'prefix' => $sessionStorageId, + ]); + } + + $config['sessionStorage'] = $sessionStorage instanceof StoreInterface ? $sessionStorage : null; + + return $config; + } + + private function bootStrategy(array $config): array + { + $strategy = $config['strategy'] ?? Configuration::STRATEGY_REGULAR; + + if (! is_string($strategy)) { + $strategy = Configuration::STRATEGY_REGULAR; + } + + $config['strategy'] = $strategy; + + return $config; + } + + private function bootTokenCache(array $config): array + { + $tokenCache = $config['tokenCache'] ?? null; + + if (false === $tokenCache) { + unset($config['tokenCache']); + + return $config; + } + + if (null === $tokenCache) { + $tokenCache = $this->getTokenCachePool(); + } + + if (is_string($tokenCache)) { + $tokenCache = app(trim($tokenCache)); + } + + $config['tokenCache'] = $tokenCache instanceof CacheItemPoolInterface ? $tokenCache : null; + + return $config; + } + + private function bootTransientStorage(array $config): array + { + $transientStorage = $config['transientStorage'] ?? null; + $transientStorageId = $config['transientStorageId'] ?? 'auth0_transient'; + + if (false === $transientStorage) { + unset($config['transientStorage']); + + return $config; + } + + if (null === $transientStorage) { + $transientStorage = app(LaravelSession::class, [ + 'prefix' => $transientStorageId, + ]); + } + + if (is_string($transientStorage)) { + $transientStorage = app(trim($transientStorage), [ + 'prefix' => $transientStorageId, + ]); + } + + $config['transientStorage'] = $transientStorage instanceof StoreInterface ? $transientStorage : null; + + return $config; + } + + private function getManagementTokenCachePool(): CacheItemPoolInterface + { + if (! $this->managementTokenCachePool instanceof CacheItemPoolInterface) { + $this->managementTokenCachePool = app(LaravelCachePool::class); + } + + return $this->managementTokenCachePool; + } + + private function getTokenCachePool(): CacheItemPoolInterface + { + if (! $this->tokenCachePool instanceof CacheItemPoolInterface) { + $this->tokenCachePool = app(LaravelCachePool::class); + } + + return $this->tokenCachePool; + } + /** * Updates the Auth0 PHP SDK's telemetry to include the correct Laravel markers. */ @@ -53,49 +190,26 @@ public function getConfiguration(): Configuration /** * @var array $config */ - if (! isset($config['tokenCache']) || ! isset($config['managementTokenCache'])) { - $cache = new LaravelCachePool(); - - if (! isset($config['tokenCache'])) { - $config['tokenCache'] = $cache; - } - - if (! isset($config['managementTokenCache'])) { - $config['managementTokenCache'] = $cache; - } - } + // Give host application an opportunity to update the configuration before assigning defaults. $event = new Building($config); event($event); + $config = $event->getConfiguration(); - $configuration = new Configuration($event->getConfiguration()); + $config = $this->bootStrategy($config); + $config = $this->bootTokenCache($config); + $config = $this->bootManagementTokenCache($config); - if (! in_array($configuration->getStrategy(), [Configuration::STRATEGY_API, Configuration::STRATEGY_MANAGEMENT_API], true)) { - // If no sessionStorage is defined, use an LaravelSession store instance. - if (! isset($config['sessionStorage'])) { - $sessionStore = app(LaravelSession::class, [ - 'prefix' => $configuration->getSessionStorageId(), - ]); - - $configuration->setSessionStorage(sessionStorage: $sessionStore); - } - - // If no transientStorage is defined, use an LaravelSession store instance. - if (! isset($config['transientStorage'])) { - $transientStore = app(LaravelSession::class, [ - 'prefix' => $configuration->getTransientStorageId(), - ]); - - $configuration->setTransientStorage(transientStorage: $transientStore); - } + if (in_array($config['strategy'], Configuration::STRATEGIES_USING_SESSIONS, true)) { + $config = $this->bootSessionStorage($config); + $config = $this->bootTransientStorage($config); } - $this->configuration = $configuration; + $config = new Configuration($config); - // Give apps an opportunity to mutate the configuration before applying it. - $event = new Built($configuration); + // Give host application an opportunity to update the configuration before applying it. + $event = new Built($config); event($event); - $this->configuration = $event->getConfiguration(); } diff --git a/tests/Unit/Auth0Test.php b/tests/Unit/Auth0Test.php index 31ac32e2..c01cf55b 100644 --- a/tests/Unit/Auth0Test.php +++ b/tests/Unit/Auth0Test.php @@ -104,3 +104,107 @@ $updated = spl_object_id($laravel->getSdk()); expect($cache)->not->toBe($updated); }); + +test('bootStrategy() rejects non-string values', function (): void { + $method = new ReflectionMethod(Auth0::class, 'bootStrategy'); + $method->setAccessible(true); + + expect($method->invoke($this->laravel, ['strategy' => 123])) + ->toMatchArray(['strategy' => SdkConfiguration::STRATEGY_REGULAR]); +}); + +test('bootSessionStorage() behaves as expected', function (): void { + $method = new ReflectionMethod(Auth0::class, 'bootSessionStorage'); + $method->setAccessible(true); + + expect($method->invoke($this->laravel, [])) + ->sessionStorage->toBeInstanceOf(LaravelSession::class); + + expect($method->invoke($this->laravel, ['sessionStorage' => null])) + ->sessionStorage->toBeInstanceOf(LaravelSession::class); + + expect($method->invoke($this->laravel, ['sessionStorage' => false])) + ->sessionStorage->toBeNull(); + + expect($method->invoke($this->laravel, ['sessionStorage' => LaravelCachePool::class])) + ->sessionStorage->toBeNull(); + + expect($method->invoke($this->laravel, ['sessionStorage' => MemoryStore::class])) + ->sessionStorage->toBeInstanceOf(MemoryStore::class); + + $this->app->singleton('testStore', static fn (): MemoryStore => app(MemoryStore::class)); + + expect($method->invoke($this->laravel, ['sessionStorage' => 'testStore'])) + ->sessionStorage->toBeInstanceOf(MemoryStore::class); +}); + +test('bootTransientStorage() behaves as expected', function (): void { + $method = new ReflectionMethod(Auth0::class, 'bootTransientStorage'); + $method->setAccessible(true); + + expect($method->invoke($this->laravel, [])) + ->transientStorage->toBeInstanceOf(LaravelSession::class); + + expect($method->invoke($this->laravel, ['transientStorage' => null])) + ->transientStorage->toBeInstanceOf(LaravelSession::class); + + expect($method->invoke($this->laravel, ['transientStorage' => false])) + ->transientStorage->toBeNull(); + + expect($method->invoke($this->laravel, ['transientStorage' => LaravelCachePool::class])) + ->transientStorage->toBeNull(); + + expect($method->invoke($this->laravel, ['transientStorage' => MemoryStore::class])) + ->transientStorage->toBeInstanceOf(MemoryStore::class); + + $this->app->singleton('testStore', static fn (): MemoryStore => app(MemoryStore::class)); + + expect($method->invoke($this->laravel, ['transientStorage' => 'testStore'])) + ->transientStorage->toBeInstanceOf(MemoryStore::class); +}); + +test('bootTokenCache() behaves as expected', function (): void { + $method = new ReflectionMethod(Auth0::class, 'bootTokenCache'); + $method->setAccessible(true); + + expect($method->invoke($this->laravel, [])) + ->tokenCache->toBeInstanceOf(LaravelCachePool::class); + + expect($method->invoke($this->laravel, ['tokenCache' => null])) + ->tokenCache->toBeInstanceOf(LaravelCachePool::class); + + expect($method->invoke($this->laravel, ['tokenCache' => LaravelCachePool::class])) + ->tokenCache->toBeInstanceOf(LaravelCachePool::class); + + expect($method->invoke($this->laravel, ['tokenCache' => false])) + ->tokenCache->toBeNull(); + + expect($method->invoke($this->laravel, ['tokenCache' => MemoryStore::class])) + ->tokenCache->toBeNull(); + + expect($method->invoke($this->laravel, ['tokenCache' => 'cache.psr6'])) + ->tokenCache->toBeInstanceOf(CacheItemPoolInterface::class); +}); + +test('bootManagementTokenCache() behaves as expected', function (): void { + $method = new ReflectionMethod(Auth0::class, 'bootManagementTokenCache'); + $method->setAccessible(true); + + expect($method->invoke($this->laravel, [])) + ->managementTokenCache->toBeInstanceOf(LaravelCachePool::class); + + expect($method->invoke($this->laravel, ['managementTokenCache' => null])) + ->managementTokenCache->toBeInstanceOf(LaravelCachePool::class); + + expect($method->invoke($this->laravel, ['managementTokenCache' => LaravelCachePool::class])) + ->managementTokenCache->toBeInstanceOf(LaravelCachePool::class); + + expect($method->invoke($this->laravel, ['managementTokenCache' => false])) + ->managementTokenCache->toBeNull(); + + expect($method->invoke($this->laravel, ['managementTokenCache' => MemoryStore::class])) + ->managementTokenCache->toBeNull(); + + expect($method->invoke($this->laravel, ['managementTokenCache' => 'cache.psr6'])) + ->managementTokenCache->toBeInstanceOf(CacheItemPoolInterface::class); +}); From 9eb38df790da5532eb695f75a228effd87fed3ed Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 26 Apr 2023 10:01:22 -0500 Subject: [PATCH 328/525] Add `LoginAttempting` event for customizing authorization parameters (#382) --- docs/Events.md | 19 +++++++------ .../Event/Stateful/LoginAttempting.php | 27 ++++++++++++++++++ src/Event/Stateful/LoginAttempting.php | 28 +++++++++++++++++++ src/Http/Controller/Stateful/Login.php | 8 +++++- 4 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 src/Contract/Event/Stateful/LoginAttempting.php create mode 100644 src/Event/Stateful/LoginAttempting.php diff --git a/docs/Events.md b/docs/Events.md index 85d80a50..218dcb33 100644 --- a/docs/Events.md +++ b/docs/Events.md @@ -40,21 +40,22 @@ You can learn more about working with the Laravel event system in the [Laravel d During login with the `Auth0\Laravel\Http\Controller\Stateful\Login` controller, the following events may be raised: -| Event | Description | -| ------------------------------ | ----------------------------------------------------------------------------------- | -| `Illuminate\Auth\Events\Login` | Raised when a user is logging in. The model of the user is provided with the event. | +| Event | Description | +| ------------------------------------------------------- | -------------------------------------------------------------------------------------------- | +| `Illuminate\Auth\Events\Login` | Raised when a user is logging in. The model of the user is provided with the event. | +| `Auth0\Laravel\Contract\Event\Stateful\LoginAttempting` | Raised before the login redirect is issued, allowing an opportunity to customize parameters. | ## Callback Controller Events During callback with the `Auth0\Laravel\Http\Controller\Stateful\Callback` controller, the following events may be raised: -| Event | Description | -| --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `Illuminate\Auth\Events\Attempting` | Raised when a user is returned to the application after authenticating with Auth0. This is raised before verification of the authentication process begins. | -| `Illuminate\Auth\Events\Failed` | Raised when authentication with Auth0 failed. The reason is provided with the event as an array. | +| Event | Description | +| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Illuminate\Auth\Events\Attempting` | Raised when a user is returned to the application after authenticating with Auth0. This is raised before verification of the authentication process begins. | +| `Illuminate\Auth\Events\Failed` | Raised when authentication with Auth0 failed. The reason is provided with the event as an array. | | `Auth0\Laravel\Event\Stateful\AuthenticationFailed` | Raised when authentication with Auth0 failed. This provides an opportunity to intercept the exception thrown by the middleware, by using the event's `setThrowException()` method to `false`. You can also customize the type of exception thrown using `setException()`. | -| `Illuminate\Auth\Events\Illuminate\Auth\Events\Validated` | Raised when authentication was successful, but immediately before the user's session is established. | -| `Auth0\Laravel\Event\Stateful\AuthenticationSucceeded` | Raised when authentication was successful. The model of the authenticated user is provided with the event. | +| `Illuminate\Auth\Events\Illuminate\Auth\Events\Validated` | Raised when authentication was successful, but immediately before the user's session is established. | +| `Auth0\Laravel\Event\Stateful\AuthenticationSucceeded` | Raised when authentication was successful. The model of the authenticated user is provided with the event. | ## Logout Controller Events diff --git a/src/Contract/Event/Stateful/LoginAttempting.php b/src/Contract/Event/Stateful/LoginAttempting.php new file mode 100644 index 00000000..3c278d0b --- /dev/null +++ b/src/Contract/Event/Stateful/LoginAttempting.php @@ -0,0 +1,27 @@ +parameters; + } + + public function setParameters(array $parameters): self + { + $this->parameters = $parameters; + + return $this; + } +} diff --git a/src/Http/Controller/Stateful/Login.php b/src/Http/Controller/Stateful/Login.php index 203682ac..1979b4b3 100644 --- a/src/Http/Controller/Stateful/Login.php +++ b/src/Http/Controller/Stateful/Login.php @@ -8,6 +8,7 @@ use Auth0\Laravel\Contract\Auth\Guard as GuardContract; use Auth0\Laravel\Contract\Entities\Credential; use Auth0\Laravel\Contract\Http\Controller\Stateful\Login as LoginContract; +use Auth0\Laravel\Event\Stateful\LoginAttempting; use Auth0\Laravel\Http\Controller\ControllerAbstract; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; @@ -34,7 +35,12 @@ public function __invoke( return redirect()->intended(config('auth0.routes.home', '/')); } - $url = $this->getSdk()->login(); + $event = new LoginAttempting(); + event($event); + + $url = $this->getSdk()->login( + params: $event->getParameters(), + ); return redirect()->away($url); } From 7a24f63095bbaf65436d3114be8e0e4124f2ef06 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 26 Apr 2023 10:48:32 -0500 Subject: [PATCH 329/525] Update tests --- tests/Unit/Auth/GuardTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/Unit/Auth/GuardTest.php b/tests/Unit/Auth/GuardTest.php index 7da631a4..68717cdd 100644 --- a/tests/Unit/Auth/GuardTest.php +++ b/tests/Unit/Auth/GuardTest.php @@ -7,12 +7,29 @@ use Auth0\Laravel\Exception\AuthenticationException; use Auth0\Laravel\Entities\Credential; use Auth0\Laravel\Model\Stateful\User; +use Auth0\SDK\Configuration\SdkConfiguration; use Illuminate\Support\Facades\Route; uses()->group('auth', 'auth.guard', 'auth.guard.shared'); beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.domain' => uniqid() . '.auth0.com', + 'auth0.clientId' => uniqid(), + 'auth0.clientSecret' => $this->secret, + 'auth0.cookieSecret' => uniqid(), + 'auth0.routes.home' => '/' . uniqid(), + ]); + + $this->laravel = app('auth0'); $this->guard = auth('testGuard'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + $this->session = $this->config->getSessionStorage(); + $this->user = new User(['sub' => uniqid('auth0|')]); Route::middleware('auth:auth0')->get('/test', function () { From f50eab94dfac4161a6cf04f59ddcd2a3eadc9194 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 1 May 2023 17:34:39 -0500 Subject: [PATCH 330/525] Update workflows --- .github/workflows/php_composer_normalize.yml | 7 +++++- .github/workflows/php_composer_validate.yml | 7 +++++- .github/workflows/php_pest.yml | 22 ++++++------------- .github/workflows/php_phpcsf.yml | 22 ++++++------------- .github/workflows/php_phpstan.yml | 22 ++++++------------- .github/workflows/php_psalm.yml | 22 ++++++------------- .github/workflows/php_rector.yml | 22 ++++++------------- .github/workflows/sec_semgrep.yml | 19 ++-------------- .github/workflows/sec_snyk.yml | 23 ++++---------------- 9 files changed, 53 insertions(+), 113 deletions(-) diff --git a/.github/workflows/php_composer_normalize.yml b/.github/workflows/php_composer_normalize.yml index 304bd54c..95c696c0 100644 --- a/.github/workflows/php_composer_normalize.yml +++ b/.github/workflows/php_composer_normalize.yml @@ -1,15 +1,20 @@ name: "Composer Normalize" on: - pull_request_target: {} + pull_request: {} push: branches: - main +permissions: {} + jobs: normalize: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + with: + persist-credentials: false + - uses: docker://ergebnis/composer-normalize-action diff --git a/.github/workflows/php_composer_validate.yml b/.github/workflows/php_composer_validate.yml index a05a3a3b..487d814b 100644 --- a/.github/workflows/php_composer_validate.yml +++ b/.github/workflows/php_composer_validate.yml @@ -1,15 +1,20 @@ name: "Composer Validate" on: - pull_request_target: {} + pull_request: {} push: branches: - main +permissions: {} + jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + with: + persist-credentials: false + - run: composer validate diff --git a/.github/workflows/php_pest.yml b/.github/workflows/php_pest.yml index fd966476..9436907b 100644 --- a/.github/workflows/php_pest.yml +++ b/.github/workflows/php_pest.yml @@ -1,36 +1,28 @@ name: "PEST" on: - pull_request_target: {} + pull_request: {} push: branches: - main +permissions: {} + jobs: pest: runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - uses: actions/checkout@v3 + with: + persist-credentials: false - uses: shivammathur/setup-php@v2 with: - php-version: 8.1 + php-version: "8.1" coverage: pcov - - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - - uses: actions/cache@v3 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-composer- - - - run: composer install --no-progress --prefer-dist --optimize-autoloader + - run: composer install --no-progress - run: vendor/bin/pest --order-by random --parallel diff --git a/.github/workflows/php_phpcsf.yml b/.github/workflows/php_phpcsf.yml index e3b39756..dd9bb6c9 100644 --- a/.github/workflows/php_phpcsf.yml +++ b/.github/workflows/php_phpcsf.yml @@ -1,34 +1,26 @@ name: "PHP CS Fixer" on: - pull_request_target: {} + pull_request: {} push: branches: - main +permissions: {} + jobs: phpcsf: runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - uses: actions/checkout@v3 - - - uses: shivammathur/setup-php@v2 with: - php-version: 8.1 - - - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + persist-credentials: false - - uses: actions/cache@v3 + - uses: shivammathur/setup-php@v2 with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-composer- + php-version: "8.1" - - run: composer install --no-progress --prefer-dist --optimize-autoloader + - run: composer install --no-progress - run: vendor/bin/php-cs-fixer fix src --dry-run --diff diff --git a/.github/workflows/php_phpstan.yml b/.github/workflows/php_phpstan.yml index 0a22278f..aac8c128 100644 --- a/.github/workflows/php_phpstan.yml +++ b/.github/workflows/php_phpstan.yml @@ -1,34 +1,26 @@ name: "PHPStan" on: - pull_request_target: {} + pull_request: {} push: branches: - main +permissions: {} + jobs: phpstan: runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - uses: actions/checkout@v3 - - - uses: shivammathur/setup-php@v2 with: - php-version: 8.1 - - - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + persist-credentials: false - - uses: actions/cache@v3 + - uses: shivammathur/setup-php@v2 with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-composer- + php-version: "8.1" - - run: composer install --no-progress --prefer-dist --optimize-autoloader + - run: composer install --no-progress - run: vendor/bin/phpstan analyze --no-ansi --no-progress --debug diff --git a/.github/workflows/php_psalm.yml b/.github/workflows/php_psalm.yml index 8280a6bc..7e1d0c6b 100644 --- a/.github/workflows/php_psalm.yml +++ b/.github/workflows/php_psalm.yml @@ -1,34 +1,26 @@ name: "Psalm" on: - pull_request_target: {} + pull_request: {} push: branches: - main +permissions: {} + jobs: psalm: runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - uses: actions/checkout@v3 - - - uses: shivammathur/setup-php@v2 with: - php-version: 8.1 - - - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + persist-credentials: false - - uses: actions/cache@v3 + - uses: shivammathur/setup-php@v2 with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-composer- + php-version: "8.1" - - run: composer install --no-progress --prefer-dist --optimize-autoloader + - run: composer install --no-progress - run: vendor/bin/psalm diff --git a/.github/workflows/php_rector.yml b/.github/workflows/php_rector.yml index 34ae9cf9..fd0851b1 100644 --- a/.github/workflows/php_rector.yml +++ b/.github/workflows/php_rector.yml @@ -1,34 +1,26 @@ name: "Rector" on: - pull_request_target: {} + pull_request: {} push: branches: - main +permissions: {} + jobs: rector: runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - uses: actions/checkout@v3 - - - uses: shivammathur/setup-php@v2 with: - php-version: 8.1 - - - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + persist-credentials: false - - uses: actions/cache@v3 + - uses: shivammathur/setup-php@v2 with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-composer- + php-version: "8.1" - - run: composer install --no-progress --prefer-dist --optimize-autoloader + - run: composer install --no-progress - run: vendor/bin/rector process --dry-run diff --git a/.github/workflows/sec_semgrep.yml b/.github/workflows/sec_semgrep.yml index 4bc66a5f..e9be6baf 100644 --- a/.github/workflows/sec_semgrep.yml +++ b/.github/workflows/sec_semgrep.yml @@ -1,26 +1,21 @@ name: "Semgrep" on: - pull_request_target: {} push: branches: - main -permissions: - security-events: write - jobs: semgrep: runs-on: ubuntu-latest - strategy: - fail-fast: false - container: image: returntocorp/semgrep steps: - uses: actions/checkout@v3 + with: + persist-credentials: false - run: semgrep scan --sarif --output=semgrep.sarif env: @@ -32,13 +27,3 @@ jobs: SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} SEMGREP_REPO_NAME: "auth0/auth0-PHP" SEMGREP_REPO_URL: "https://github.com/auth0/auth0-PHP" - - - uses: andstor/file-existence-action@v1 - id: sarif_file_exists - with: - files: "semgrep.sarif" - - - uses: github/codeql-action/upload-sarif@v2 - with: - sarif_file: semgrep.sarif - if: always() diff --git a/.github/workflows/sec_snyk.yml b/.github/workflows/sec_snyk.yml index 93cb3e7b..5adb0f2d 100644 --- a/.github/workflows/sec_snyk.yml +++ b/.github/workflows/sec_snyk.yml @@ -1,33 +1,28 @@ name: "Snyk" on: - pull_request_target: {} push: branches: - main -permissions: - security-events: write - jobs: snyk: runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - uses: shivammathur/setup-php@v2 with: - php-version: 8.1 + php-version: "8.1" coverage: none extensions: mbstring env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: actions/checkout@v3 + with: + persist-credentials: false - - run: composer update --no-interaction --no-progress + - run: composer install --no-progress --prefer-dist --optimize-autoloader - uses: snyk/actions/php@master continue-on-error: true @@ -35,13 +30,3 @@ jobs: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: args: --severity-threshold=high --sarif-file-output=snyk.sarif - - - uses: andstor/file-existence-action@v1 - id: sarif_file_exists - with: - files: "snyk.sarif" - - - uses: github/codeql-action/upload-sarif@v2 - if: steps.sarif_file_exists.outputs.files_exists == 'true' - with: - sarif_file: snyk.sarif From 806b36db3eb41577125a3157094b344ed6289ccc Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 1 May 2023 17:38:33 -0500 Subject: [PATCH 331/525] Update `pest:debug` command --- composer.json | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index b9141aea..9772532c 100644 --- a/composer.json +++ b/composer.json @@ -39,14 +39,13 @@ "ext-json": "*", "ext-mbstring": "*", "auth0/auth0-php": "^8.5", - "illuminate/contracts": "^9.0 || ^10.0", - "illuminate/http": "^9.0 || ^10.0", - "illuminate/support": "^9.0 || ^10.0", - "psr/cache": "^2.0 || ^3.0" + "illuminate/contracts": "^9 || ^10", + "illuminate/http": "^9 || ^10", + "illuminate/support": "^9 || ^10", + "psr/cache": "^2 || ^3" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.16", - "infection/infection": "^0.26.20", "mockery/mockery": "^1.5.1", "nunomaduro/larastan": "^2.6.0", "orchestra/testbench": "^7.19 || ^8.5.1", @@ -108,9 +107,8 @@ } }, "scripts": { - "mutate": "@php ./vendor/bin/infection --test-framework=pest --show-mutations", "pest:coverage": "@php vendor/bin/pest --coverage --parallel --no-progress", - "pest:debug": "@php vendor/bin/pest --log-events-verbose-text pest.log --fail-on-risky --stop-on-error", + "pest:debug": "@php vendor/bin/pest --log-events-verbose-text pest.log --fail-on-risky --stop-on-failure", "pest:profile": "@php vendor/bin/pest --profile", "pest": "@php vendor/bin/pest --order-by random --fail-on-risky", "phpcs:fix": "@php vendor/bin/php-cs-fixer fix", From 00e5b33fda19489fb5e348e322211d7523de490a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 1 May 2023 17:41:40 -0500 Subject: [PATCH 332/525] Update sec_snyk.yml --- .github/workflows/sec_snyk.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sec_snyk.yml b/.github/workflows/sec_snyk.yml index 5adb0f2d..9a9fa1b4 100644 --- a/.github/workflows/sec_snyk.yml +++ b/.github/workflows/sec_snyk.yml @@ -22,7 +22,7 @@ jobs: with: persist-credentials: false - - run: composer install --no-progress --prefer-dist --optimize-autoloader + - run: composer install --no-progress - uses: snyk/actions/php@master continue-on-error: true From cd22d377266ecc1b84bd265657f11f9838eb1af0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 1 May 2023 17:41:44 -0500 Subject: [PATCH 333/525] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e5790a6d..852f2ef6 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ composer.local.json_ composer.local.old .vscode pest.log +NOTES.md From 2d15ee28154c8eb81ac5d70f3a84933ba43f7f19 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 18 May 2023 01:03:12 -0500 Subject: [PATCH 334/525] Merge 7.8.0 (#393) --- .gitattributes | 5 +- .github/workflows/php_pest.yml | 2 +- .php-cs-fixer.dist.php | 25 +- .phpcs.xml.dist | 13 + CHANGELOG.md | 33 + README.md | 328 ++++----- codecov.yml | 12 + composer.json | 45 +- config/auth0.php | 106 ++- deprecated/Cache/LaravelCacheItem.php | 56 ++ deprecated/Cache/LaravelCachePool.php | 18 + deprecated/Contract/Auth/Guard.php | 16 + deprecated/Contract/Auth/User/Provider.php | 16 + deprecated/Contract/Auth/User/Repository.php | 16 + deprecated/Contract/Auth0.php | 16 + deprecated/Contract/Configuration.php | 16 + deprecated/Contract/Entities/Credential.php | 16 + deprecated/Contract/Event/Auth0Event.php | 16 + .../Contract/Event/Configuration/Building.php | 16 + .../Contract/Event/Configuration/Built.php | 16 + .../Event/Middleware/StatefulRequest.php | 16 + .../Event/Middleware/StatelessRequest.php | 16 + .../Event/Stateful/AuthenticationFailed.php | 16 + .../Stateful/AuthenticationSucceeded.php | 16 + .../Event/Stateful/LoginAttempting.php | 16 + .../Contract/Event/Stateful/TokenExpired.php | 16 + .../Event/Stateful/TokenRefreshFailed.php | 16 + .../Event/Stateful/TokenRefreshSucceeded.php | 16 + .../Stateless/TokenVerificationAttempting.php | 16 + .../Stateless/TokenVerificationFailed.php | 16 + .../Stateless/TokenVerificationSucceeded.php | 16 + .../Exception/AuthenticationException.php | 16 + .../Contract/Exception/GuardException.php | 16 + .../Contract/Exception/SessionException.php | 16 + .../Exception/Stateful/CallbackException.php | 16 + .../Http/Controller/Stateful/Callback.php | 16 + .../Http/Controller/Stateful/Login.php | 16 + .../Http/Controller/Stateful/Logout.php | 16 + .../Http/Middleware/Stateful/Authenticate.php | 16 + .../Stateful/AuthenticateOptional.php | 16 + .../Http/Middleware/Stateless/Authorize.php | 16 + .../Stateless/AuthorizeOptional.php | 16 + deprecated/Contract/Model/Stateful/User.php | 16 + deprecated/Contract/Model/Stateless/User.php | 16 + deprecated/Contract/Model/User.php | 16 + deprecated/Contract/ServiceProvider.php | 16 + deprecated/DEPRECATED.md | 3 + deprecated/Event/Configuration/Building.php | 16 + deprecated/Event/Configuration/Built.php | 16 + .../Event/Middleware/StatefulRequest.php | 16 + .../Event/Middleware/StatelessRequest.php | 16 + .../Event/Stateful/AuthenticationFailed.php | 16 + .../Stateful/AuthenticationSucceeded.php | 16 + deprecated/Event/Stateful/LoginAttempting.php | 16 + deprecated/Event/Stateful/TokenExpired.php | 16 + .../Event/Stateful/TokenRefreshFailed.php | 16 + .../Event/Stateful/TokenRefreshSucceeded.php | 16 + .../Stateless/TokenVerificationAttempting.php | 16 + .../Stateless/TokenVerificationFailed.php | 16 + .../Stateless/TokenVerificationSucceeded.php | 16 + .../Exception/AuthenticationException.php | 16 + deprecated/Exception/GuardException.php | 16 + deprecated/Exception/SessionException.php | 16 + .../Exception/Stateful/CallbackException.php | 16 + .../Http/Controller/Stateful/Callback.php | 16 + deprecated/Http/Controller/Stateful/Login.php | 16 + .../Http/Controller/Stateful/Logout.php | 16 + deprecated/Http/Middleware/Guard.php | 16 + .../Http/Middleware/Stateful/Authenticate.php | 16 + .../Stateful/AuthenticateOptional.php | 16 + .../Http/Middleware/Stateless/Authorize.php | 16 + .../Stateless/AuthorizeOptional.php | 16 + deprecated/Model/Imposter.php | 17 + deprecated/Model/Stateful/User.php | 17 + deprecated/Model/Stateless/User.php | 17 + deprecated/Model/User.php | 16 + deprecated/Store/LaravelSession.php | 18 + docs/Configuration.md | 160 +++++ docs/Events.md | 46 +- docs/Installation.md | 21 + docs/{Management API.md => Management.md} | 8 +- ...er Models and Repositories.md => Users.md} | 90 ++- infection.json5.dist | 11 - phpstan.neon.dist | 5 +- phpunit.xml.dist | 5 +- psalm.xml.dist | 3 + rector.php | 105 ++- src/Auth/Guard.php | 675 ++++-------------- src/Auth0.php | 267 +------ src/Bridges/BridgeAbstract.php | 14 + src/Bridges/BridgeContract.php | 12 + src/Bridges/CacheBridge.php | 16 + .../CacheBridgeAbstract.php} | 163 +++-- src/Bridges/CacheBridgeContract.php | 14 + src/Bridges/CacheItemBridge.php | 55 ++ src/Bridges/CacheItemBridgeAbstract.php | 60 ++ src/Bridges/CacheItemBridgeContract.php | 20 + src/Bridges/SessionBridge.php | 16 + .../SessionBridgeAbstract.php} | 99 ++- src/Bridges/SessionBridgeContract.php | 14 + src/Cache/LaravelCacheItem.php | 94 --- src/Configuration.php | 487 ++++++++++++- src/ConfigurationContract.php | 47 ++ src/Contract/Auth/User/Provider.php | 15 - src/Contract/Configuration.php | 24 - src/Contract/Event/Configuration/Building.php | 27 - .../Event/Middleware/StatefulRequest.php | 9 - .../Event/Middleware/StatelessRequest.php | 9 - src/Contract/Event/Stateful/TokenExpired.php | 9 - .../Event/Stateful/TokenRefreshFailed.php | 9 - .../Event/Stateful/TokenRefreshSucceeded.php | 9 - .../Exception/AuthenticationException.php | 15 - src/Contract/Exception/GuardException.php | 25 - src/Contract/Exception/SessionException.php | 11 - .../Exception/Stateful/CallbackException.php | 11 - src/Contract/Model/Stateful/User.php | 9 - src/Contract/Model/Stateless/User.php | 9 - src/Contract/ServiceProvider.php | 9 - src/Controllers/CallbackController.php | 14 + .../CallbackControllerAbstract.php} | 76 +- .../CallbackControllerContract.php} | 4 +- src/Controllers/ControllerAbstract.php | 23 + src/Controllers/ControllerContract.php | 12 + src/Controllers/LoginController.php | 14 + src/Controllers/LoginControllerAbstract.php | 54 ++ .../LoginControllerContract.php} | 4 +- src/Controllers/LogoutController.php | 14 + src/Controllers/LogoutControllerAbstract.php | 51 ++ .../LogoutControllerContract.php} | 4 +- src/Entities/Credential.php | 167 ----- src/Entities/CredentialEntity.php | 118 +++ src/Entities/CredentialEntityAbstract.php | 132 ++++ .../CredentialEntityContract.php} | 47 +- src/Entities/EntityAbstract.php | 12 + src/Entities/EntityContract.php | 12 + src/Entities/InstanceEntity.php | 17 + src/Entities/InstanceEntityAbstract.php | 292 ++++++++ .../InstanceEntityContract.php} | 23 +- src/Entities/InstanceEntityTrait.php | 62 ++ src/Event/Configuration/Building.php | 27 - src/Event/Configuration/Built.php | 28 - src/Event/Middleware/StatefulRequest.php | 19 - src/Event/Middleware/StatelessRequest.php | 19 - src/Event/Stateful/AuthenticationFailed.php | 43 -- .../Stateful/AuthenticationSucceeded.php | 29 - src/Event/Stateful/LoginAttempting.php | 28 - src/Event/Stateful/TokenExpired.php | 12 - src/Event/Stateful/TokenRefreshFailed.php | 12 - src/Event/Stateful/TokenRefreshSucceeded.php | 12 - .../Stateless/TokenVerificationAttempting.php | 29 - .../Stateless/TokenVerificationFailed.php | 28 - .../Stateless/TokenVerificationSucceeded.php | 27 - src/Events/Auth0EventContract.php | 16 + src/Events/AuthenticationFailed.php | 14 + src/Events/AuthenticationFailedAbstract.php | 42 ++ .../AuthenticationFailedContract.php} | 11 +- src/Events/AuthenticationSucceeded.php | 14 + .../AuthenticationSucceededAbstract.php | 30 + .../AuthenticationSucceededContract.php} | 9 +- .../BuildingConfigurationEvent.php | 14 + .../BuildingConfigurationEventAbstract.php | 30 + .../BuildingConfigurationEventContract.php | 32 + .../Configuration/BuiltConfigurationEvent.php | 14 + .../BuiltConfigurationEventAbstract.php | 31 + .../BuiltConfigurationEventContract.php} | 10 +- .../EventAbstract.php} | 10 +- .../EventContract.php} | 7 +- src/Events/LoginAttempting.php | 14 + src/Events/LoginAttemptingAbstract.php | 28 + .../LoginAttemptingContract.php} | 9 +- .../Middleware/StatefulMiddlewareRequest.php | 9 + .../StatefulMiddlewareRequestAbstract.php | 18 + .../StatefulMiddlewareRequestContract.php | 14 + .../Middleware/StatelessMiddlewareRequest.php | 9 + .../StatelessMiddlewareRequestAbstract.php | 18 + .../StatelessMiddlewareRequestContract.php | 14 + src/Events/TokenExpired.php | 14 + src/Events/TokenExpiredAbstract.php | 14 + src/Events/TokenExpiredContract.php | 12 + src/Events/TokenRefreshFailed.php | 14 + src/Events/TokenRefreshFailedAbstract.php | 14 + src/Events/TokenRefreshFailedContract.php | 12 + src/Events/TokenRefreshSucceeded.php | 14 + src/Events/TokenRefreshSucceededAbstract.php | 14 + src/Events/TokenRefreshSucceededContract.php | 12 + src/Events/TokenVerificationAttempting.php | 14 + .../TokenVerificationAttemptingAbstract.php | 29 + .../TokenVerificationAttemptingContract.php} | 9 +- src/Events/TokenVerificationFailed.php | 14 + .../TokenVerificationFailedAbstract.php | 31 + .../TokenVerificationFailedContract.php} | 7 +- src/Events/TokenVerificationSucceeded.php | 14 + .../TokenVerificationSucceededAbstract.php | 29 + .../TokenVerificationSucceededContract.php} | 7 +- src/Exception/AuthenticationException.php | 16 - src/Exception/GuardException.php | 16 - src/Exception/SessionException.php | 20 - src/Exception/Stateful/CallbackException.php | 20 - src/Exceptions/AuthenticationException.php | 16 + .../AuthenticationExceptionAbstract.php | 16 + .../AuthenticationExceptionContract.php | 20 + src/Exceptions/ControllerException.php | 16 + .../ControllerExceptionAbstract.php | 16 + .../ControllerExceptionContract.php | 20 + .../CallbackControllerException.php | 16 + .../CallbackControllerExceptionAbstract.php | 18 + .../CallbackControllerExceptionContract.php | 22 + src/Exceptions/ExceptionAbstract.php | 18 + src/Exceptions/ExceptionContract.php | 18 + src/Exceptions/GuardException.php | 16 + src/Exceptions/GuardExceptionAbstract.php | 16 + src/Exceptions/GuardExceptionContract.php | 30 + src/Exceptions/SessionException.php | 16 + src/Exceptions/SessionExceptionAbstract.php | 16 + src/Exceptions/SessionExceptionContract.php | 20 + src/Facade/Auth0.php | 10 +- src/Guards/AuthenticationGuard.php | 388 ++++++++++ src/Guards/AuthenticationGuardContract.php | 37 + src/Guards/AuthorizationGuard.php | 230 ++++++ src/Guards/AuthorizationGuardContract.php | 33 + src/Guards/GuardAbstract.php | 360 ++++++++++ .../Guard.php => Guards/GuardContract.php} | 121 +++- src/Http/Controller/ControllerAbstract.php | 29 - src/Http/Controller/Stateful/Login.php | 47 -- src/Http/Controller/Stateful/Logout.php | 49 -- src/Http/Middleware/MiddlewareAbstract.php | 21 - src/Http/Middleware/Stateful/Authenticate.php | 54 -- .../Stateful/AuthenticateOptional.php | 46 -- src/Http/Middleware/Stateless/Authorize.php | 51 -- .../Stateless/AuthorizeOptional.php | 46 -- src/Middleware/AuthenticateMiddleware.php | 14 + .../AuthenticateMiddlewareAbstract.php | 53 ++ .../AuthenticateMiddlewareContract.php} | 9 +- .../AuthenticateOptionalMiddleware.php | 14 + ...AuthenticateOptionalMiddlewareAbstract.php | 44 ++ ...uthenticateOptionalMiddlewareContract.php} | 9 +- src/Middleware/AuthenticatorMiddleware.php | 26 + .../AuthenticatorMiddlewareContract.php | 12 + src/Middleware/AuthorizeMiddleware.php | 14 + .../AuthorizeMiddlewareAbstract.php | 50 ++ .../AuthorizeMiddlewareContract.php} | 9 +- .../AuthorizeOptionalMiddleware.php | 14 + .../AuthorizeOptionalMiddlewareAbstract.php | 46 ++ .../AuthorizeOptionalMiddlewareContract.php} | 9 +- src/Middleware/AuthorizerMiddleware.php | 26 + .../AuthorizerMiddlewareContract.php | 12 + src/Middleware/GuardMiddleware.php | 16 + .../GuardMiddlewareAbstract.php} | 17 +- src/Middleware/GuardMiddlewareContract.php | 12 + src/Middleware/MiddlewareAbstract.php | 37 + src/Middleware/MiddlewareContract.php | 14 + src/Model/Imposter.php | 11 - src/Model/Stateful/User.php | 15 - src/Model/Stateless/User.php | 15 - src/Service.php | 17 + src/ServiceAbstract.php | 63 ++ src/ServiceContract.php | 11 + src/ServiceProvider.php | 77 +- src/ServiceProviderAbstract.php | 234 ++++++ src/ServiceProviderContract.php | 44 ++ src/Traits/ActingAsAuth0User.php | 60 +- src/Traits/Impersonate.php | 73 +- src/UserProvider.php | 16 + .../Provider.php => UserProviderAbstract.php} | 155 ++-- src/UserProviderContract.php | 18 + .../Repository.php => UserRepository.php} | 15 +- src/UserRepositoryAbstract.php | 19 + ...ository.php => UserRepositoryContract.php} | 7 +- src/Users/ImposterUser.php | 15 + src/Users/ImposterUserContract.php | 12 + src/Users/StatefulUser.php | 15 + src/Users/StatefulUserContract.php | 12 + src/Users/StatelessUser.php | 15 + src/Users/StatelessUserContract.php | 12 + .../User.php => Users/UserAbstract.php} | 43 +- .../Model/User.php => Users/UserContract.php} | 13 +- src/Users/UserTrait.php | 27 + tests/Pest.php | 113 ++- tests/TestCase.php | 52 +- tests/Unit/Auth/GuardStatefulTest.php | 184 ++--- tests/Unit/Auth/GuardStatelessTest.php | 28 +- tests/Unit/Auth/GuardTest.php | 246 ++++++- tests/Unit/Auth/User/ProviderTest.php | 105 --- .../CacheBridgeTest.php} | 50 +- .../CacheItemBridgeTest.php} | 22 +- .../SessionBridgeTest.php} | 10 +- tests/Unit/ConfigurationTest.php | 95 ++- .../CallbackControllerTest.php} | 86 +-- .../LoginControllerTest.php} | 39 +- .../Unit/Controllers/LogoutControllerTest.php | 63 ++ ...ntialTest.php => CredentialEntityTest.php} | 95 +-- tests/Unit/Entities/InstanceEntityTest.php | 62 ++ tests/Unit/Guards/AuthenticationGuardTest.php | 431 +++++++++++ tests/Unit/Guards/AuthorizationGuardTest.php | 218 ++++++ .../Http/Controller/Stateful/LogoutTest.php | 57 -- .../AuthenticateMiddlewareTest.php} | 32 +- .../AuthenticateOptionalMiddlewareTest.php} | 26 +- .../AuthenticatorMiddlewareTest.php | 39 + .../AuthorizeMiddlewareTest.php} | 43 +- .../AuthorizeOptionalMiddlewareTest.php} | 43 +- .../Middleware/AuthorizerMiddlewareTest.php | 39 + .../GuardMiddlewareTest.php} | 12 +- tests/Unit/ServiceProviderTest.php | 506 +++++++++++-- tests/Unit/{Auth0Test.php => ServiceTest.php} | 115 +-- tests/Unit/Traits/ActingAsAuth0UserTest.php | 142 +++- tests/Unit/Traits/ImpersonateTest.php | 361 ++++++++-- tests/Unit/UserProviderTest.php | 159 +++++ ...ositoryTest.php => UserRepositoryTest.php} | 6 +- tests/Unit/{Model => Users}/UserTest.php | 26 +- tests/constants.php | 3 - 310 files changed, 9717 insertions(+), 3720 deletions(-) create mode 100644 .phpcs.xml.dist create mode 100644 codecov.yml create mode 100644 deprecated/Cache/LaravelCacheItem.php create mode 100644 deprecated/Cache/LaravelCachePool.php create mode 100644 deprecated/Contract/Auth/Guard.php create mode 100644 deprecated/Contract/Auth/User/Provider.php create mode 100644 deprecated/Contract/Auth/User/Repository.php create mode 100644 deprecated/Contract/Auth0.php create mode 100644 deprecated/Contract/Configuration.php create mode 100644 deprecated/Contract/Entities/Credential.php create mode 100644 deprecated/Contract/Event/Auth0Event.php create mode 100644 deprecated/Contract/Event/Configuration/Building.php create mode 100644 deprecated/Contract/Event/Configuration/Built.php create mode 100644 deprecated/Contract/Event/Middleware/StatefulRequest.php create mode 100644 deprecated/Contract/Event/Middleware/StatelessRequest.php create mode 100644 deprecated/Contract/Event/Stateful/AuthenticationFailed.php create mode 100644 deprecated/Contract/Event/Stateful/AuthenticationSucceeded.php create mode 100644 deprecated/Contract/Event/Stateful/LoginAttempting.php create mode 100644 deprecated/Contract/Event/Stateful/TokenExpired.php create mode 100644 deprecated/Contract/Event/Stateful/TokenRefreshFailed.php create mode 100644 deprecated/Contract/Event/Stateful/TokenRefreshSucceeded.php create mode 100644 deprecated/Contract/Event/Stateless/TokenVerificationAttempting.php create mode 100644 deprecated/Contract/Event/Stateless/TokenVerificationFailed.php create mode 100644 deprecated/Contract/Event/Stateless/TokenVerificationSucceeded.php create mode 100644 deprecated/Contract/Exception/AuthenticationException.php create mode 100644 deprecated/Contract/Exception/GuardException.php create mode 100644 deprecated/Contract/Exception/SessionException.php create mode 100644 deprecated/Contract/Exception/Stateful/CallbackException.php create mode 100644 deprecated/Contract/Http/Controller/Stateful/Callback.php create mode 100644 deprecated/Contract/Http/Controller/Stateful/Login.php create mode 100644 deprecated/Contract/Http/Controller/Stateful/Logout.php create mode 100644 deprecated/Contract/Http/Middleware/Stateful/Authenticate.php create mode 100644 deprecated/Contract/Http/Middleware/Stateful/AuthenticateOptional.php create mode 100644 deprecated/Contract/Http/Middleware/Stateless/Authorize.php create mode 100644 deprecated/Contract/Http/Middleware/Stateless/AuthorizeOptional.php create mode 100644 deprecated/Contract/Model/Stateful/User.php create mode 100644 deprecated/Contract/Model/Stateless/User.php create mode 100644 deprecated/Contract/Model/User.php create mode 100644 deprecated/Contract/ServiceProvider.php create mode 100644 deprecated/DEPRECATED.md create mode 100644 deprecated/Event/Configuration/Building.php create mode 100644 deprecated/Event/Configuration/Built.php create mode 100644 deprecated/Event/Middleware/StatefulRequest.php create mode 100644 deprecated/Event/Middleware/StatelessRequest.php create mode 100644 deprecated/Event/Stateful/AuthenticationFailed.php create mode 100644 deprecated/Event/Stateful/AuthenticationSucceeded.php create mode 100644 deprecated/Event/Stateful/LoginAttempting.php create mode 100644 deprecated/Event/Stateful/TokenExpired.php create mode 100644 deprecated/Event/Stateful/TokenRefreshFailed.php create mode 100644 deprecated/Event/Stateful/TokenRefreshSucceeded.php create mode 100644 deprecated/Event/Stateless/TokenVerificationAttempting.php create mode 100644 deprecated/Event/Stateless/TokenVerificationFailed.php create mode 100644 deprecated/Event/Stateless/TokenVerificationSucceeded.php create mode 100644 deprecated/Exception/AuthenticationException.php create mode 100644 deprecated/Exception/GuardException.php create mode 100644 deprecated/Exception/SessionException.php create mode 100644 deprecated/Exception/Stateful/CallbackException.php create mode 100644 deprecated/Http/Controller/Stateful/Callback.php create mode 100644 deprecated/Http/Controller/Stateful/Login.php create mode 100644 deprecated/Http/Controller/Stateful/Logout.php create mode 100644 deprecated/Http/Middleware/Guard.php create mode 100644 deprecated/Http/Middleware/Stateful/Authenticate.php create mode 100644 deprecated/Http/Middleware/Stateful/AuthenticateOptional.php create mode 100644 deprecated/Http/Middleware/Stateless/Authorize.php create mode 100644 deprecated/Http/Middleware/Stateless/AuthorizeOptional.php create mode 100644 deprecated/Model/Imposter.php create mode 100644 deprecated/Model/Stateful/User.php create mode 100644 deprecated/Model/Stateless/User.php create mode 100644 deprecated/Model/User.php create mode 100644 deprecated/Store/LaravelSession.php create mode 100644 docs/Configuration.md create mode 100644 docs/Installation.md rename docs/{Management API.md => Management.md} (99%) rename docs/{User Models and Repositories.md => Users.md} (59%) delete mode 100644 infection.json5.dist create mode 100644 src/Bridges/BridgeAbstract.php create mode 100644 src/Bridges/BridgeContract.php create mode 100644 src/Bridges/CacheBridge.php rename src/{Cache/LaravelCachePool.php => Bridges/CacheBridgeAbstract.php} (58%) create mode 100644 src/Bridges/CacheBridgeContract.php create mode 100644 src/Bridges/CacheItemBridge.php create mode 100644 src/Bridges/CacheItemBridgeAbstract.php create mode 100644 src/Bridges/CacheItemBridgeContract.php create mode 100644 src/Bridges/SessionBridge.php rename src/{Store/LaravelSession.php => Bridges/SessionBridgeAbstract.php} (78%) create mode 100644 src/Bridges/SessionBridgeContract.php delete mode 100644 src/Cache/LaravelCacheItem.php create mode 100644 src/ConfigurationContract.php delete mode 100644 src/Contract/Auth/User/Provider.php delete mode 100644 src/Contract/Configuration.php delete mode 100644 src/Contract/Event/Configuration/Building.php delete mode 100644 src/Contract/Event/Middleware/StatefulRequest.php delete mode 100644 src/Contract/Event/Middleware/StatelessRequest.php delete mode 100644 src/Contract/Event/Stateful/TokenExpired.php delete mode 100644 src/Contract/Event/Stateful/TokenRefreshFailed.php delete mode 100644 src/Contract/Event/Stateful/TokenRefreshSucceeded.php delete mode 100644 src/Contract/Exception/AuthenticationException.php delete mode 100644 src/Contract/Exception/GuardException.php delete mode 100644 src/Contract/Exception/SessionException.php delete mode 100644 src/Contract/Exception/Stateful/CallbackException.php delete mode 100644 src/Contract/Model/Stateful/User.php delete mode 100644 src/Contract/Model/Stateless/User.php delete mode 100644 src/Contract/ServiceProvider.php create mode 100644 src/Controllers/CallbackController.php rename src/{Http/Controller/Stateful/Callback.php => Controllers/CallbackControllerAbstract.php} (62%) rename src/{Contract/Http/Controller/Stateful/Callback.php => Controllers/CallbackControllerContract.php} (77%) create mode 100644 src/Controllers/ControllerAbstract.php create mode 100644 src/Controllers/ControllerContract.php create mode 100644 src/Controllers/LoginController.php create mode 100644 src/Controllers/LoginControllerAbstract.php rename src/{Contract/Http/Controller/Stateful/Login.php => Controllers/LoginControllerContract.php} (80%) create mode 100644 src/Controllers/LogoutController.php create mode 100644 src/Controllers/LogoutControllerAbstract.php rename src/{Contract/Http/Controller/Stateful/Logout.php => Controllers/LogoutControllerContract.php} (78%) delete mode 100644 src/Entities/Credential.php create mode 100644 src/Entities/CredentialEntity.php create mode 100644 src/Entities/CredentialEntityAbstract.php rename src/{Contract/Entities/Credential.php => Entities/CredentialEntityContract.php} (68%) create mode 100644 src/Entities/EntityAbstract.php create mode 100644 src/Entities/EntityContract.php create mode 100644 src/Entities/InstanceEntity.php create mode 100644 src/Entities/InstanceEntityAbstract.php rename src/{Contract/Auth0.php => Entities/InstanceEntityContract.php} (53%) create mode 100644 src/Entities/InstanceEntityTrait.php delete mode 100644 src/Event/Configuration/Building.php delete mode 100644 src/Event/Configuration/Built.php delete mode 100644 src/Event/Middleware/StatefulRequest.php delete mode 100644 src/Event/Middleware/StatelessRequest.php delete mode 100644 src/Event/Stateful/AuthenticationFailed.php delete mode 100644 src/Event/Stateful/AuthenticationSucceeded.php delete mode 100644 src/Event/Stateful/LoginAttempting.php delete mode 100644 src/Event/Stateful/TokenExpired.php delete mode 100644 src/Event/Stateful/TokenRefreshFailed.php delete mode 100644 src/Event/Stateful/TokenRefreshSucceeded.php delete mode 100644 src/Event/Stateless/TokenVerificationAttempting.php delete mode 100644 src/Event/Stateless/TokenVerificationFailed.php delete mode 100644 src/Event/Stateless/TokenVerificationSucceeded.php create mode 100644 src/Events/Auth0EventContract.php create mode 100644 src/Events/AuthenticationFailed.php create mode 100644 src/Events/AuthenticationFailedAbstract.php rename src/{Contract/Event/Stateful/AuthenticationFailed.php => Events/AuthenticationFailedContract.php} (80%) create mode 100644 src/Events/AuthenticationSucceeded.php create mode 100644 src/Events/AuthenticationSucceededAbstract.php rename src/{Contract/Event/Stateful/AuthenticationSucceeded.php => Events/AuthenticationSucceededContract.php} (77%) create mode 100644 src/Events/Configuration/BuildingConfigurationEvent.php create mode 100644 src/Events/Configuration/BuildingConfigurationEventAbstract.php create mode 100644 src/Events/Configuration/BuildingConfigurationEventContract.php create mode 100644 src/Events/Configuration/BuiltConfigurationEvent.php create mode 100644 src/Events/Configuration/BuiltConfigurationEventAbstract.php rename src/{Contract/Event/Configuration/Built.php => Events/Configuration/BuiltConfigurationEventContract.php} (79%) rename src/{Event/Auth0Event.php => Events/EventAbstract.php} (65%) rename src/{Contract/Event/Auth0Event.php => Events/EventContract.php} (68%) create mode 100644 src/Events/LoginAttempting.php create mode 100644 src/Events/LoginAttemptingAbstract.php rename src/{Contract/Event/Stateful/LoginAttempting.php => Events/LoginAttemptingContract.php} (70%) create mode 100644 src/Events/Middleware/StatefulMiddlewareRequest.php create mode 100644 src/Events/Middleware/StatefulMiddlewareRequestAbstract.php create mode 100644 src/Events/Middleware/StatefulMiddlewareRequestContract.php create mode 100644 src/Events/Middleware/StatelessMiddlewareRequest.php create mode 100644 src/Events/Middleware/StatelessMiddlewareRequestAbstract.php create mode 100644 src/Events/Middleware/StatelessMiddlewareRequestContract.php create mode 100644 src/Events/TokenExpired.php create mode 100644 src/Events/TokenExpiredAbstract.php create mode 100644 src/Events/TokenExpiredContract.php create mode 100644 src/Events/TokenRefreshFailed.php create mode 100644 src/Events/TokenRefreshFailedAbstract.php create mode 100644 src/Events/TokenRefreshFailedContract.php create mode 100644 src/Events/TokenRefreshSucceeded.php create mode 100644 src/Events/TokenRefreshSucceededAbstract.php create mode 100644 src/Events/TokenRefreshSucceededContract.php create mode 100644 src/Events/TokenVerificationAttempting.php create mode 100644 src/Events/TokenVerificationAttemptingAbstract.php rename src/{Contract/Event/Stateless/TokenVerificationAttempting.php => Events/TokenVerificationAttemptingContract.php} (71%) create mode 100644 src/Events/TokenVerificationFailed.php create mode 100644 src/Events/TokenVerificationFailedAbstract.php rename src/{Contract/Event/Stateless/TokenVerificationFailed.php => Events/TokenVerificationFailedContract.php} (84%) create mode 100644 src/Events/TokenVerificationSucceeded.php create mode 100644 src/Events/TokenVerificationSucceededAbstract.php rename src/{Contract/Event/Stateless/TokenVerificationSucceeded.php => Events/TokenVerificationSucceededContract.php} (82%) delete mode 100644 src/Exception/AuthenticationException.php delete mode 100644 src/Exception/GuardException.php delete mode 100644 src/Exception/SessionException.php delete mode 100644 src/Exception/Stateful/CallbackException.php create mode 100644 src/Exceptions/AuthenticationException.php create mode 100644 src/Exceptions/AuthenticationExceptionAbstract.php create mode 100644 src/Exceptions/AuthenticationExceptionContract.php create mode 100644 src/Exceptions/ControllerException.php create mode 100644 src/Exceptions/ControllerExceptionAbstract.php create mode 100644 src/Exceptions/ControllerExceptionContract.php create mode 100644 src/Exceptions/Controllers/CallbackControllerException.php create mode 100644 src/Exceptions/Controllers/CallbackControllerExceptionAbstract.php create mode 100644 src/Exceptions/Controllers/CallbackControllerExceptionContract.php create mode 100644 src/Exceptions/ExceptionAbstract.php create mode 100644 src/Exceptions/ExceptionContract.php create mode 100644 src/Exceptions/GuardException.php create mode 100644 src/Exceptions/GuardExceptionAbstract.php create mode 100644 src/Exceptions/GuardExceptionContract.php create mode 100644 src/Exceptions/SessionException.php create mode 100644 src/Exceptions/SessionExceptionAbstract.php create mode 100644 src/Exceptions/SessionExceptionContract.php create mode 100644 src/Guards/AuthenticationGuard.php create mode 100644 src/Guards/AuthenticationGuardContract.php create mode 100644 src/Guards/AuthorizationGuard.php create mode 100644 src/Guards/AuthorizationGuardContract.php create mode 100644 src/Guards/GuardAbstract.php rename src/{Contract/Auth/Guard.php => Guards/GuardContract.php} (50%) delete mode 100644 src/Http/Controller/ControllerAbstract.php delete mode 100644 src/Http/Controller/Stateful/Login.php delete mode 100644 src/Http/Controller/Stateful/Logout.php delete mode 100644 src/Http/Middleware/MiddlewareAbstract.php delete mode 100644 src/Http/Middleware/Stateful/Authenticate.php delete mode 100644 src/Http/Middleware/Stateful/AuthenticateOptional.php delete mode 100644 src/Http/Middleware/Stateless/Authorize.php delete mode 100644 src/Http/Middleware/Stateless/AuthorizeOptional.php create mode 100644 src/Middleware/AuthenticateMiddleware.php create mode 100644 src/Middleware/AuthenticateMiddlewareAbstract.php rename src/{Contract/Http/Middleware/Stateful/Authenticate.php => Middleware/AuthenticateMiddlewareContract.php} (58%) create mode 100644 src/Middleware/AuthenticateOptionalMiddleware.php create mode 100644 src/Middleware/AuthenticateOptionalMiddlewareAbstract.php rename src/{Contract/Http/Middleware/Stateless/Authorize.php => Middleware/AuthenticateOptionalMiddlewareContract.php} (61%) create mode 100644 src/Middleware/AuthenticatorMiddleware.php create mode 100644 src/Middleware/AuthenticatorMiddlewareContract.php create mode 100644 src/Middleware/AuthorizeMiddleware.php create mode 100644 src/Middleware/AuthorizeMiddlewareAbstract.php rename src/{Contract/Http/Middleware/Stateless/AuthorizeOptional.php => Middleware/AuthorizeMiddlewareContract.php} (58%) create mode 100644 src/Middleware/AuthorizeOptionalMiddleware.php create mode 100644 src/Middleware/AuthorizeOptionalMiddlewareAbstract.php rename src/{Contract/Http/Middleware/Stateful/AuthenticateOptional.php => Middleware/AuthorizeOptionalMiddlewareContract.php} (62%) create mode 100644 src/Middleware/AuthorizerMiddleware.php create mode 100644 src/Middleware/AuthorizerMiddlewareContract.php create mode 100644 src/Middleware/GuardMiddleware.php rename src/{Http/Middleware/Guard.php => Middleware/GuardMiddlewareAbstract.php} (57%) create mode 100644 src/Middleware/GuardMiddlewareContract.php create mode 100644 src/Middleware/MiddlewareAbstract.php create mode 100644 src/Middleware/MiddlewareContract.php delete mode 100644 src/Model/Imposter.php delete mode 100644 src/Model/Stateful/User.php delete mode 100644 src/Model/Stateless/User.php create mode 100644 src/Service.php create mode 100644 src/ServiceAbstract.php create mode 100644 src/ServiceContract.php create mode 100644 src/ServiceProviderAbstract.php create mode 100644 src/ServiceProviderContract.php create mode 100644 src/UserProvider.php rename src/{Auth/User/Provider.php => UserProviderAbstract.php} (64%) create mode 100644 src/UserProviderContract.php rename src/{Auth/User/Repository.php => UserRepository.php} (54%) create mode 100644 src/UserRepositoryAbstract.php rename src/{Contract/Auth/User/Repository.php => UserRepositoryContract.php} (88%) create mode 100644 src/Users/ImposterUser.php create mode 100644 src/Users/ImposterUserContract.php create mode 100644 src/Users/StatefulUser.php create mode 100644 src/Users/StatefulUserContract.php create mode 100644 src/Users/StatelessUser.php create mode 100644 src/Users/StatelessUserContract.php rename src/{Model/User.php => Users/UserAbstract.php} (57%) rename src/{Contract/Model/User.php => Users/UserContract.php} (72%) create mode 100644 src/Users/UserTrait.php delete mode 100644 tests/Unit/Auth/User/ProviderTest.php rename tests/Unit/{Cache/LaravelCachePoolTest.php => Bridges/CacheBridgeTest.php} (77%) rename tests/Unit/{Cache/LaravelCacheItemTest.php => Bridges/CacheItemBridgeTest.php} (79%) rename tests/Unit/{Store/LaravelSessionTest.php => Bridges/SessionBridgeTest.php} (90%) rename tests/Unit/{Http/Controller/Stateful/CallbackTest.php => Controllers/CallbackControllerTest.php} (61%) rename tests/Unit/{Http/Controller/Stateful/LoginTest.php => Controllers/LoginControllerTest.php} (50%) create mode 100644 tests/Unit/Controllers/LogoutControllerTest.php rename tests/Unit/Entities/{CredentialTest.php => CredentialEntityTest.php} (64%) create mode 100644 tests/Unit/Entities/InstanceEntityTest.php create mode 100644 tests/Unit/Guards/AuthenticationGuardTest.php create mode 100644 tests/Unit/Guards/AuthorizationGuardTest.php delete mode 100644 tests/Unit/Http/Controller/Stateful/LogoutTest.php rename tests/Unit/{Http/Middleware/Stateful/AuthenticateTest.php => Middleware/AuthenticateMiddlewareTest.php} (76%) rename tests/Unit/{Http/Middleware/Stateful/AuthenticateOptionalTest.php => Middleware/AuthenticateOptionalMiddlewareTest.php} (77%) create mode 100644 tests/Unit/Middleware/AuthenticatorMiddlewareTest.php rename tests/Unit/{Http/Middleware/Stateless/AuthorizeTest.php => Middleware/AuthorizeMiddlewareTest.php} (75%) rename tests/Unit/{Http/Middleware/Stateless/AuthorizeOptionalTest.php => Middleware/AuthorizeOptionalMiddlewareTest.php} (75%) create mode 100644 tests/Unit/Middleware/AuthorizerMiddlewareTest.php rename tests/Unit/{Http/Middleware/GuardTest.php => Middleware/GuardMiddlewareTest.php} (83%) rename tests/Unit/{Auth0Test.php => ServiceTest.php} (62%) create mode 100644 tests/Unit/UserProviderTest.php rename tests/Unit/{Auth/User/RepositoryTest.php => UserRepositoryTest.php} (75%) rename tests/Unit/{Model => Users}/UserTest.php (79%) delete mode 100644 tests/constants.php diff --git a/.gitattributes b/.gitattributes index a4fe7cca..e29b8969 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,8 +2,10 @@ .gitattributes export-ignore .github/ export-ignore .gitignore export-ignore +.php-cs-fixer.dist.php export-ignore .semgrepignore export-ignore .shiprc export-ignore +CHANGELOG.ARCHIVE.md export-ignore CHANGELOG.md export-ignore docs/ export-ignore EXAMPLES.md export-ignore @@ -16,6 +18,3 @@ rector.php export-ignore tests/ export-ignore UPGRADE.md export-ignore vendor/ export-ignore -CHANGELOG.ARCHIVE.md export-ignore -infection.json5.dist export-ignore -.php-cs-fixer.dist.php export-ignore diff --git a/.github/workflows/php_pest.yml b/.github/workflows/php_pest.yml index 9436907b..f7917679 100644 --- a/.github/workflows/php_pest.yml +++ b/.github/workflows/php_pest.yml @@ -24,7 +24,7 @@ jobs: - run: composer install --no-progress - - run: vendor/bin/pest --order-by random --parallel + - run: vendor/bin/pest --order-by random --fail-on-risky --stop-on-defect --coverage --parallel --min=95 - uses: codecov/codecov-action@v3 with: diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 2dc96809..b37fdaf6 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -1,5 +1,7 @@ setRiskyAllowed(true) ->setRules([ @@ -8,14 +10,15 @@ 'array_syntax' => ['syntax' => 'short'], 'assign_null_coalescing_to_coalesce_equal' => true, 'backtick_to_shell_exec' => true, - 'binary_operator_spaces' => ['operators' => ['=' => 'align', 'xor' => null, '+=' => 'align_single_space', '===' => 'align_single_space_minimal', '|' => 'single_space', '=>' => 'align_single_space_minimal_by_scope']], + 'binary_operator_spaces' => true, 'blank_line_after_namespace' => true, 'blank_line_after_opening_tag' => true, 'blank_line_before_statement' => true, + 'blank_line_between_import_groups' => true, 'braces' => true, 'cast_spaces' => true, - 'class_attributes_separation' => ['elements' => ['const' => 'only_if_meta', 'method' => 'one', 'property' => 'only_if_meta', 'trait_import' => 'one', 'case' => 'one']], - 'class_definition' => true, + 'class_attributes_separation' => ['elements' => ['const' => 'one', 'method' => 'one', 'property' => 'one', 'trait_import' => 'one', 'case' => 'one']], + 'class_definition' => ['multi_line_extends_each_single_line' => true, 'single_line' => true, 'single_item_single_line' => true, 'space_before_parenthesis' => false, 'inline_constructor_arguments' => false], 'class_reference_name_casing' => true, 'clean_namespace' => true, 'combine_consecutive_issets' => true, @@ -25,7 +28,9 @@ 'compact_nullable_typehint' => true, 'concat_space' => ['spacing' => 'one'], 'constant_case' => ['case' => 'lower'], + 'curly_braces_position' => ['control_structures_opening_brace' => 'same_line', 'functions_opening_brace' => 'next_line_unless_newline_at_signature_end', 'anonymous_functions_opening_brace' => 'same_line', 'classes_opening_brace' => 'next_line_unless_newline_at_signature_end', 'anonymous_classes_opening_brace' => 'same_line', 'allow_single_line_empty_anonymous_classes' => true, 'allow_single_line_anonymous_functions' => true], 'date_time_create_from_format_call' => true, + 'date_time_immutable' => true, 'declare_equal_normalize' => ['space' => 'none'], 'declare_parentheses' => true, 'declare_strict_types' => true, @@ -78,7 +83,7 @@ 'magic_constant_casing' => true, 'magic_method_casing' => true, 'mb_str_functions' => true, - 'method_argument_space' => true, + 'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline', 'after_heredoc' => true], 'method_chaining_indentation' => true, 'modernize_strpos' => true, 'modernize_types_casting' => true, @@ -139,7 +144,7 @@ 'object_operator_without_whitespace' => true, 'octal_notation' => true, 'operator_linebreak' => true, - 'ordered_class_elements' => ['sort_algorithm' => 'alpha', 'order' => ['use_trait', 'case', 'constant', 'constant_private', 'constant_protected', 'constant_public', 'property_private', 'property_private_readonly', 'property_private_static', 'property_protected', 'property_protected_readonly', 'property_protected_static', 'property_public', 'property_public_readonly', 'property_public_static', 'property_static', 'protected', 'construct', 'destruct', 'magic', 'method', 'public', 'method_abstract', 'method_private', 'method_private_abstract', 'method_private_abstract_static', 'method_private_static', 'method_protected', 'method_protected_abstract', 'method_protected_abstract_static', 'method_protected_static', 'method_public', 'method_public_abstract', 'method_public_abstract_static', 'method_public_static', 'method_static', 'phpunit', 'private', 'property']], + 'ordered_class_elements' => ['sort_algorithm' => 'alpha', 'order' => ['use_trait', 'case', 'constant', 'constant_private', 'constant_protected', 'constant_public', 'property_private', 'property_private_readonly', 'property_private_static', 'property_protected', 'property_protected_readonly', 'property_protected_static', 'property_public', 'property_public_readonly', 'property_public_static', 'property_static', 'protected', 'construct', 'destruct', 'magic', 'method', 'public', 'method_public', 'method_abstract', 'method_public_abstract', 'method_public_abstract_static', 'method_public_static', 'method_static', 'method_private', 'method_private_abstract', 'method_private_abstract_static', 'method_private_static', 'method_protected', 'method_protected_abstract', 'method_protected_abstract_static', 'method_protected_static', 'phpunit', 'private', 'property']], 'ordered_imports' => ['sort_algorithm' => 'alpha', 'imports_order' => ['const', 'class', 'function']], 'ordered_interfaces' => true, 'ordered_traits' => true, @@ -192,6 +197,7 @@ 'single_line_throw' => true, 'single_quote' => true, 'single_space_after_construct' => true, + 'single_space_around_construct' => true, 'single_trait_insert_per_statement' => true, 'space_after_semicolon' => true, 'standardize_increment' => true, @@ -208,9 +214,9 @@ 'ternary_operator_spaces' => true, 'ternary_to_elvis_operator' => true, 'ternary_to_null_coalescing' => true, - 'trailing_comma_in_multiline' => ['after_heredoc' => true, 'elements' => ['arguments', 'parameters']], + 'trailing_comma_in_multiline' => ['after_heredoc' => true, 'elements' => ['arguments', 'arrays', 'match', 'parameters']], 'trim_array_spaces' => true, - 'types_spaces' => ['space' => 'single'], + 'types_spaces' => ['space' => 'single', 'space_multiple_catch' => 'single'], 'unary_operator_spaces' => true, 'use_arrow_functions' => true, 'visibility_required' => true, @@ -221,6 +227,5 @@ ->setFinder( PhpCsFixer\Finder::create() ->exclude('vendor') - ->in([__DIR__.'/src/']) - ) -; + ->in([__DIR__ . '/src/', __DIR__ . '/deprecated/']), + ); diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist new file mode 100644 index 00000000..993f321e --- /dev/null +++ b/.phpcs.xml.dist @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/CHANGELOG.md b/CHANGELOG.md index 6beee8d9..e4a10ca7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,38 @@ # Changelog +## [Unreleased] + +### Added + +- This release adds support for authenticating using **[Pushed Authorization Requests](https://www.rfc-editor.org/rfc/rfc6749)**. + +- This release introduces **two new Authentication Guards** which provide a streamlined integration experience for developers that need to simultaneously support both session-based authentication and token-based endpoint authorization in their Laravel applications. + + | Guard | Class | Description | + | --------------------- | ----------------------------------------------- | ----------------------------- | + | `auth0.authenticator` | `Auth0\Laravel\Auth\Guards\AuthenticationGuard` | Session-based authentication. | + | `auth0.authorizer` | `Auth0\Laravel\Auth\Guards\AuthorizationGuard` | Token-based authorization. | + +- These guards are compatible with Laravel's Authentication API and support the native `auth` middleware. + +- These guards are compatible with Laravel's Authorization API and support the native `can` middleware, and the `Guard` facade, and work with the Policies API. + +- 3 new pre-built Guards are available: `scope` and `permission`, as well as a dynamic `*:*`. This enables you to verify whether the user's access token has a particular scope or (if RBAC is enabled on the Auth0 API) a particular permission. For example `Gate::check('scope', 'email')` or `Route::get(/*...*/)->can('read:messages')`. + +- The SDK now automatically registers these guards to Laravel's standard `web` and `api` middleware groups, respectively. Manual Guard setup in `config/auth.php` is no longer necessary. + +- The SDK now automatically registers the Authentication routes. Manual route setup in `routes/web.php` is no longer necessary. + +- 2 new routing Middleware have been added: `Auth0\Laravel\Http\Middleware\Authenticator` and `Auth0\Laravel\Http\Middleware\Authorizer`. These are automatically registered with your Laravel application, and ensure the Auth0 Guards are used for authentication and authorization, respectively. This replaces the need for the `guard` middleware or otherwise manual Guard assignment in your routes. + +### Improved + +- We've introduced **a new configuration syntax**. This new syntax is more flexible and allows for more complex configuration scenarios. It also allows more efficient configuration of multiple guards. Developers using the previous syntax will have their existing configurations applied to all guards uniformly, to avoid a breaking change. + +- The SDK can now **configure itself using a `.auth0.json` file in the project root directory**. This file can be generated [using the Auth0 CLI](./docs/JSON%20Configuration.md), and provides a significantly simpler configuration experience for developers. + +- The previous `auth0.guard` Guard (`Auth0\Laravel\Auth\Guard`) has been **refactored** as a lightweight wrapper around the new `SessionGuard` and `TokenGuard` guards. + ## [7.7.0](https://github.com/auth0/laravel-auth0/tree/7.7.0) (2023-04-26) ### Added diff --git a/README.md b/README.md index 40af202e..72e4114c 100644 --- a/README.md +++ b/README.md @@ -12,303 +12,217 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. ## Documentation - Quickstarts - - [Application using Sessions (Stateful)](https://auth0.com/docs/quickstart/laravel/php) — Traditional web application that uses sessions and supports logging in, logging out, and querying user profiles. [The complete source code is also available.](https://github.com/auth0-samples/auth0-laravel-php-web-app) - - [API using Access Tokens (Stateless)](https://auth0.com/docs/quickstart/backend/laravel) — Backend service that authorizes endpoints using access tokens provided by a frontend client and returns JSON responses. [The complete source code is also available.](https://github.com/auth0-samples/auth0-laravel-api-samples) + - [Authentication using Sessions](https://auth0.com/docs/quickstart/webapp/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) — An application that uses sessions and supports logging in, logging out, and querying user profiles. + - [Authorization using Tokens](https://auth0.com/docs/quickstart/backend/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) — A backend API service that authorizes requests using tokens from a frontend application. - Documentation - - [Examples](./EXAMPLES.md) — Cookbook offering example solutions for common scenarios and questions. - [Events](./docs/Events.md) — Hooking into [events](https://laravel.com/docs/10.x/events) raised by the SDK to customize behavior. - - [Management API](./docs/Management%20API.md) — Making API calls to [Auth0 Management API endpoints](https://auth0.com/docs/api/management/v2). - - [User Models and Repositories](./docs/User%20Models%20and%20Repositories.md) — Extending the SDK to support database storage, [Eloquent](https://laravel.com/docs/10.x/eloquent), and other scenarios. + - [Management API](./docs/Management.md) — Making API calls to [Auth0 Management API endpoints](https://auth0.com/docs/api/management/v2). + - [User Models and Repositories](./docs/Users.md) — Extending the SDK to support database storage, [Eloquent](https://laravel.com/docs/10.x/eloquent), and other scenarios. + - [Examples](./EXAMPLES.md) — Solutions for other common scenarios and questions. - [Documentation Hub](https://www.auth0.com/docs) — Learn more about integrating Auth0. ## Getting Started ### Requirements -- Laravel 10 (PHP 8.1+) or Laravel 9 (PHP 8.0+) -- [Composer](https://getcomposer.org/) -- [Auth0 account](https://auth0.com/signup) +You will need to use a [supported version](#support-policy) of PHP and Laravel: -Our examples use the [Auth0 CLI](https://github.com/auth0/auth0-cli) to help get you kickstarted quickly. You should have the CLI [installed](https://github.com/auth0/auth0-cli#installation) and [authenticated](https://github.com/auth0/auth0-cli#authenticating-to-your-tenant). +| Laravel | PHP | +| ------- | ---- | +| 10 | 8.1+ | +| 9 | 8.0+ | -> Please review our [support policy](#support-policy) for details on our PHP and Laravel version support. +You'll also need an [Auth0 account](https://auth0.com/signup), as well as [Composer](https://getcomposer.org/) and the [Auth0 CLI](https://github.com/auth0/auth0-cli). -### Installation +### SDK Installation -Open a shell to the root of your Laravel application's root directory, and import the SDK using [Composer](https://getcomposer.org/): +Run the following command within your project directory to install the [Auth0 Laravel SDK](https://github.com/auth0/laravel-auth0): -```bash -composer require auth0/login:^7.0 --with-all-dependencies +```shell +composer require auth0/login:^7.8 --update-with-all-dependencies ``` -Next, generate the `config/auth0.php` configuration file for your application: +Then generate an SDK configuration file for your application: -```bash -php artisan vendor:publish --tag=auth0-config +```shell +php artisan vendor:publish --tag auth0 ``` -Now is also a good time to clear your application caches: - -```bash -php artisan optimize:clear -``` +### SDK Configuration -### Determine Your Application Type +> **Note** +> If you prefer to use environment variables to configure the SDK, please see [docs/Installation](./docs/Installation.md) for guidance. -Before we begin configuring your application, it's important to understand the difference between "stateful" and "stateless" applications, and which one is appropriate for your use case. +Run the following command from your project directory to download the [Auth0 CLI](https://github.com/auth0/auth0-cli): -- **Stateful** applications use a session to store user information (their state). - - These provide a login/logout experience. - - These are **authenticating** users. - - These often need to know the **identity** of the requestor. - - These are often considered traditional web applications. -- **Stateless** applications authorize requests to routes. - - These use Access Tokens to firewall requests. - - These are **authorizing** requests. - - These are agnostic to the identity of the requestor. - - These are typically considered backend services. - - These are often used to provide data to single-page applications. +```shell +curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . +``` -As we continue, we'll use these terms to help guide you to the correct configuration paths for your application type. +Then authenticate the CLI with your Auth0 account: -> **Note** -> The SDK does not support simultaneously using stateless and stateful guards within the same application at this time. If you need to support both, you will need to create two separate application instances. Support for this is planned for a future release. - -### Creating an Auth0 Application +```shell +./auth0 login +``` -Create a new Auth0 application using [the Auth0 CLI](https://github.com/auth0/): +Next, create a new application with Auth0: -```bash -auth0 apps create \ +```shell +./auth0 apps create \ --name "My Laravel Application" \ --type "regular" \ --auth-method "post" \ --callbacks "http://localhost:8000/callback" \ --logout-urls "http://localhost:8000/" \ --reveal-secrets \ - --no-input + --no-input \ + --json > .auth0.app.json ``` -You will receive a response with details about your new application. - -Please make a note of your tenant's **domain** (e.g. `tenant.region.auth0.com`), **client ID**, and **client secret**. These will be required in the configuration step below. - -### Creating an Auth0 API - -You can create a new Auth0 API using [the Auth0 CLI](https://github.com/auth0/). - -In the following command, you can choose any `--name` and `--identifier` values you like. However, the `--identifier` value must be a valid URL, although it does not need to be publicly accessible. Note that the identifier value cannot be changed later. +You should also create a new API: -> **Note** -> The identifier value will be used as the audience claim in your Access Tokens, so it is important to choose a value that will not conflict with other APIs you may be using. - -```bash -auth0 apis create \ - --name "My Laravel Application's API" \ +```shell +./auth0 apis create \ + --name "My Laravel Application API" \ --identifier "https://github.com/auth0/laravel-auth0" \ --offline-access \ - --no-input + --no-input \ + --json > .auth0.api.json ``` -You will receive a response with details about your new API. - -Please make a note of your new API's **identifier**. This will be required in the configuration step and will be referred to as the `audience`. +This produces two files in your project directory that configure the SDK. -### Configuring the SDK +As these files contain credentials it's important to treat these as sensitive. You should ensure you do not commit these to version control. If you're using Git, you should add them to your `.gitignore` file: -Open the `.env` file within your Laravel application's root directory, append the lines below to it, and fill in the missing values: +```bash +echo ".auth0.*.json" >> .gitignore +``` -```ini -# In previous steps we configured our application callbacks use to port 8000, -# which is consistent for running your app using `php artisan serve`. -APP_URL=http://localhost:8000 +### Authentication -# Use the `domain` you noted earlier during application creation. -AUTH0_DOMAIN={yourDomain} +The SDK automatically registers all the necessary facilities within the `web` middleware group for your users to authenticate with your application. These routes are: -# Use the `client id` you noted earlier during application creation. -AUTH0_CLIENT_ID={yourClientId} +| Route | Purpose | +| ----------- | ---------------------------------- | +| `/login` | Initiates the authentication flow. | +| `/logout` | Logs the user out. | +| `/callback` | Handles the callback from Auth0. | -# Use the `client_secret` you noted earlier during application creation. -AUTH0_CLIENT_SECRET={yourClientSecret} +See [docs/Configuration](./docs/Configuration.md) for guidance on disabling automatic registration, and manually registering these facilities. -# Use the `identifier` you noted earlier during API creation. -AUTH0_AUDIENCE={yourApiIdentifier} +### Access Control -# This should be any sufficiently long, random string. -# You can use `openssl rand -hex 32` to generate an adequate string. -AUTH0_COOKIE_SECRET= -``` +The SDK automatically registers its authentication and authorization guards into the standard `web` and `api` middleware for your Laravel application, respectively. -If you are building a stateless application, you should also configure the `AUTH0_STRATEGY` environment variable: +See [docs/Configuration](./docs/Configuration.md) for guidance on disabling this automatic registration, and manually registering the guards. -```ini -AUTH0_STRATEGY=api -``` +You can use the Auth0 SDK's authentication guard to restrict access to your application's routes. -### Configuring Your Application - -Open your `config/auth.php` file. - -Find the `guards` section, and add a new guard to the `guards` array that uses the `auth0.guard` driver. +To require the requesting party to be authenticated (routes using the `web` middleware defined in `routes/web.php`) or authorized (routes using the `api` middleware defined in `routes/api.php`), you can use Laravel's `auth` middleware: ```php -'guards' => [ - 'someGuardName' => [ - 'driver' => 'auth0.guard', - 'provider' => 'someProviderName', - ], -], +Route::get('/private', function () { + return response('Welcome! You are logged in.'); +})->middleware('auth'); ``` -Find the `providers` section, and add a new provider to the `providers` array that uses `auth0.provider` as the driver. +You can also require the requestor have specific [permissions](https://auth0.com/docs/manage-users/access-control/rbac) by combining this with Laravel's `can` middleware: ```php -'providers' => [ - 'someProviderName' => [ - 'driver' => 'auth0.provider', - 'repository' => \Auth0\Laravel\Auth\User\Repository::class - ], -], +Route::get('/scope', function () { + return response('You have the `read:messages` permissions, and can therefore access this resource.'); +})->middleware('auth')->can('read:messages'); ``` > **Note** -> Please ensure the provider's name (in this case, `someProviderName`) matches the `provider` value in the guard definition. - -### Adding Login - -> **Note** -> This section only applies to stateful application types. - -The SDK provides routing controllers that handle the authentication flow for your application. Add these routes where most appropriate for your configuration. `routes/web.php` is a common location for many Laravel applications. - -```php -group(function () { - Route::get('/login', Login::class)->name('login'); - Route::get('/logout', Logout::class)->name('logout'); - Route::get('/callback', Callback::class)->name('callback'); -}); +> Permissions need RBAC to be enabled on [your Auth0 API's settings](https://manage.auth0.com/#/apis). -// Other routes... -``` - -### Routing Middleware +### User and Token Information -The SDK provides a collection of routing middleware to help you secure your application's routes. Any routes you wish to protect should be wrapped in the appropriate middleware. +When requests are made to your application, the SDK will automatically attempt to authenticate or authorize the requestor, depending on the type of route. Information about the requesting party is expressed through the `user()` method of Laravel's `Auth` Facade, or the `auth()` helper function. -#### Stateful Applications - -**`auth0.authenticate` requires a user to be logged in to access a route.** Other requests will be redirected to the `login` route. - -```php -Route::get('/required', function () { - return view(/* Authenticated */); -})->middleware('auth0.authenticate'); -``` - -**`auth0.authenticate.optional` allows anyone to access a route.** It will check if a user is logged in and will make sure `Auth::user()` is available to the route if so. This is useful when you wish to display different content to logged-in users and guests. +For routes using the `web` middleware defined in `routes/web.php`, the `user()` method will return profile information for the authenticated user. ```php Route::get('/', function () { - if (Auth::check()) { - return view(/* Authenticated */) - } - - return view(/* Guest */) -})->middleware('auth0.authenticate.optional'); -``` - -#### Stateless Services - -**`auth0.authorize` requires a valid access token for a request.** Otherwise, it will return a `401 Unauthorized` response. + if (! auth()->check()) { + return response('You are not logged in.'); + } -```php -Route::get('/api/private', function () { - return response()->json([ - 'message' => 'Hello from a private endpoint! You need to be authorized to see this.', - 'authorized' => Auth::check(), - 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, - ], 200, [], JSON_PRETTY_PRINT); -})->middleware('auth0.authorize'); -``` - -**`auth0.authorize` can further require access tokens to have a specific scope.** If the scope is not present for the token, it will return a `403 Forbidden` response. + $user = auth()->user(); + $name = $user->name ?? 'User'; + $email = $user->email ?? ''; -```php -Route::get('/api/private-scoped', function () { - return response()->json([ - 'message' => 'Hello from a private endpoint! You need to be authorized and have a scope of read:messages to see this.', - 'authorized' => Auth::check(), - 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, - ], 200, [], JSON_PRETTY_PRINT); -})->middleware('auth0.authorize:read:messages'); + return response("Hello {$name}! Your email address is {$email}."); +});; ``` -**`auth0.authorize.optional` allows anyone to access a route.** It will check if a valid access token is present and will make sure `Auth::user()` is available to the route if so. This is useful when you wish to return different responses to authenticated and unauthenticated requests. +For routes using the `api` middleware defined in `routes/api.php`, the `user()` method will return details about the access token. ```php -Route::get('/api/public', function () { +Route::get('/', function () { + if (! auth()->check()) { return response()->json([ - 'message' => 'Hello from a public endpoint! You don\'t need to be authorized to see this.', - 'authorized' => Auth::check(), - 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, - ], 200, [], JSON_PRETTY_PRINT); -})->middleware('auth0.authorize.optional'); + 'message' => 'You did not provide a valid token.', + ]); + } + + return response()->json([ + 'message' => 'Your token is valid; you are authorized.', + 'id' => auth()->id(), + 'token' => auth()?->user()?->getAttributes(), + ]); +}); ``` -
+### Management API -### Guard Assignment +You can update user information using the [Auth0 Management API](https://github.com/auth0/laravel-auth0/blob/main/docs/Management.md). All Management endpoints are accessible through the SDK's `management()` method. -For the SDK to function, requests must be routed through a guard configured with the `auth0.guard` driver. This can be done in several ways. +**Before making Management API calls you must enable your application to communicate with the Management API.** This can be done from the [Auth0 Dashboard's API page](https://manage.auth0.com/#/apis/), choosing `Auth0 Management API`, and selecting the 'Machine to Machine Applications' tab. Authorize your Laravel application, and then click the down arrow to choose the scopes you wish to grant. -#### Default Guard - -You can set the `default` guard in your `config/auth.php` file to the guard you have configured for the SDK. +For the following example, in which we will update a user's metadata and assign a random favorite color, you should grant the `read:users` and `update:users` scopes. A list of API endpoints and the required scopes can be found in [the Management API documentation](https://auth0.com/docs/api/management/v2). ```php - [ - 'guard' => 'someGuardName' - ], +Route::get('/colors', function () { + $endpoint = Auth0::management()->users(); - // ... -]; -``` + $colors = ['red', 'blue', 'green', 'black', 'white', 'yellow', 'purple', 'orange', 'pink', 'brown']; -#### Route Middleware + $endpoint->update( + id: auth()->id(), + body: [ + 'user_metadata' => [ + 'color' => $colors[random_int(0, count($colors) - 1)] + ] + ] + ); -As a convenience, the SDK provides a `guard` middleware that can be used to assign a specific guard to handle a route group. + $metadata = $endpoint->get(auth()->id()); + $metadata = Auth0::json($metadata); -```php -user()->name; -Route::middleware('guard:someGuardName')->group(function () { - Route::get('/example', \App\HtpController\Example::class)->name('example'); - // Other routes... -}); + return response("Hello {$name}! Your favorite color is {$color}."); +})->middleware('auth'); ``` -#### AuthManager `shouldUse()` Method +A quick reference guide of all the SDK's Management API methods is [available here](https://github.com/auth0/laravel-auth0/blob/main/docs/Management.md). -You can also use the `shouldUse()` method on the `AuthManager` to assign a specific guard. +## Gates and Policies -This is the equivalent of setting the `default` guard in your `config/auth.php` file, but can be done at runtime. +The SDK supports [Laravel's Authorization API](https://laravel.com/docs/authorization#main-content) and provides several convenient pre-built [Gates](https://laravel.com/docs/authorization#gates) for common tasks. -```php -shouldUse('someGuardName'); +| Gate | Facade Usage | Middleware Usage | Purpose | +| ------------ | --------------------------------------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `scope` | `Gate::check('scope', 'email');` | `Route::get(/*...*/)->can('scope', 'email');` | Determine if the user's access token has a specified [scope](https://auth0.com/docs/get-started/apis/scopes). | +| `permission` | `Gate::check('permission', 'read:messages');` | `Route::get(/*...*/)->can('permission', 'read:messages');` | Determine if the user's access token has a specified [permission](https://auth0.com/docs/manage-users/access-control/rbac). This requires RBAC be enabled on [your Auth0 API's settings](https://manage.auth0.com/#/apis). | +| `*:*` | `Gate::check('read:messages');` | `Route::get(/*...*/)->can('read:messages');` | A convenience alias for `permission` (described above), you can supply any permission string in the colon-delimited `ability:context` syntax. | -Route::get('/example', \App\HttpController\Example::class)->name('example'); -// Other routes.. -``` +Using these gates, you can easily authorize users or access tokens to perform actions in your application. Your application can use Laravel's [Policies API](https://laravel.com/docs/10.x/authorization#creating-policies) in combination with these gates to further simplify authorization. ## Support Policy diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..bfdf8bee --- /dev/null +++ b/codecov.yml @@ -0,0 +1,12 @@ +codecov: + range: "95...100" + status: + project: + patch: + changes: +ignore: + - "src/Contract" + - "src/Event" + - "src/Exception" + - "src/Http" + - "src/Model" diff --git a/composer.json b/composer.json index 9772532c..f3a3d71b 100644 --- a/composer.json +++ b/composer.json @@ -38,45 +38,50 @@ "php": "^8.0", "ext-json": "*", "ext-mbstring": "*", - "auth0/auth0-php": "^8.5", + "auth0/auth0-php": "^8.6", "illuminate/contracts": "^9 || ^10", "illuminate/http": "^9 || ^10", "illuminate/support": "^9 || ^10", + "psr-discovery/all": "^1.0", "psr/cache": "^2 || ^3" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.16", - "mockery/mockery": "^1.5.1", - "nunomaduro/larastan": "^2.6.0", - "orchestra/testbench": "^7.19 || ^8.5.1", - "pestphp/pest": "^2.5.3", - "pestphp/pest-plugin-laravel": "^2.0", - "phpstan/phpstan": "^1.10.14", - "phpstan/phpstan-strict-rules": "^1.5.1", - "psalm/plugin-laravel": "^2.8", - "psr-mock/http": "^1.0", - "rector/rector": "^0.15.25", - "symfony/cache": "^6.2.8", - "vimeo/psalm": "^5.9", - "wikimedia/composer-merge-plugin": "^2.1.0" + "friendsofphp/php-cs-fixer": "^3", + "mockery/mockery": "^1", + "nunomaduro/larastan": "^2", + "orchestra/testbench": "^7 || ^8", + "pestphp/pest": "^2", + "pestphp/pest-plugin-laravel": "^2", + "phpstan/phpstan": "^1", + "phpstan/phpstan-strict-rules": "^1", + "psalm/plugin-laravel": "^2", + "psr-mock/http": "^1", + "rector/rector": "*", + "spatie/laravel-ray": "^1", + "squizlabs/php_codesniffer": "^3", + "symfony/cache": "^6", + "vimeo/psalm": "^5", + "wikimedia/composer-merge-plugin": "^2" }, "minimum-stability": "dev", "prefer-stable": true, "autoload": { "psr-4": { - "Auth0\\Laravel\\": "src" + "Auth0\\Laravel\\": [ + "src/", + "deprecated/" + ] } }, "autoload-dev": { "psr-4": { - "Auth0\\Laravel\\Tests\\": "tests" + "Auth0\\Laravel\\Tests\\": "tests/" } }, "config": { "allow-plugins": { "pestphp/pest-plugin": true, "wikimedia/composer-merge-plugin": true, - "infection/extension-installer": true, "php-http/discovery": false }, "optimize-autoloader": true, @@ -108,9 +113,9 @@ }, "scripts": { "pest:coverage": "@php vendor/bin/pest --coverage --parallel --no-progress", - "pest:debug": "@php vendor/bin/pest --log-events-verbose-text pest.log --fail-on-risky --stop-on-failure", + "pest:debug": "@php vendor/bin/pest --fail-on-risky --stop-on-defect", "pest:profile": "@php vendor/bin/pest --profile", - "pest": "@php vendor/bin/pest --order-by random --fail-on-risky", + "pest": "@php vendor/bin/pest --order-by random --fail-on-risky --stop-on-defect --coverage --parallel --min=95", "phpcs:fix": "@php vendor/bin/php-cs-fixer fix", "phpcs": "@php vendor/bin/php-cs-fixer fix --dry-run --diff", "phpstan": "@php vendor/bin/phpstan analyze", diff --git a/config/auth0.php b/config/auth0.php index 5fc380da..02010290 100644 --- a/config/auth0.php +++ b/config/auth0.php @@ -5,65 +5,51 @@ use Auth0\Laravel\Configuration; use Auth0\SDK\Configuration\SdkConfiguration; -/* - * Please review available configuration options here: - * https://github.com/auth0/auth0-PHP#configuration-options. - */ -return [ - // Should be assigned either 'api', 'management', or 'webapp' to indicate your application's use case for the SDK. - // Determines what configuration options will be required. - 'strategy' => env('AUTH0_STRATEGY', SdkConfiguration::STRATEGY_REGULAR), - - // Auth0 domain for your tenant, found in your Auth0 Application settings. - 'domain' => env('AUTH0_DOMAIN'), - - // If you have configured Auth0 to use a custom domain, configure it here. - 'customDomain' => env('AUTH0_CUSTOM_DOMAIN'), - - // Client ID, found in the Auth0 Application settings. - 'clientId' => env('AUTH0_CLIENT_ID'), - - // Authentication callback URI, as defined in your Auth0 Application settings. - 'redirectUri' => env('AUTH0_REDIRECT_URI', env('APP_URL') . '/callback'), - - // Client Secret, found in the Auth0 Application settings. - 'clientSecret' => env('AUTH0_CLIENT_SECRET'), - - // One or more API identifiers, found in your Auth0 API settings. The SDK uses the first value for building links. If provided, at least one of these values must match the 'aud' claim to validate an ID Token successfully. - 'audience' => Configuration::stringToArrayOrNull(env('AUTH0_AUDIENCE')), - - // One or more scopes to request for Tokens. See https://auth0.com/docs/scopes - 'scope' => Configuration::stringToArray(env('AUTH0_SCOPE')), - - // One or more Organization IDs, found in your Auth0 Organization settings. The SDK uses the first value for building links. If provided, at least one of these values must match the 'org_id' claim to validate an ID Token successfully. - 'organization' => Configuration::stringToArrayOrNull(env('AUTH0_ORGANIZATION')), - - // The secret used to derive an encryption key for the user identity in a session cookie and to sign the transient cookies used by the login callback. - 'cookieSecret' => env('AUTH0_COOKIE_SECRET', env('APP_KEY')), - - // How long, in seconds, before cookies expire. If set to 0 the cookie will expire at the end of the session (when the browser closes). - 'cookieExpires' => (int) env('AUTH0_COOKIE_EXPIRES', 0), - - // Cookie domain, for example 'www.example.com', for use with PHP sessions and SDK cookies. Defaults to value of HTTP_HOST server environment information. - // Note: To make cookies visible on all subdomains then the domain must be prefixed with a dot like '.example.com'. - 'cookieDomain' => env('AUTH0_COOKIE_DOMAIN'), - - // Specifies path on the domain where the cookies will work. Defaults to '/'. Use a single slash ('/') for all paths on the domain. - 'cookiePath' => env('AUTH0_COOKIE_PATH', '/'), - - // Defaults to false. Specifies whether cookies should ONLY be sent over secure connections. - 'cookieSecure' => Configuration::stringToBoolOrNull(env('AUTH0_COOKIE_SECURE'), false), - - // Named routes within your Laravel application that the SDK may call during stateful requests for redirections. - 'routes' => [ - 'home' => env('AUTH0_ROUTE_HOME', '/'), - 'login' => env('AUTH0_ROUTE_LOGIN', 'login'), +return Configuration::VERSION_2 + [ + 'registerGuards' => true, + 'registerMiddleware' => true, + 'registerAuthenticationRoutes' => true, + + 'guards' => [ + 'default' => [ + Configuration::CONFIG_STRATEGY => Configuration::get(Configuration::CONFIG_STRATEGY, SdkConfiguration::STRATEGY_NONE), + Configuration::CONFIG_DOMAIN => Configuration::get(Configuration::CONFIG_DOMAIN), + Configuration::CONFIG_CUSTOM_DOMAIN => Configuration::get(Configuration::CONFIG_CUSTOM_DOMAIN), + Configuration::CONFIG_CLIENT_ID => Configuration::get(Configuration::CONFIG_CLIENT_ID), + Configuration::CONFIG_CLIENT_SECRET => Configuration::get(Configuration::CONFIG_CLIENT_SECRET), + Configuration::CONFIG_AUDIENCE => Configuration::get(Configuration::CONFIG_AUDIENCE), + Configuration::CONFIG_ORGANIZATION => Configuration::get(Configuration::CONFIG_ORGANIZATION), + Configuration::CONFIG_USE_PKCE => Configuration::get(Configuration::CONFIG_USE_PKCE), + Configuration::CONFIG_SCOPE => Configuration::get(Configuration::CONFIG_SCOPE), + Configuration::CONFIG_RESPONSE_MODE => Configuration::get(Configuration::CONFIG_RESPONSE_MODE), + Configuration::CONFIG_RESPONSE_TYPE => Configuration::get(Configuration::CONFIG_RESPONSE_TYPE), + Configuration::CONFIG_TOKEN_ALGORITHM => Configuration::get(Configuration::CONFIG_TOKEN_ALGORITHM), + Configuration::CONFIG_TOKEN_JWKS_URI => Configuration::get(Configuration::CONFIG_TOKEN_JWKS_URI), + Configuration::CONFIG_TOKEN_MAX_AGE => Configuration::get(Configuration::CONFIG_TOKEN_MAX_AGE), + Configuration::CONFIG_TOKEN_LEEWAY => Configuration::get(Configuration::CONFIG_TOKEN_LEEWAY), + Configuration::CONFIG_TOKEN_CACHE => Configuration::get(Configuration::CONFIG_TOKEN_CACHE), + Configuration::CONFIG_TOKEN_CACHE_TTL => Configuration::get(Configuration::CONFIG_TOKEN_CACHE_TTL), + Configuration::CONFIG_HTTP_MAX_RETRIES => Configuration::get(Configuration::CONFIG_HTTP_MAX_RETRIES), + Configuration::CONFIG_HTTP_TELEMETRY => Configuration::get(Configuration::CONFIG_HTTP_TELEMETRY), + Configuration::CONFIG_MANAGEMENT_TOKEN => Configuration::get(Configuration::CONFIG_MANAGEMENT_TOKEN), + Configuration::CONFIG_MANAGEMENT_TOKEN_CACHE => Configuration::get(Configuration::CONFIG_MANAGEMENT_TOKEN_CACHE), + Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_KEY => Configuration::get(Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_KEY), + Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_ALGORITHM => Configuration::get(Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_ALGORITHM), + Configuration::CONFIG_PUSHED_AUTHORIZATION_REQUEST => Configuration::get(Configuration::CONFIG_PUSHED_AUTHORIZATION_REQUEST), + ], + + 'api' => [ + Configuration::CONFIG_STRATEGY => SdkConfiguration::STRATEGY_API, + ], + + 'web' => [ + Configuration::CONFIG_STRATEGY => SdkConfiguration::STRATEGY_REGULAR, + Configuration::CONFIG_COOKIE_SECRET => Configuration::get(Configuration::CONFIG_COOKIE_SECRET, env('APP_KEY')), + Configuration::CONFIG_REDIRECT_URI => Configuration::get(Configuration::CONFIG_REDIRECT_URI, env('APP_URL') . '/callback'), + Configuration::CONFIG_SESSION_STORAGE => Configuration::get(Configuration::CONFIG_SESSION_STORAGE), + Configuration::CONFIG_SESSION_STORAGE_ID => Configuration::get(Configuration::CONFIG_SESSION_STORAGE_ID), + Configuration::CONFIG_TRANSIENT_STORAGE => Configuration::get(Configuration::CONFIG_TRANSIENT_STORAGE), + Configuration::CONFIG_TRANSIENT_STORAGE_ID => Configuration::get(Configuration::CONFIG_TRANSIENT_STORAGE_ID), + ], ], - - 'behavior' => [ - // If TRUE, the Guard will follow < 7.5 behavior in which calling Guard::user() will automatically login a user using discovered credentials, if they are not already. - // Note that if this property is missing from the configuration, the SDK will default to true as a fallback for previous behavior. - // You must explicitly set it to FALSE to disable this behavior. - 'legacyGuardUserMethod' => Configuration::stringToBoolOrNull(env('AUTH0_BEHAVIOR_LEGACY_GUARD_USER_METHOD'), false), - ] ]; diff --git a/deprecated/Cache/LaravelCacheItem.php b/deprecated/Cache/LaravelCacheItem.php new file mode 100644 index 00000000..391641d8 --- /dev/null +++ b/deprecated/Cache/LaravelCacheItem.php @@ -0,0 +1,56 @@ +expiration = match (true) { + null === $time => new DateTimeImmutable('now +1 year'), + is_int($time) => new DateTimeImmutable('now +' . (string) $time . ' seconds'), + $time instanceof DateInterval => (new DateTimeImmutable())->add($time), + }; + + return $this; + } + + public function expiresAt(?DateTimeInterface $expiration): static + { + $this->expiration = $expiration ?? new DateTimeImmutable('now +1 year'); + + return $this; + } + + public function set(mixed $value): static + { + $this->value = $value; + + return $this; + } + + public static function miss(string $key): self + { + return new self( + key: $key, + value: null, + hit: false, + ); + } +} diff --git a/deprecated/Cache/LaravelCachePool.php b/deprecated/Cache/LaravelCachePool.php new file mode 100644 index 00000000..0641f7d5 --- /dev/null +++ b/deprecated/Cache/LaravelCachePool.php @@ -0,0 +1,18 @@ +.json` +- `auth0.api.json` +- `auth0.app.json` +- `auth0.api..json` +- `auth0.app..json` + +Where `` is the value of Laravel's `APP_ENV` environment variable (if set.) Duplicate keys in the files listed above will be overwritten in the order listed. + +## Environment Variables + +The SDK supports the use of environment variables to configure the SDK. These can be defined in the `.env` file in the root of your project, or in your hosting environment. + +| Variable | Description | +| --------------------- | --------------------------------------------------------------------------------------------------- | +| `AUTH0_STRATEGY` | String. The Auth0 strategy to use. | +| `AUTH0_DOMAIN` | String (FQDN.) The Auth0 domain for your tenant. | +| `AUTH0_CUSTOM_DOMAIN` | String (FQDN.) The Auth0 custom domain for your tenant, if set. | +| `AUTH0_CLIENT_ID` | String. The Client ID for your Auth0 application. | +| `AUTH0_CLIENT_SECRET` | String. The Client Secret for your Auth0 application. | +| `AUTH0_COOKIE_SECRET` | String. The optional secret used to encrypt the cookie used by the SDK. | +| `AUTH0_REDIRECT_URI` | String (URL.) The redirect URI for your application. | +| `AUTH0_AUDIENCE` | String (comma-delimited list.) The audiences for your application. | +| `AUTH0_SCOPE` | String (comma-delimited list.) The scopes for your application. Defaults to 'openid,profile,email'. | +| `AUTH0_ORGANIZATION` | String (comma-delimited list.) The organizations for your application. | + +The following environment variables are also supported, but should not be adjusted unless you know what you are doing: + +| Variable | Description | +| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `AUTH0_USE_PKCE` | Boolean. Whether to use PKCE for the authorization flow. Defaults to `true`. | +| `AUTH0_RESPONSE_MODE` | String. The response mode to use for the authorization flow. Defaults to `query`. | +| `AUTH0_RESPONSE_TYPE` | String. The response type to use for the authorization flow. Defaults to `code`. | +| `AUTH0_TOKEN_ALGORITHM` | String. The algorithm to use for the ID token. Defaults to `RS256`. | +| `AUTH0_TOKEN_JWKS_URI` | String (URL.) The URI to use to retrieve the JWKS for the ID token. Defaults to `https:///.well-known/jwks.json`. | +| `AUTH0_TOKEN_MAX_AGE` | Integer. The maximum age of a token, in seconds. No default value is assigned. | +| `AUTH0_TOKEN_LEEWAY` | Integer. The leeway to use when validating a token, in seconds. Defaults to `60` (1 minute). | +| `AUTH0_TOKEN_CACHE` | String (class name.) A PSR-6 class to use for caching JWKS responses. | +| `AUTH0_TOKEN_CACHE_TTL` | Integer. The TTL to use for caching JWKS responses. Defaults to `60` (1 minute). | +| `AUTH0_HTTP_MAX_RETRIES` | Integer. The maximum number of times to retry a failed HTTP request. Defaults to `3`. | +| `AUTH0_HTTP_TELEMETRY` | Boolean. Whether to send telemetry data with HTTP requests to Auth0. Defaults to `true`. | +| `AUTH0_SESSION_STORAGE` | String (class name.) The `StoreInterface` class to use for storing session data. Defaults to using Laravel's native Sessions API. | +| `AUTH0_SESSION_STORAGE_ID` | String. The namespace to use for storing session data. Defaults to `auth0_session`. | +| `AUTH0_TRANSIENT_STORAGE` | String (class name.) The `StoreInterface` class to use for storing temporary session data. Defaults to using Laravel's native Sessions API. | +| `AUTH0_TRANSIENT_STORAGE_ID` | String. The namespace to use for storing temporary session data. Defaults to `auth0_transient`. | +| `AUTH0_MANAGEMENT_TOKEN` | String (class name.) The Management API token to use for the Management API client. (If one is not provided, the SDK will attempt to create one for you.) | +| `AUTH0_MANAGEMENT_TOKEN_CACHE` | Integer. A PSR-6 class to use for caching Management API tokens. | +| `AUTH0_CLIENT_ASSERTION_SIGNING_KEY` | String. The key to use for signing client assertions. | +| `AUTH0_CLIENT_ASSERTION_SIGNING_ALGORITHM` | String. The algorithm to use for signing client assertions. Defaults to `RS256`. | +| `AUTH0_PUSHED_AUTHORIZATION_REQUEST` | Boolean. Whether the SDK should use Pushed Authorization Requests during authentication. Note that your tenant must have this feature enabled. Defaults to `false`. | + +## Overriding Automatic Behavior + +### Guard Registration + +By default, the SDK will register the Authentication and Authorization guards with your Laravel application, as well as a compatible [User Provider](./Users.md). + +You can disable this behavior by setting `registerGuards` to false in your `config/auth0.php` file. + +To register the guards manually, update your `config/auth.php` file as follows: + +```php +'guards' => [ + 'auth0-session' => [ + 'driver' => 'auth0.authentication', + 'provider' => 'auth0-provider', + 'configuration' => 'web', + ], + 'auth0-api' => [ + 'driver' => 'auth0.authorization', + 'provider' => 'auth0-provider', + 'configuration' => 'api', + ], +], + +'providers' => [ + 'auth0-provider' => [ + 'driver' => 'auth0', + 'repository' => \Auth0\Laravel\Auth\User\Repository::class, + ], +], +``` + +### Middleware Registration + +By default, the SDK will register the Authentication and Authorization guards within your application's `web` and `api` middleware groups. You can disable this behavior by setting `registerMiddleware` to false in your `config/auth0.php` file. + +To register the middleware manually, update your `app/Http/Kernel.php` file as follows: + +```php +protected $middlewareGroups = [ + 'web' => [ + // ... + \Auth0\Laravel\Middleware\Authenticate::class, + // ... + ], + + 'api' => [ + // ... + \Auth0\Laravel\Middleware\Authorization::class, + // ... + ], +]; +``` + +Alternatively, you can assign the guards to specific routes by using the `Auth` facade. For `routes/web.php`, add the following before any routes: + +```php +Auth::shouldUse('auth0-session'); +``` + +For `routes/api.php`, add the following before any routes: + +```php +Auth::shouldUse('auth0-api'); +``` + +### Authentication Routes + +By default, the SDK will register the following routes for authentication: + +| Method | URI | Name | Controller | Purpose | +| ------ | ----------- | ---------- | ------------------------------------------------- | ---------------------------------- | +| `GET` | `/login` | `login` | `Auth0\Laravel\Controllers\LoginController` | Initiates the authentication flow. | +| `GET` | `/logout` | `logout` | `Auth0\Laravel\Controllers\LogoutController` | Logs the user out. | +| `GET` | `/callback` | `callback` | `Auth0\Laravel\Controllers\CallbackController` | Handles the callback from Auth0. | + +You can disable this behavior by setting `registerAuthenticationRoutes` to false in your `config/auth0.php` file. + +If you've disabled the automatic registration of routes, you can register the routes manually by adding the following to your `routes/web.php` file: + +```php +Auth0::routes(); +``` + +Or, if you prefer complete control over the routing process: + +```php +use Auth0\Laravel\Controllers\{Login, Logout, Callback}; + +Route::group(['middleware' => ['guard:auth0-session'], static function (): void { + Route::get('/login', Login::class)->name('login'); + Route::get('/logout', Logout::class)->name('logout'); + Route::get('/callback', Callback::class)->name('callback'); +}); +``` diff --git a/docs/Events.md b/docs/Events.md index 218dcb33..04618c7a 100644 --- a/docs/Events.md +++ b/docs/Events.md @@ -38,48 +38,50 @@ You can learn more about working with the Laravel event system in the [Laravel d ## Login Controller Events -During login with the `Auth0\Laravel\Http\Controller\Stateful\Login` controller, the following events may be raised: +During login with `Auth0\Laravel\Controllers\LoginController` the following events may be raised: -| Event | Description | -| ------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -| `Illuminate\Auth\Events\Login` | Raised when a user is logging in. The model of the user is provided with the event. | -| `Auth0\Laravel\Contract\Event\Stateful\LoginAttempting` | Raised before the login redirect is issued, allowing an opportunity to customize parameters. | +| Event | Description | +| -------------------------------------- | -------------------------------------------------------------------------------------------- | +| `Illuminate\Auth\Events\Login` | Raised when a user is logging in. The model of the user is provided with the event. | +| `Auth0\Laravel\Events\LoginAttempting` | Raised before the login redirect is issued, allowing an opportunity to customize parameters. | ## Callback Controller Events -During callback with the `Auth0\Laravel\Http\Controller\Stateful\Callback` controller, the following events may be raised: +During callback with `Auth0\Laravel\Controllers\CallbackController` the following events may be raised: | Event | Description | | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Illuminate\Auth\Events\Attempting` | Raised when a user is returned to the application after authenticating with Auth0. This is raised before verification of the authentication process begins. | | `Illuminate\Auth\Events\Failed` | Raised when authentication with Auth0 failed. The reason is provided with the event as an array. | -| `Auth0\Laravel\Event\Stateful\AuthenticationFailed` | Raised when authentication with Auth0 failed. This provides an opportunity to intercept the exception thrown by the middleware, by using the event's `setThrowException()` method to `false`. You can also customize the type of exception thrown using `setException()`. | +| `Auth0\Laravel\Events\AuthenticationFailed` | Raised when authentication with Auth0 failed. This provides an opportunity to intercept the exception thrown by the middleware, by using the event's `setThrowException()` method to `false`. You can also customize the type of exception thrown using `setException()`. | | `Illuminate\Auth\Events\Illuminate\Auth\Events\Validated` | Raised when authentication was successful, but immediately before the user's session is established. | -| `Auth0\Laravel\Event\Stateful\AuthenticationSucceeded` | Raised when authentication was successful. The model of the authenticated user is provided with the event. | +| `Auth0\Laravel\Events\AuthenticationSucceeded` | Raised when authentication was successful. The model of the authenticated user is provided with the event. | ## Logout Controller Events -During logout with the `Auth0\Laravel\Http\Controller\Stateful\Logout` controller, the following events may be raised: +During logout with `Auth0\Laravel\Controllers\LogoutController` the following events may be raised: | Event | Description | | ------------------------------- | ------------------------------------------------------------------------------------ | | `Illuminate\Auth\Events\Logout` | Raised when a user is logging out. The model of the user is provided with the event. | -## Authentication Middleware Events +## Deprecated Middleware Events -During request handling with any `Auth0\Laravel\Http\Middleware\Stateful` middleware, the following events may be raised: +### Authentication Middleware Events -| Event | Description | -| ------------------------------------------------ | ---------------------------------------------------------------------------------- | -| `Auth0\Laravel\Event\Middleware\StatefulRequest` | Raised when a request is being handled by a session-based ('stateful') middleware. | +During request handling with `Auth0\Laravel\Middleware\AuthenticateMiddleware` or `Auth0\Laravel\Middleware\AuthenticateOptionalMiddleware` the following events may be raised: -## Authorization Middleware Events +| Event | Description | +| ----------------------------------------------------------- | ---------------------------------------------------------------------------------- | +| `Auth0\Laravel\Events\Middleware\StatefulMiddlewareRequest` | Raised when a request is being handled by a session-based ('stateful') middleware. | -During request handling with any `Auth0\Laravel\Http\Controller\Stateless` middleware, the following events may be raised: +### Authorization Middleware Events -| Event | Description | -| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | -| `Auth0\Laravel\Event\Middleware\StatelessRequest` | Raised when a request is being handled by an access token-based ('stateless') middleware. | -| `Auth0\Laravel\Event\Stateless\TokenVerificationAttempting` | Raised before an access token is attempted to be verified. The encoded token string is provided with the event. | -| `Auth0\Laravel\Event\Stateless\TokenVerificationSucceeded` | Raised when an access token is successfully verified. The decoded token contents are provided with the event. | -| `Auth0\Laravel\Event\Stateless\TokenVerificationFailed` | Raised when an access token cannot be verified. The reason (as a string) is provided with the event. | +During request handling with `Auth0\Laravel\Middleware\AuthorizeMiddleware` or `Auth0\Laravel\Middleware\AuthorizeOptionalMiddleware` middleware, the following events may be raised: + +| Event | Description | +| ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- | +| `Auth0\Laravel\Events\Middleware\StatelessMiddlewareRequest` | Raised when a request is being handled by an access token-based ('stateless') middleware. | +| `Auth0\Laravel\Events\TokenVerificationAttempting` | Raised before an access token is attempted to be verified. The encoded token string is provided with the event. | +| `Auth0\Laravel\Events\TokenVerificationSucceeded` | Raised when an access token is successfully verified. The decoded token contents are provided with the event. | +| `Auth0\Laravel\Events\TokenVerificationFailed` | Raised when an access token cannot be verified. The reason (as a string) is provided with the event. | diff --git a/docs/Installation.md b/docs/Installation.md new file mode 100644 index 00000000..68c81dab --- /dev/null +++ b/docs/Installation.md @@ -0,0 +1,21 @@ +# Installation + +This document is an addendum to the [README](../README.md) file, and covers advanced installation techniques. Please review the installation guidance there before continuing. + +## Alternative Configuration Methods + +Although our guidance is to use the Auth0 CLI to create the JSON configuration files for the SDK, we recognize that this may not be possible in all cases. + +### Environment Variables + +The SDK supports the use of environment variables to configure the SDK. These can be defined in the `.env` file in the root of your project, or in your hosting environment. + +To successfully use the SDK, you must provide the following environment variables at a minimum: + +| Variable | Description | +| --------------------- | --------------------------------------- | +| `AUTH0_DOMAIN` | The Auth0 domain for your tenant. | +| `AUTH0_CLIENT_ID` | The Client ID for your application. | +| `AUTH0_CLIENT_SECRET` | The Client Secret for your application. | + +For a full list of supported environment variables, see [Configuration](./Configuration.md). diff --git a/docs/Management API.md b/docs/Management.md similarity index 99% rename from docs/Management API.md rename to docs/Management.md index 3b393d93..5dc662b7 100644 --- a/docs/Management API.md +++ b/docs/Management.md @@ -2,12 +2,18 @@ The Auth0 Laravel SDK provides easy-to-use methods to access Auth0's Management API endpoints. Nearly every endpoint of the Management API is available to use with your Laravel application. For more information about any of these endpoints, see the [Management API Explorer](https://auth0.com/docs/api/management/v2). +## Management API Permissions + +Before making Management API calls you must enable your application to communicate with the Management API. This can be done from the [Auth0 Dashboard's API page](https://manage.auth0.com/#/apis/), choosing `Auth0 Management API`, and selecting the 'Machine to Machine Applications' tab. Authorize your Laravel application, and then click the down arrow to choose the scopes you wish to grant. + ## Accessing the Management API The Management API class can be accessed through the `management()` method on the Auth0 Laravel SDK service. You can pull the Auth0 SDK instance from the Laravel service container using dependency injection, or use the `Auth0` facade. Once you have an instance, you can call any of the [available endpoints](#available-endpoints). ```php -$management = app('auth0')->management(); +use Auth0\Laravel\Facade\Auth0; + +Auth0::management(); ``` ## Available endpoints diff --git a/docs/User Models and Repositories.md b/docs/Users.md similarity index 59% rename from docs/User Models and Repositories.md rename to docs/Users.md index 78757d76..b276a9bc 100644 --- a/docs/User Models and Repositories.md +++ b/docs/Users.md @@ -1,27 +1,57 @@ -# User Models and Repositories +# Users -The Auth0 Laravel SDK uses the repository pattern to allow the abstraction of potential database operations. This pattern is useful for building completely custom integrations that fit your application's needs. +## Retrieving User Information -Let's assume you've configured the SDK's user provider in application's `config/auth.php` like this: +To retrieve information about the currently authenticated user, use the `user()` method on the `Auth0` facade, or the `auth0()` helper. ```php -/** - * Register the SDK's User Provider with your application. - * You should not remove any other entries from this array. - */ -'providers' => [ - 'my-example-provider' => [ - 'driver' => 'auth0.provider', - 'repository' => \Auth0\Laravel\Auth\User\Repository::class - ], -], +auth()->user(); +``` + +You can also retrieve information for any user using [the Management API](./Management.md). This also returns extended information about the user, including stored metadata. + +```php +use Auth0\Laravel\Facade\Auth0; + +Route::get('/profile', function () { + $profile = Auth0::management()->users()->get(auth()->id()); + $profile = Auth0::json($profile); + + $name = $profile['name'] ?? 'Unknown'; + $email = $profile['email'] ?? 'Unknown'; + + return response("Hello {$name}! Your email address is {$email}."); +})->middleware('auth'); +``` + +## Updating User Information + +To update a user's information, use [the Management API](./Management.md). + +```php +use Auth0\Laravel\Facade\Auth0; + +Route::get('/update', function () { + Auth0::management() + ->users() + ->update( + id: auth()->id(), + body: [ + 'user_metadata' => [ + 'last_visited' => time() + ] + ] + ); +})->middleware('auth'); ``` -Note the `repository` property — this tells the SDK what class to use for storing and retrieving users. The SDK provides a default implementation, but this does not persist users to an application database. You can add this functionality by using the default implementation as a starting point for building a custom repository of your own. +## Custom User Models and Repositories -## Creating a User Repository +The Auth0 Laravel SDK uses the repository pattern to allow the abstraction of potential database operations. This pattern is useful for building completely custom integrations that fit your application's needs. + +### Creating a User Repository -Creating a repository is simple: it must implement the `Auth0\Laravel\Contract\Auth\User\Repository` interface, and include two methods: +Creating a repository is simple: it must implement the `Auth0\Laravel\Auth\User\RepositoryContract` interface, and include two methods: - `fromSession()` is used to retrieve a user from the application's session. - `fromAccessToken` is used to retrieve a user from an access token. @@ -33,14 +63,12 @@ The default implementation looks like this: declare(strict_types=1); -namespace Auth0\Laravel\Auth\User; +namespace Auth0\Laravel; -use Auth0\Laravel\Contract\Auth\User\Repository as RepositoryContract; -use Auth0\Laravel\Model\Stateful\User as StatefulUser; -use Auth0\Laravel\Model\Stateless\User as StatelessUser; +use Auth0\Laravel\Users\{StatefulUser, StatelessUser}; use Illuminate\Contracts\Auth\Authenticatable; -final class Repository implements RepositoryContract +final class UserRepository extends UserRepositoryAbstract implements UserRepositoryContract { public function fromAccessToken(array $user): ?Authenticatable { @@ -64,7 +92,7 @@ declare(strict_types=1); namespace App\Repositories; use App\Models\User; -use Auth0\Laravel\Contract\Auth\User\Repository as RepositoryContract; +use Auth0\Laravel\Auth\User\RepositoryContract; use Illuminate\Contracts\Auth\Authenticatable; final class UserRepository implements RepositoryContract @@ -89,12 +117,12 @@ final class UserRepository implements RepositoryContract } ``` -## Creating a User Model +### Creating a User Model -The repository is responsible for retrieving and storing users, but it does not define the user model itself. The SDK provides an abstract user model class that can be extended for building your own implementations, `Auth0\Laravel\Model\User`. +The repository is responsible for retrieving and storing users, but it does not define the user model itself. The SDK provides an abstract user model class that can be extended for building your own implementations, `Auth0\Laravel\Entities\UserAbstract`. - User models must implement the `Illuminate\Contracts\Auth\Authenticatable` interface, which is required for Laravel's authentication system. -- User models must also implement the `Auth0\Laravel\Contract\Model\User` interface, which is required by the Laravel SDK. +- User models must also implement the `Auth0\Laravel\Entities\UserContract` interface, which is required by the Laravel SDK. Because the abstract model already fulfills the requirements of these interfaces, you can use it as-is if you do not need to add any additional functionality. Here's an example customer user model that extends the SDK's abstract user model class to support Eloquent: @@ -105,10 +133,12 @@ declare(strict_types=1); namespace App\Models; -use Auth0\Laravel\Model\User as Auth0User; +use Auth0\Laravel\Users\{UserAbstract, UserContract, UserTrait}; -final class User extends Auth0User +final class User extends UserAbstract implements UserContract { + use UserTrait; + protected $table = 'users'; protected $fillable = [ @@ -124,9 +154,9 @@ final class User extends Auth0User } ``` -## Integrating the Repository and Model +### Integrating the Repository and Model -Once you have created your repository and model, you can integrate them into your application by updating your `config/auth.php` file: +Once you have created your repository and model, you can integrate them into your application by updating your `config/auth.php` file and pointing the `repository` key to your repository class. ```php /** @@ -134,7 +164,7 @@ Once you have created your repository and model, you can integrate them into you * You should not remove any other entries from this array. */ 'providers' => [ - 'my-example-provider' => [ + 'auth0-provider' => [ 'driver' => 'auth0.provider', 'repository' => \App\Repositories\UserRepository::class, ], diff --git a/infection.json5.dist b/infection.json5.dist deleted file mode 100644 index ac2a7eeb..00000000 --- a/infection.json5.dist +++ /dev/null @@ -1,11 +0,0 @@ -{ - source: { - directories: ["src"], - }, - logs: { - "text": "infection.log" - }, - mutators: { - "@default": true, - } -} diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 613517aa..7f633302 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -7,9 +7,7 @@ parameters: paths: - src - - bootstrapFiles: - - tests/constants.php + - deprecated ignoreErrors: - '#Method (.*) has parameter (.*) with no value type specified in iterable type array.#' @@ -17,3 +15,4 @@ parameters: reportUnmatchedIgnoredErrors: false treatPhpDocTypesAsCertain: false + checkGenericClassInNonGenericObjectType: false diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 95b55956..a52f9a82 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -19,9 +19,8 @@ ./src/ - ./src/Event/ - ./src/Contract/ - ./src/Exception/ + ./src/Events/ + ./src/Exceptions/ diff --git a/psalm.xml.dist b/psalm.xml.dist index 19efe4a1..938c039f 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -10,6 +10,7 @@ > + @@ -18,6 +19,8 @@ + + diff --git a/rector.php b/rector.php index 50008adb..ef7303bb 100644 --- a/rector.php +++ b/rector.php @@ -96,7 +96,6 @@ use Rector\CodingStyle\Rector\Plus\UseIncrementAssignRector; use Rector\CodingStyle\Rector\PostInc\PostIncDecToPreIncDecRector; use Rector\CodingStyle\Rector\Property\{AddFalseDefaultToBoolPropertyRector, SplitGroupedPropertiesRector}; -use Rector\CodingStyle\Rector\Stmt\NewlineAfterStatementRector; use Rector\CodingStyle\Rector\String_\{SymplifyQuoteEscapeRector, UseClassKeywordForClassNameResolutionRector}; use Rector\CodingStyle\Rector\Switch_\BinarySwitchToIfElseRector; use Rector\CodingStyle\Rector\Ternary\TernaryConditionVariableAssignmentRector; @@ -107,7 +106,6 @@ RemoveUnusedVariableAssignRector}; use Rector\DeadCode\Rector\BinaryOp\RemoveDuplicatedInstanceOfRector; use Rector\DeadCode\Rector\BooleanAnd\RemoveAndTrueRector; -use Rector\DeadCode\Rector\Cast\RecastingRemovalRector; use Rector\DeadCode\Rector\ClassConst\RemoveUnusedPrivateClassConstantRector; use Rector\DeadCode\Rector\ClassMethod\{RemoveDelegatingParentCallRector, RemoveEmptyClassMethodRector, @@ -118,7 +116,6 @@ RemoveUnusedPromotedPropertyRector, RemoveUselessParamTagRector, RemoveUselessReturnTagRector}; -use Rector\DeadCode\Rector\Concat\RemoveConcatAutocastRector; use Rector\DeadCode\Rector\Expression\{RemoveDeadStmtRector, SimplifyMirrorAssignRector}; use Rector\DeadCode\Rector\For_\{RemoveDeadContinueRector, @@ -158,14 +155,11 @@ ReturnBinaryAndToEarlyReturnRector, ReturnBinaryOrToEarlyReturnRector}; use Rector\EarlyReturn\Rector\StmtsAwareInterface\ReturnEarlyIfVariableRector; -use Rector\Naming\Rector\Assign\RenameVariableToMatchMethodCallReturnTypeRector; -use Rector\Naming\Rector\Class_\RenamePropertyToMatchTypeRector; use Rector\Naming\Rector\ClassMethod\{RenameParamToMatchTypeRector, RenameVariableToMatchNewTypeRector}; use Rector\Naming\Rector\Foreach_\{RenameForeachValueVariableToMatchExprVariableRector, RenameForeachValueVariableToMatchMethodCallReturnTypeRector}; use Rector\Php52\Rector\Property\VarToPublicPropertyRector; -use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; use Rector\Php71\Rector\FuncCall\RemoveExtraParametersRector; use Rector\Php80\Rector\Catch_\RemoveUnusedVariableInCatchRector; use Rector\Php80\Rector\Class_\{ClassPropertyAssignToConstructorPromotionRector, @@ -189,7 +183,6 @@ ChangeReadOnlyVariableWithDefaultValueToConstantRector, FinalizeClassesWithoutChildrenRector}; use Rector\Privatization\Rector\ClassMethod\PrivatizeFinalClassMethodRector; -use Rector\Privatization\Rector\MethodCall\PrivatizeLocalGetterToPropertyRector; use Rector\Privatization\Rector\Property\{ChangeReadOnlyPropertyWithDefaultValueToConstantRector, PrivatizeFinalClassPropertyRector}; use Rector\PSR4\Rector\FileWithoutNamespace\NormalizeNamespaceByPSR4ComposerAutoloadRector; @@ -240,27 +233,27 @@ $rectorConfig->ruleWithConfiguration( RenameFunctionRector::class, [ - 'chop' => 'rtrim', - 'doubleval' => 'floatval', - 'fputs' => 'fwrite', - 'gzputs' => 'gzwrites', - 'ini_alter' => 'ini_set', - 'is_double' => 'is_float', - 'is_integer' => 'is_int', - 'is_long' => 'is_int', - 'is_real' => 'is_float', + 'chop' => 'rtrim', + 'doubleval' => 'floatval', + 'fputs' => 'fwrite', + 'gzputs' => 'gzwrites', + 'ini_alter' => 'ini_set', + 'is_double' => 'is_float', + 'is_integer' => 'is_int', + 'is_long' => 'is_int', + 'is_real' => 'is_float', 'is_writeable' => 'is_writable', - 'join' => 'implode', - 'key_exists' => 'array_key_exists', - 'mbstrcut' => 'mb_strcut', - 'mbstrlen' => 'mb_strlen', - 'mbstrpos' => 'mb_strpos', - 'mbstrrpos' => 'mb_strrpos', - 'mbsubstr' => 'mb_substr', - 'pos' => 'current', - 'sizeof' => 'count', - 'split' => 'explode', - 'strchr' => 'strstr', + 'join' => 'implode', + 'key_exists' => 'array_key_exists', + 'mbstrcut' => 'mb_strcut', + 'mbstrlen' => 'mb_strlen', + 'mbstrpos' => 'mb_strpos', + 'mbstrrpos' => 'mb_strrpos', + 'mbsubstr' => 'mb_substr', + 'pos' => 'current', + 'sizeof' => 'count', + 'split' => 'explode', + 'strchr' => 'strstr', ], ); @@ -281,30 +274,30 @@ $rectorConfig->ruleWithConfiguration( RenameFunctionRector::class, [ - 'pg_clientencoding' => 'pg_client_encoding', - 'pg_cmdtuples' => 'pg_affected_rows', - 'pg_errormessage' => 'pg_last_error', - 'pg_fieldisnull' => 'pg_field_is_null', - 'pg_fieldname' => 'pg_field_name', - 'pg_fieldnum' => 'pg_field_num', - 'pg_fieldprtlen' => 'pg_field_prtlen', - 'pg_fieldsize' => 'pg_field_size', - 'pg_fieldtype' => 'pg_field_type', - 'pg_freeresult' => 'pg_free_result', - 'pg_getlastoid' => 'pg_last_oid', - 'pg_loclose' => 'pg_lo_close', - 'pg_locreate' => 'pg_lo_create', - 'pg_loexport' => 'pg_lo_export', - 'pg_loimport' => 'pg_lo_import', - 'pg_loopen' => 'pg_lo_open', - 'pg_loread' => 'pg_lo_read', - 'pg_loreadall' => 'pg_lo_read_all', - 'pg_lounlink' => 'pg_lo_unlink', - 'pg_lowrite' => 'pg_lo_write', - 'pg_numfields' => 'pg_num_fields', - 'pg_numrows' => 'pg_num_rows', - 'pg_result' => 'pg_fetch_result', - 'pg_setclientencoding' => 'pg_set_client_encoding' + 'pg_clientencoding' => 'pg_client_encoding', + 'pg_cmdtuples' => 'pg_affected_rows', + 'pg_errormessage' => 'pg_last_error', + 'pg_fieldisnull' => 'pg_field_is_null', + 'pg_fieldname' => 'pg_field_name', + 'pg_fieldnum' => 'pg_field_num', + 'pg_fieldprtlen' => 'pg_field_prtlen', + 'pg_fieldsize' => 'pg_field_size', + 'pg_fieldtype' => 'pg_field_type', + 'pg_freeresult' => 'pg_free_result', + 'pg_getlastoid' => 'pg_last_oid', + 'pg_loclose' => 'pg_lo_close', + 'pg_locreate' => 'pg_lo_create', + 'pg_loexport' => 'pg_lo_export', + 'pg_loimport' => 'pg_lo_import', + 'pg_loopen' => 'pg_lo_open', + 'pg_loread' => 'pg_lo_read', + 'pg_loreadall' => 'pg_lo_read_all', + 'pg_lounlink' => 'pg_lo_unlink', + 'pg_lowrite' => 'pg_lo_write', + 'pg_numfields' => 'pg_num_fields', + 'pg_numrows' => 'pg_num_rows', + 'pg_result' => 'pg_fetch_result', + 'pg_setclientencoding' => 'pg_set_client_encoding', ], ); @@ -319,7 +312,7 @@ new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'l', 'lt'), new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'gte', 'ge'), new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'lte', 'le'), - new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'n', 'ne') + new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'n', 'ne'), ], ); @@ -327,7 +320,7 @@ FuncCallToConstFetchRector::class, [ 'php_sapi_name' => 'PHP_SAPI', - 'pi' => 'M_PI' + 'pi' => 'M_PI', ], ); @@ -416,7 +409,7 @@ NullableCompareToNullRector::class, OptionalParametersAfterRequiredRector::class, OptionalParametersAfterRequiredRector::class, - ParamAnnotationIncorrectNullableRector::class, + // ParamAnnotationIncorrectNullableRector::class, ParamTypeByMethodCallTypeRector::class, ParamTypeByParentCallTypeRector::class, ParamTypeFromStrictTypedPropertyRector::class, @@ -463,9 +456,9 @@ RemoveUnusedNonEmptyArrayBeforeForeachRector::class, RemoveUnusedPrivateClassConstantRector::class, RemoveUnusedPrivateMethodParameterRector::class, - RemoveUnusedPrivateMethodRector::class, + // RemoveUnusedPrivateMethodRector::class, RemoveUnusedPrivatePropertyRector::class, - RemoveUnusedPromotedPropertyRector::class, + // RemoveUnusedPromotedPropertyRector::class, RemoveUnusedVariableAssignRector::class, RemoveUnusedVariableInCatchRector::class, RemoveUselessReturnTagRector::class, diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index a8b5dd0b..0c8c0008 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -4,581 +4,167 @@ namespace Auth0\Laravel\Auth; -use Auth0\Laravel\Auth0; -use Auth0\Laravel\Contract\Auth\Guard as GuardContract; -use Auth0\Laravel\Contract\Entities\Credential; -use Auth0\Laravel\Contract\Exception\GuardException as GuardExceptionContract; -use Auth0\Laravel\Entities\Credential as CredentialConcrete; -use Auth0\Laravel\Event\Stateful\{TokenRefreshFailed, TokenRefreshSucceeded}; -use Auth0\Laravel\Event\Stateless\{TokenVerificationAttempting, TokenVerificationFailed, TokenVerificationSucceeded}; -use Auth0\Laravel\Exception\{AuthenticationException, GuardException}; -use Auth0\Laravel\Model\Stateful\User as StatefulUser; -use Auth0\SDK\Contract\Auth0Interface; -use Auth0\SDK\Exception\InvalidTokenException; -use Auth0\SDK\Token; -use Auth0\SDK\Utility\HttpResponse; -use Exception; -use Illuminate\Auth\Events\{Login, Logout}; -use Illuminate\Contracts\Auth\{Authenticatable, UserProvider}; -use Illuminate\Contracts\Container\BindingResolutionException; -use Illuminate\Contracts\Session\Session; -use Psr\Container\{ContainerExceptionInterface, NotFoundExceptionInterface}; - -use function in_array; -use function is_array; -use function is_int; -use function is_object; -use function is_string; - -final class Guard implements GuardContract +use Auth0\Laravel\Entities\CredentialEntityContract; +use Auth0\Laravel\Guards\{AuthenticationGuard, AuthenticationGuardContract, AuthorizationGuard, AuthorizationGuardContract, GuardAbstract, GuardContract}; +use Illuminate\Contracts\Auth\Authenticatable; + +/** + * @deprecated 7.8.0 Please migrate to using either Auth0\Laravel\Guards\AuthenticationGuard or Auth0\Laravel\Guards\AuthorizationGuard. + * + * @api + */ +final class Guard extends GuardAbstract implements GuardContract { - /** - * @var int - */ - public const SOURCE_IMPERSONATE = 0; // Manually set, presumably through a test case's impersonate() method. - - /** - * @var int - */ - public const SOURCE_SESSION = 2; // Assigned from a session. - - /** - * @var int - */ - public const SOURCE_TOKEN = 1; // Assigned from a decoded token. - private ?Credential $credential = null; - private ?int $credentialSource = null; - private bool $impersonating = false; - private ?UserProvider $provider = null; - private ?string $pushHash = null; - - public function __construct( - private string $name = '', - private ?array $config = null, - ) { - } + private ?AuthenticationGuardContract $authenticator = null; - /** - * Get a credential candidate from an Auth0-PHP SDK session. - * - * @return null|Credential Credential when a valid token is found, null otherwise. - */ - private function findSession(): ?Credential - { - $this->getSession(); - $session = $this->pullState(); - $user = $session?->getUser(); - - if ($session instanceof Credential && $user instanceof Authenticatable) { - $user = $this->getProvider()->retrieveByCredentials($this->normalizeUserArray($user)); - - if ($user instanceof Authenticatable) { - $credential = CredentialConcrete::create( - user: $user, - idToken: $session->getIdToken(), - accessToken: $session->getAccessToken(), - accessTokenScope: $session->getAccessTokenScope(), - accessTokenExpiration: $session->getAccessTokenExpiration(), - refreshToken: $session->getRefreshToken(), - ); - - return $this->refreshSession($credential); - } - } + private ?AuthorizationGuardContract $authorizer = null; - return null; - } + private ?int $credentialSource = null; /** - * Get a credential candidate from a provided access token. - * - * @return null|Credential Credential object if a valid token is found, null otherwise. + * @param null|int $source Credential source in which to search. Defaults to searching all sources. */ - private function findToken(): ?Credential - { - $token = trim(app('request')->bearerToken() ?? ''); + public function find( + ?int $source = null, + ): ?CredentialEntityContract { + $token = null; + $session = null; - if ('' === $token) { - return null; + if ($this->isImpersonating()) { + return $this->getImposter(); } - $user = $this->getProvider()->retrieveByToken('token', $token); - - if ($user instanceof Authenticatable) { - $data = $this->normalizeUserArray($user); - - if ([] !== $data) { - $scope = isset($data['scope']) && is_string($data['scope']) ? explode(' ', $data['scope']) : []; - $exp = isset($data['exp']) && is_numeric($data['exp']) ? (int) $data['exp'] : null; - - return CredentialConcrete::create( - user: $user, - accessToken: $token, - accessTokenScope: $scope, - accessTokenExpiration: $exp, - ); - } + if (null === $source || self::SOURCE_TOKEN === $source) { + $token = $this->getAuthorizationGuard()->findToken(); } - return null; - } - - /** - * Get the Auth0 PHP SDK instance. - * - * @throws BindingResolutionException If the Auth0 class cannot be resolved. - * @throws NotFoundExceptionInterface If the Auth0 service cannot be found. - * @throws ContainerExceptionInterface If the Auth0 service cannot be resolved. - * - * @return Auth0Interface Auth0 PHP SDK instance. - */ - private function getSdk(): Auth0Interface - { - return $this->getService()->getSdk(); - } - - /** - * Get the Auth0 service instance. - * - * @throws BindingResolutionException If the Auth0 class cannot be resolved. - * - * @return Auth0 Auth0 service. - */ - private function getService(): Auth0 - { - return app('auth0'); - } - - /** - * Normalize a user model object for easier storage or comparison. - * - * @param Authenticatable $user User model object. - * - * @throws Exception If the user model object cannot be normalized. - * - * @return array Normalized user model object. - * - * @psalm-suppress TypeDoesNotContainType - * - * @codeCoverageIgnore - */ - private function normalizeUserArray( - Authenticatable $user, - ): array { - $implements = class_implements($user); - $fail = false; - - // @phpstan-ignore-next-line - if (in_array('JsonSerializable', $implements, true) && method_exists($user, 'jsonSerialize')) { - /** @phpstan-ignore-next-line */ - $user = (array) $user->jsonSerialize(); - // @phpstan-ignore-next-line - } elseif (in_array('Illuminate\Contracts\Support\Arrayable', $implements, true) && method_exists($user, 'toArray')) { - /** @phpstan-ignore-next-line */ - $user = (array) $user->toArray(); - // @phpstan-ignore-next-line - } elseif (in_array('Illuminate\Contracts\Support\Jsonable', $implements, true) && method_exists($user, 'toJson')) { - /** @phpstan-ignore-next-line */ - $user = (array) $user->toJson(); - // @phpstan-ignore-next-line - } elseif (method_exists($user, 'attributesToArray')) { - /** @phpstan-ignore-next-line */ - $user = (array) $user->attributesToArray(); - } else { - $fail = true; - } - // @phpstan-ignore-end - - if ($fail) { - throw new GuardException(GuardExceptionContract::USER_MODEL_NORMALIZATION_FAILURE); + if (null === $source && ! $token instanceof CredentialEntityContract || self::SOURCE_SESSION === $source) { + $session = $this->getAuthenticationGuard()->findSession(); } - try { - // @phpstan-ignore-next-line - return json_decode(json_encode($user, JSON_THROW_ON_ERROR), true, 512, JSON_THROW_ON_ERROR); - } catch (\JsonException) { - throw new GuardException(GuardExceptionContract::USER_MODEL_NORMALIZATION_FAILURE); - } + return $token ?? $session ?? null; } - private function pullState(): ?Credential + public function forgetUser(): self { - $sdk = $this->getSdk(); - $sdk->refreshState(); - - $credentials = $sdk->getCredentials(); - - /** @var mixed $credentials */ - if (is_object($credentials) && property_exists($credentials, 'user') && property_exists($credentials, 'idToken') && property_exists($credentials, 'accessToken') && property_exists($credentials, 'accessTokenScope') && property_exists($credentials, 'accessTokenExpiration') && property_exists($credentials, 'refreshToken')) { - return CredentialConcrete::create( - user: new StatefulUser($credentials->user), - idToken: $credentials->idToken, - accessToken: $credentials->accessToken, - accessTokenScope: $credentials->accessTokenScope, - accessTokenExpiration: $credentials->accessTokenExpiration, - refreshToken: $credentials->refreshToken, - ); - } - - return null; - } - - private function pushState( - ?Credential $credential = null, - ): self { - if (self::SOURCE_SESSION !== $this->getCredentialSource()) { - return $this; - } - - $sdk = $this->getSdk(); - $credential ??= $this->getCredential(); - - if (! $credential instanceof Credential) { - $sdk->clear(true); - - return $this; - } - - $pushHash = json_encode($credential); - - // @codeCoverageIgnoreStart - if (! is_string($pushHash)) { - $pushHash = ''; - } - // @codeCoverageIgnoreEnd - - $pushHash = md5($pushHash); - - if ($pushHash === $this->pushHash) { - return $this; - } - - $user = $credential->getUser(); - $idToken = $credential->getIdToken(); - $accessToken = $credential->getAccessToken(); - $accessTokenScope = $credential->getAccessTokenScope(); - $accessTokenExpiration = $credential->getAccessTokenExpiration(); - $refreshToken = $credential->getRefreshToken(); - - if ($user instanceof Authenticatable) { - $sdk->setUser($this->normalizeUserArray($user)); - } - - if (null !== $idToken) { - $sdk->setIdToken($idToken); - } - - if (null !== $accessToken) { - $sdk->setAccessToken($accessToken); - } - - if (null !== $accessTokenScope) { - $sdk->setAccessTokenScope($accessTokenScope); - } - - if (null !== $accessTokenExpiration) { - $sdk->setAccessTokenExpiration($accessTokenExpiration); - } - - if (null !== $refreshToken) { - $sdk->setRefreshToken($refreshToken); - } - - $this->pushHash = $pushHash; + $this->setCredential(); return $this; } - private function refreshSession( - ?Credential $credential, - ): ?Credential { - if (! $credential instanceof Credential || true !== $credential->getAccessTokenExpired()) { - return $credential; + public function getCredential(): ?CredentialEntityContract + { + if ($this->isImpersonating()) { + return $this->getImposter(); } - if (null === $credential->getRefreshToken()) { - return null; - } + $token = null; + $session = null; + $source = $this->getCredentialSource(); - try { - $this->getSdk()->renew(); - $session = $this->pullState(); - } catch (\Throwable) { - event(new TokenRefreshFailed()); - $session = null; + if (null === $source || self::SOURCE_TOKEN === $source) { + $token = $this->getAuthorizationGuard()->getCredential(); } - if ($session instanceof Credential) { - event(new TokenRefreshSucceeded()); - - $user = $this->getProvider()->retrieveByCredentials((array) $session->getUser()); - - if ($user instanceof Authenticatable) { - return CredentialConcrete::create( - user: $user, - idToken: $session->getIdToken(), - accessToken: $session->getAccessToken(), - accessTokenScope: $session->getAccessTokenScope(), - accessTokenExpiration: $session->getAccessTokenExpiration(), - refreshToken: $session->getRefreshToken(), - ); - } + if (null === $source && ! $token instanceof CredentialEntityContract || self::SOURCE_SESSION === $source) { + $session = $this->getAuthenticationGuard()->getCredential(); } - $this->setCredential(null, null); - $this->pushState(); - - return null; + return $token ?? $session ?? null; } - public function authenticate(): Authenticatable - { - if (($user = $this->user()) instanceof Authenticatable) { - return $user; - } - - throw new AuthenticationException(AuthenticationException::UNAUTHENTICATED); - } - - public function check(): bool - { - return $this->hasUser(); - } - - public function find( - int $source, - ): ?Credential { - if ($this->impersonating) { - return $this->getCredential(); - } - - if (self::SOURCE_TOKEN === $source) { - $candidate = $this->findToken(); + /** + * Sets the currently authenticated user for the guard. + * + * @param null|CredentialEntityContract $credential Optional. The credential to use. + * @param null|int $source Optional. The source context in which to assign the user. Defaults to all sources. + */ + public function login( + ?CredentialEntityContract $credential, + ?int $source = null, + ): GuardContract { + $this->stopImpersonating(); - if ($candidate instanceof Credential) { - return $candidate; - } + if (null === $source || self::SOURCE_TOKEN === $source) { + $this->getAuthorizationGuard()->login($credential); } - if (self::SOURCE_SESSION === $source) { - $candidate = $this->findSession(); - - if ($candidate instanceof Credential) { - return $candidate; - } + if (null === $source || self::SOURCE_SESSION === $source) { + $this->getAuthenticationGuard()->login($credential); } - return null; - } - - public function forgetUser(): self - { - $this->setCredential(); + $this->credentialSource = $source; return $this; } - public function getCredential(): ?Credential - { - if (! $this->impersonating && self::SOURCE_SESSION === $this->getCredentialSource() && $this->credential instanceof Credential) { - $updated = $this->findSession(); - $source = $updated instanceof Credential ? self::SOURCE_SESSION : null; - $this->setCredential($updated, $source); - $this->pushState($updated); - } - - return $this->credential; - } - - public function getCredentialSource(): ?int - { - return $this->credentialSource; - } - - public function getName(): string + public function logout(): GuardContract { - return $this->name; - } - - public function getProvider(): UserProvider - { - if ($this->provider instanceof UserProvider) { - return $this->provider; - } - - $providerName = $this->config['provider'] ?? ''; - - if (! is_string($providerName) || '' === $providerName) { - // @codeCoverageIgnoreStart - throw new GuardException(GuardExceptionContract::USER_PROVIDER_UNCONFIGURED); - // @codeCoverageIgnoreEnd - } + if ($this->isImpersonating()) { + $this->stopImpersonating(); - $providerName = trim($providerName); - $provider = app('auth')->createUserProvider($providerName); - - if ($provider instanceof UserProvider) { - $this->provider = $provider; - - return $provider; + return $this; } - // @codeCoverageIgnoreStart - throw new GuardException(sprintf(GuardExceptionContract::USER_PROVIDER_UNAVAILABLE, $providerName)); - // @codeCoverageIgnoreEnd - } + $source = $this->getCredentialSource(); - public function getSession(): Session - { - $store = app('session.store'); - $request = app('request'); - - if (! $request->hasSession(true)) { - $request->setLaravelSession($store); + if (null === $source || self::SOURCE_TOKEN === $source) { + $this->getAuthorizationGuard()->logout(); } - if (! $store->isStarted()) { - $store->start(); + if (null === $source || self::SOURCE_SESSION === $source) { + $this->getAuthenticationGuard()->logout(); } - return $store; + return $this; } - public function guest(): bool + public function refreshUser(): void { - return ! $this->check(); - } - - public function hasScope( - string $scope, - Credential $credential, - ): bool { - if ('*' === $scope) { - return true; + if ($this->isImpersonating()) { + return; } - $available = $credential->getAccessTokenScope(); + $source = $this->getCredentialSource(); - if (is_array($available) && [] !== $available) { - return in_array($scope, $available, true); + if (null === $source || self::SOURCE_TOKEN === $source) { + $this->getAuthorizationGuard()->refreshUser(); } - return false; - } - - public function hasUser(): bool - { - return $this->getCredential()?->getUser() instanceof Authenticatable; - } - - public function id(): int | string | null - { - $user = $this->user()?->getAuthIdentifier(); - - if (is_string($user) || is_int($user)) { - return $user; + if (null === $source || self::SOURCE_SESSION === $source) { + $this->getAuthenticationGuard()->refreshUser(); } - - return null; } - public function login( - ?Credential $credential, + public function setCredential( + ?CredentialEntityContract $credential = null, ?int $source = null, - ): self { - $this->setCredential($credential, $source); - $this->pushState($credential); - $user = $credential?->getUser(); - - if ($credential instanceof Credential && $user instanceof Authenticatable) { - event(new Login(self::class, $user, true)); - } - - return $this; - } + ): GuardContract { + $this->stopImpersonating(); - public function logout(): self - { - $this->impersonating = false; - $user = $this->user(); - - if ($user instanceof Authenticatable) { - event(new Logout(self::class, $user)); - } - - $this->setCredential(null, $this->getCredentialSource()); - $this->pushState(); - $this->forgetUser(); - - return $this; - } - - public function processToken( - string $token, - ): ?array { - $event = new TokenVerificationAttempting($token); - event($event); - $token = $event->getToken(); - - try { - $data = $this->getSdk()->decode(token: $token, tokenType: Token::TYPE_ACCESS_TOKEN)->toArray(); - event(new TokenVerificationSucceeded($token, $data)); - - return $data; - } catch (InvalidTokenException $invalidTokenException) { - event(new TokenVerificationFailed($token, $invalidTokenException)); - - return null; + if (null === $source || self::SOURCE_TOKEN === $source) { + $this->getAuthorizationGuard()->setCredential($credential); } - } - - public function refreshUser(): void - { - if ($this->check()) { - $credential = $this->getCredential(); - $accessToken = $credential?->getAccessToken(); - - if (! $credential instanceof \Auth0\Laravel\Contract\Entities\Credential || null === $accessToken) { - return; - } - - $response = $this->getSdk()->authentication()->userInfo($accessToken); - - if (HttpResponse::wasSuccessful($response)) { - $response = HttpResponse::decodeContent($response); - - if (! is_array($response)) { - return; - } - $user = $this->getProvider()->retrieveByCredentials($response); - - $this->pushState(CredentialConcrete::create( - user: $user, - idToken: $credential->getIdToken(), - accessToken: $credential->getAccessToken(), - accessTokenScope: $credential->getAccessTokenScope(), - accessTokenExpiration: $credential->getAccessTokenExpiration(), - refreshToken: $credential->getRefreshToken(), - )); - } + if (null === $source || self::SOURCE_SESSION === $source) { + $this->getAuthenticationGuard()->setCredential($credential); } - } - public function setCredential( - ?Credential $credential = null, - ?int $source = null, - ): self { - $this->credential = $credential; $this->credentialSource = $source; return $this; } + /** + * @param CredentialEntityContract $credential + * @param ?int $source + */ public function setImpersonating( - bool $impersonate = false, + CredentialEntityContract $credential, + ?int $source = null, ): self { - $this->impersonating = $impersonate; + $this->impersonationSource = $source; + $this->impersonating = $credential; return $this; } @@ -586,59 +172,70 @@ public function setImpersonating( public function setUser( Authenticatable $user, ): void { - $credential = $this->getCredential() ?? CredentialConcrete::create(); - $credential->setUser($user); + if ($this->isImpersonating()) { + if ($this->getImposter()?->getUser() === $user) { + return; + } + + $this->stopImpersonating(); + } + + $source = $this->getCredentialSource(); - $this->setCredential($credential); - $this->pushState($credential); + if (null === $source || self::SOURCE_TOKEN === $source) { + $this->getAuthorizationGuard()->setUser($user); + } + + if (null === $source || self::SOURCE_SESSION === $source) { + $this->getAuthenticationGuard()->setUser($user); + } } - /** - * @codeCoverageIgnore - */ public function user(): ?Authenticatable { - $legacyBehavior = config('auth0.behavior.legacyGuardUserMethod', true); - $currentUser = $this->getCredential()?->getUser(); - - if ($currentUser instanceof Authenticatable) { - return $currentUser; + if ($this->isImpersonating()) { + return $this->getImposter()?->getUser(); } - if (true === $legacyBehavior) { - $token = $this->find(self::SOURCE_TOKEN); + $credential = $this->getCredential(); - if ($token instanceof Credential) { - $this->login($token, self::SOURCE_TOKEN); + if ($credential instanceof CredentialEntityContract) { + return $credential->getUser(); + } - return $this->getCredential()?->getUser(); - } + // $source = $this->getCredentialSource(); + // $token = null; + // $session = null; - $session = $this->find(self::SOURCE_SESSION); + // if (null === $source || self::SOURCE_TOKEN === $source) { + // $token = $this->getAuthorizationGuard()->user(); + // } - if ($session instanceof Credential) { - $this->login($session, self::SOURCE_SESSION); + // if (null === $source || self::SOURCE_SESSION === $source) { + // $session = $this->getAuthenticationGuard()->user(); + // } - return $this->getCredential()?->getUser(); - } - } + // return $token ?? $session ?? null; return null; } - /** - * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter - * - * @param array $credentials - */ - public function validate( - array $credentials = [], - ): bool { - return false; + private function getAuthenticationGuard(): AuthenticationGuardContract + { + $this->sdk(); + + return $this->authenticator ??= new AuthenticationGuard(name: $this->name, config: $this->config, sdk: $this->sdk); + } + + private function getAuthorizationGuard(): AuthorizationGuardContract + { + $this->sdk(); + + return $this->authorizer ??= new AuthorizationGuard(name: $this->name, config: $this->config, sdk: $this->sdk); } - public function viaRemember(): bool + private function getCredentialSource(): ?int { - return false; + return $this->credentialSource; } } diff --git a/src/Auth0.php b/src/Auth0.php index 310bb6ed..c6db0b32 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -4,265 +4,18 @@ namespace Auth0\Laravel; -use Auth0\Laravel\Cache\LaravelCachePool; -use Auth0\Laravel\Contract\Auth0 as ServiceContract; -use Auth0\Laravel\Event\Configuration\{Building, Built}; -use Auth0\Laravel\Store\LaravelSession; -use Auth0\SDK\Auth0 as SDK; -use Auth0\SDK\Configuration\SdkConfiguration as Configuration; -use Auth0\SDK\Contract\API\ManagementInterface; -use Auth0\SDK\Contract\{Auth0Interface as SDKContract, StoreInterface}; -use Auth0\SDK\Utility\HttpTelemetry; -use Psr\Cache\CacheItemPoolInterface; - -use function in_array; -use function is_string; +use Auth0\Laravel\Entities\InstanceEntityTrait; /** - * Service that provides access to the Auth0 SDK. + * Auth0 Laravel SDK service provider. Provides access to the SDK's methods. + * + * @codeCoverageIgnore + * + * @deprecated 7.8.0 Use Auth0\Laravel\Service instead. + * + * @api */ -final class Auth0 implements ServiceContract +final class Auth0 extends ServiceAbstract implements ServiceContract { - /** - * The Laravel-Auth0 SDK version:. - * - * @var string - */ - public const VERSION = '7.7.0'; - - public function __construct( - private ?SDKContract $sdk = null, - private ?Configuration $configuration = null, - private ?CacheItemPoolInterface $tokenCachePool = null, - private ?CacheItemPoolInterface $managementTokenCachePool = null, - ) { - } - - private function bootManagementTokenCache(array $config): array - { - $managementTokenCache = $config['managementTokenCache'] ?? null; - - if (false === $managementTokenCache) { - unset($config['managementTokenCache']); - - return $config; - } - - if (null === $managementTokenCache) { - $managementTokenCache = $this->getManagementTokenCachePool(); - } - - if (is_string($managementTokenCache)) { - $managementTokenCache = app(trim($managementTokenCache)); - } - - $config['managementTokenCache'] = $managementTokenCache instanceof CacheItemPoolInterface ? $managementTokenCache : null; - - return $config; - } - - private function bootSessionStorage(array $config): array - { - $sessionStorage = $config['sessionStorage'] ?? null; - $sessionStorageId = $config['sessionStorageId'] ?? 'auth0_session'; - - if (false === $sessionStorage) { - unset($config['sessionStorage']); - - return $config; - } - - if (null === $sessionStorage) { - $sessionStorage = app(LaravelSession::class, [ - 'prefix' => $sessionStorageId, - ]); - } - - if (is_string($sessionStorage)) { - $sessionStorage = app(trim($sessionStorage), [ - 'prefix' => $sessionStorageId, - ]); - } - - $config['sessionStorage'] = $sessionStorage instanceof StoreInterface ? $sessionStorage : null; - - return $config; - } - - private function bootStrategy(array $config): array - { - $strategy = $config['strategy'] ?? Configuration::STRATEGY_REGULAR; - - if (! is_string($strategy)) { - $strategy = Configuration::STRATEGY_REGULAR; - } - - $config['strategy'] = $strategy; - - return $config; - } - - private function bootTokenCache(array $config): array - { - $tokenCache = $config['tokenCache'] ?? null; - - if (false === $tokenCache) { - unset($config['tokenCache']); - - return $config; - } - - if (null === $tokenCache) { - $tokenCache = $this->getTokenCachePool(); - } - - if (is_string($tokenCache)) { - $tokenCache = app(trim($tokenCache)); - } - - $config['tokenCache'] = $tokenCache instanceof CacheItemPoolInterface ? $tokenCache : null; - - return $config; - } - - private function bootTransientStorage(array $config): array - { - $transientStorage = $config['transientStorage'] ?? null; - $transientStorageId = $config['transientStorageId'] ?? 'auth0_transient'; - - if (false === $transientStorage) { - unset($config['transientStorage']); - - return $config; - } - - if (null === $transientStorage) { - $transientStorage = app(LaravelSession::class, [ - 'prefix' => $transientStorageId, - ]); - } - - if (is_string($transientStorage)) { - $transientStorage = app(trim($transientStorage), [ - 'prefix' => $transientStorageId, - ]); - } - - $config['transientStorage'] = $transientStorage instanceof StoreInterface ? $transientStorage : null; - - return $config; - } - - private function getManagementTokenCachePool(): CacheItemPoolInterface - { - if (! $this->managementTokenCachePool instanceof CacheItemPoolInterface) { - $this->managementTokenCachePool = app(LaravelCachePool::class); - } - - return $this->managementTokenCachePool; - } - - private function getTokenCachePool(): CacheItemPoolInterface - { - if (! $this->tokenCachePool instanceof CacheItemPoolInterface) { - $this->tokenCachePool = app(LaravelCachePool::class); - } - - return $this->tokenCachePool; - } - - /** - * Updates the Auth0 PHP SDK's telemetry to include the correct Laravel markers. - */ - private function setSdkTelemetry(): self - { - HttpTelemetry::setEnvProperty('Laravel', app()->version()); - HttpTelemetry::setPackage('laravel-auth0', self::VERSION); - - return $this; - } - - public function getConfiguration(): Configuration - { - if (! $this->configuration instanceof Configuration) { - $config = config('auth0'); - - /** - * @var array $config - */ - - // Give host application an opportunity to update the configuration before assigning defaults. - $event = new Building($config); - event($event); - $config = $event->getConfiguration(); - - $config = $this->bootStrategy($config); - $config = $this->bootTokenCache($config); - $config = $this->bootManagementTokenCache($config); - - if (in_array($config['strategy'], Configuration::STRATEGIES_USING_SESSIONS, true)) { - $config = $this->bootSessionStorage($config); - $config = $this->bootTransientStorage($config); - } - - $config = new Configuration($config); - - // Give host application an opportunity to update the configuration before applying it. - $event = new Built($config); - event($event); - $this->configuration = $event->getConfiguration(); - } - - return $this->configuration; - } - - public function getCredentials(): ?object - { - return $this->getSdk()->getCredentials(); - } - - public function getSdk(): SDKContract - { - if (! $this->sdk instanceof SDKContract) { - return $this->setSdk(new SDK($this->getConfiguration())); - } - - return $this->sdk; - } - - public function management(): ManagementInterface - { - return $this->getSdk()->management(); - } - - public function reset(): self - { - unset($this->sdk, $this->configuration); - - $this->sdk = null; - $this->configuration = null; - - return $this; - } - - public function setConfiguration(Configuration $configuration): self - { - $this->configuration = $configuration; - - if ($this->sdk instanceof SDKContract) { - $this->sdk->setConfiguration($configuration); - } - - return $this; - } - - public function setSdk(SDKContract $sdk): SDKContract - { - $this->configuration = $sdk->configuration(); - $this->sdk = $sdk; - - $this->setSdkTelemetry(); - - return $this->sdk; - } + use InstanceEntityTrait; } diff --git a/src/Bridges/BridgeAbstract.php b/src/Bridges/BridgeAbstract.php new file mode 100644 index 00000000..d351f4ba --- /dev/null +++ b/src/Bridges/BridgeAbstract.php @@ -0,0 +1,14 @@ + */ - private array $deferred = []; + protected array $deferred = []; - private function createItem(string $key, mixed $value): CacheItemInterface - { - if (! is_string($value)) { - return LaravelCacheItem::miss($key); - } - - $value = unserialize($value); - - if (false === $value) { - return LaravelCacheItem::miss($key); - } - - return new LaravelCacheItem($key, $value, true); - } - - /** - * @param string $key the key for which to return the corresponding Cache Item - * - * @codeCoverageIgnore - */ - private function getDeferred(string $key): ?CacheItemInterface - { - if (! isset($this->deferred[$key])) { - return null; - } - - $deferred = $this->deferred[$key]; - $item = clone $deferred['item']; - $expires = $deferred['expiration']; - - if ($expires instanceof DateTimeInterface) { - $expires = $expires->getTimestamp(); - } - - if (null !== $expires && $expires <= time()) { - unset($this->deferred[$key]); - - return null; - } - - return $item; - } - - private function getStore(): Store - { - return app(CacheManager::class)->getStore(); - } - - public function clear(): bool + final public function clear(): bool { $this->deferred = []; - return $this->getStore() - ->flush(); + return $this->getCache()->flush(); } - public function commit(): bool + final public function commit(): bool { $success = true; @@ -100,13 +52,12 @@ public function commit(): bool /** * @param string $key the key for which to return the corresponding Cache Item */ - public function deleteItem(string $key): bool + final public function deleteItem(string $key): bool { - return $this->getStore() - ->forget($key); + return $this->getCache()->forget($key); } - public function deleteItems(array $keys): bool + final public function deleteItems(array $keys): bool { $deleted = true; @@ -119,13 +70,12 @@ public function deleteItems(array $keys): bool return $deleted; } - public function getItem(string $key): CacheItemInterface + final public function getItem(string $key): CacheItemInterface { - $value = $this->getStore() - ->get($key); + $value = $this->getCache()->get($key); if (false === $value) { - return LaravelCacheItem::miss($key); + return CacheItemBridge::miss($key); } return $this->createItem($key, $value); @@ -136,18 +86,17 @@ public function getItem(string $key): CacheItemInterface * * @return CacheItemInterface[] */ - public function getItems(array $keys = []): iterable + final public function getItems(array $keys = []): iterable { if ([] === $keys) { return []; } - $results = $this->getStore() - ->many($keys); + $results = $this->getCache()->many($keys); $items = []; foreach ($results as $key => $value) { - $key = (string) $key; + $key = (string) $key; $items[$key] = $this->createItem($key, $value); } @@ -157,20 +106,20 @@ public function getItems(array $keys = []): iterable /** * @param string $key the key for which to return the corresponding Cache Item */ - public function hasItem(string $key): bool + final public function hasItem(string $key): bool { return $this->getItem($key) ->isHit(); } - public function save(CacheItemInterface $item): bool + final public function save(CacheItemInterface $item): bool { - if (! $item instanceof LaravelCacheItem) { + if (! $item instanceof CacheItemBridge) { return false; } - $value = serialize($item->get()); - $key = $item->getKey(); + $value = serialize($item->get()); + $key = $item->getKey(); $expires = $item->getExpiration(); if ($expires->getTimestamp() <= time()) { @@ -179,20 +128,76 @@ public function save(CacheItemInterface $item): bool $ttl = $expires->getTimestamp() - time(); - return $this->getStore()->put($key, $value, $ttl); + return $this->getCache()->put($key, $value, $ttl); } - public function saveDeferred(CacheItemInterface $item): bool + final public function saveDeferred(CacheItemInterface $item): bool { - if (! $item instanceof LaravelCacheItem) { + if (! $item instanceof CacheItemBridge) { return false; } $this->deferred[$item->getKey()] = [ - 'item' => $item, + 'item' => $item, 'expiration' => $item->getExpiration(), ]; return true; } + + protected function createItem(string $key, mixed $value): CacheItemInterface + { + if (! is_string($value)) { + return CacheItemBridge::miss($key); + } + + $value = unserialize($value); + + if (false === $value) { + return CacheItemBridge::miss($key); + } + + return new CacheItemBridge($key, $value, true); + } + + protected function getCache(): Store + { + $cache = cache(); + + // @codeCoverageIgnoreStart + if (! $cache instanceof CacheManager) { + throw new RuntimeException('Cache store is not an instance of Illuminate\Contracts\Cache\CacheManager'); + } + // @codeCoverageIgnoreEnd + + return $cache->getStore(); + } + + /** + * @param string $key the key for which to return the corresponding Cache Item + * + * @codeCoverageIgnore + */ + protected function getDeferred(string $key): ?CacheItemInterface + { + if (! isset($this->deferred[$key])) { + return null; + } + + $deferred = $this->deferred[$key]; + $item = clone $deferred['item']; + $expires = $deferred['expiration']; + + if ($expires instanceof DateTimeInterface) { + $expires = $expires->getTimestamp(); + } + + if (null !== $expires && $expires <= time()) { + unset($this->deferred[$key]); + + return null; + } + + return $item; + } } diff --git a/src/Bridges/CacheBridgeContract.php b/src/Bridges/CacheBridgeContract.php new file mode 100644 index 00000000..5b058a9f --- /dev/null +++ b/src/Bridges/CacheBridgeContract.php @@ -0,0 +1,14 @@ +expiration = match (true) { + null === $time => new DateTimeImmutable('now +1 year'), + is_int($time) => new DateTimeImmutable('now +' . (string) $time . ' seconds'), + $time instanceof DateInterval => (new DateTimeImmutable())->add($time), + }; + + return $this; + } + + public function expiresAt(?DateTimeInterface $expiration): static + { + $this->expiration = $expiration ?? new DateTimeImmutable('now +1 year'); + + return $this; + } + + public function set(mixed $value): static + { + $this->value = $value; + + return $this; + } + + public static function miss(string $key): self + { + return new self( + key: $key, + value: null, + hit: false, + ); + } +} diff --git a/src/Bridges/CacheItemBridgeAbstract.php b/src/Bridges/CacheItemBridgeAbstract.php new file mode 100644 index 00000000..281fab0e --- /dev/null +++ b/src/Bridges/CacheItemBridgeAbstract.php @@ -0,0 +1,60 @@ +isHit() ? $this->value : null; + } + + /** + * Returns the expiration timestamp. + */ + final public function getExpiration(): DateTimeInterface + { + return $this->expiration ?? new DateTimeImmutable('now +1 year'); + } + + final public function getKey(): string + { + return $this->key; + } + + /** + * Returns the raw value, regardless of hit status. + */ + final public function getRawValue(): mixed + { + return $this->value; + } + + final public function isHit(): bool + { + return $this->hit; + } + + abstract public function expiresAfter(int | DateInterval | null $time): static; + + abstract public function expiresAt(?DateTimeInterface $expiration): static; + + abstract public function set(mixed $value): static; +} diff --git a/src/Bridges/CacheItemBridgeContract.php b/src/Bridges/CacheItemBridgeContract.php new file mode 100644 index 00000000..d2f26577 --- /dev/null +++ b/src/Bridges/CacheItemBridgeContract.php @@ -0,0 +1,20 @@ +setPrefix($prefix); } - /** - * Prefixes a key with the SDK's configured namespace. - * - * @param string $key - */ - private function getPrefixedKey(string $key): string - { - return $this->getPrefix() . '_' . trim($key); - } - - /** - * Retrieves the Laravel session store. - * - * @throws SessionException If a Laravel session store is not available. - * - * @psalm-suppress RedundantConditionGivenDocblockType - */ - private function getStore(): Store - { - $store = app('session.store'); - - if (! request()->hasSession(true)) { - request()->setLaravelSession($store); - } - - if (! $store->isStarted()) { - $store->start(); - } - - return $store; - } - /** * This method is required by the interface but is not used by this SDK. * * @param bool $deferring whether to defer persisting the storage state */ - public function defer(bool $deferring): void + final public function defer(bool $deferring): void { } @@ -71,7 +35,7 @@ public function defer(bool $deferring): void * * @throws SessionException If a Laravel session store is not available. */ - public function delete(string $key): void + final public function delete(string $key): void { $this->getStore()->forget($this->getPrefixedKey($key)); } @@ -84,7 +48,7 @@ public function delete(string $key): void * * @throws SessionException If a Laravel session store is not available. */ - public function get(string $key, $default = null) + final public function get(string $key, $default = null): mixed { return $this->getStore()->get($this->getPrefixedKey($key), $default); } @@ -94,10 +58,10 @@ public function get(string $key, $default = null) * * @throws SessionException If a Laravel session store is not available. */ - public function getAll(): array + final public function getAll(): array { - $pairs = $this->getStore()->all(); - $prefix = $this->prefix . '_'; + $pairs = $this->getStore()->all(); + $prefix = $this->prefix . '_'; $response = []; foreach (array_keys($pairs) as $key) { @@ -114,7 +78,7 @@ public function getAll(): array * * @return string Prefix used for all session keys. */ - public function getPrefix(): string + final public function getPrefix(): string { return $this->prefix; } @@ -124,7 +88,7 @@ public function getPrefix(): string * * @throws SessionException If a Laravel session store is not available. */ - public function purge(): void + final public function purge(): void { $entities = $this->getAll(); @@ -141,7 +105,7 @@ public function purge(): void * * @throws SessionException If a Laravel session store is not available. */ - public function set(string $key, $value): void + final public function set(string $key, $value): void { $this->getStore()->put($this->getPrefixedKey($key), $value); } @@ -153,7 +117,7 @@ public function set(string $key, $value): void * * @return $this */ - public function setPrefix( + final public function setPrefix( string $prefix = 'auth0', ): self { $prefix = trim($prefix); @@ -166,4 +130,37 @@ public function setPrefix( return $this; } + + /** + * Prefixes a key with the SDK's configured namespace. + * + * @param string $key + */ + protected function getPrefixedKey(string $key): string + { + return $this->getPrefix() . '_' . trim($key); + } + + /** + * Retrieves the Laravel session store. + * + * @throws SessionException If a Laravel session store is not available. + * + * @psalm-suppress RedundantConditionGivenDocblockType + */ + protected function getStore(): Store + { + $store = app('session.store'); + $request = app('request'); + + if (! $request->hasSession(true)) { + $request->setLaravelSession($store); + } + + if (! $store->isStarted()) { + $store->start(); + } + + return $store; + } } diff --git a/src/Bridges/SessionBridgeContract.php b/src/Bridges/SessionBridgeContract.php new file mode 100644 index 00000000..9d9c52af --- /dev/null +++ b/src/Bridges/SessionBridgeContract.php @@ -0,0 +1,14 @@ +expiration = match (true) { - null === $time => new DateTimeImmutable('now +1 year'), - is_int($time) => new DateTimeImmutable('now +' . (string) $time . ' seconds'), - $time instanceof DateInterval => (new DateTimeImmutable())->add($time), - }; - - return $this; - } - - public function expiresAt(?DateTimeInterface $expiration): static - { - $this->expiration = $expiration ?? new DateTimeImmutable('now +1 year'); - - return $this; - } - - public function get(): mixed - { - return $this->isHit() ? $this->value : null; - } - - /** - * Returns the expiration timestamp. - */ - public function getExpiration(): DateTimeInterface - { - return $this->expiration ?? new DateTime('now +1 year'); - } - - public function getKey(): string - { - return $this->key; - } - - /** - * Returns the raw value, regardless of hit status. - */ - public function getRawValue(): mixed - { - return $this->value; - } - - public function isHit(): bool - { - return $this->hit; - } - - public function set(mixed $value): static - { - $this->value = $value; - - return $this; - } - - /** - * Return a LaravelCacheItem instance flagged as missed. - * - * @param string $key - */ - public static function miss(string $key): self - { - return new self( - key: $key, - value: null, - hit: false, - ); - } -} diff --git a/src/Configuration.php b/src/Configuration.php index ccc8fbbd..9814a4f2 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -4,18 +4,463 @@ namespace Auth0\Laravel; -use Auth0\Laravel\Contract\Configuration as ConfigurationContract; +use Illuminate\Support\{Arr, Str}; +use function constant; use function count; +use function defined; +use function in_array; +use function is_array; +use function is_bool; +use function is_int; use function is_string; /** * Helpers to map configuration data stored as strings from .env files into formats consumable by the Auth0-PHP SDK. + * + * @api */ final class Configuration implements ConfigurationContract { - public static function stringToArray(?string $config, string $delimiter = ' '): array + /** + * @var string[] + */ + private const USES_ARRAYS = [ + self::CONFIG_AUDIENCE, + self::CONFIG_SCOPE, + self::CONFIG_ORGANIZATION, + ]; + + /** + * @var string[] + */ + private const USES_BOOLEANS = [ + self::CONFIG_USE_PKCE, + self::CONFIG_HTTP_TELEMETRY, + self::CONFIG_COOKIE_SECURE, + self::CONFIG_PUSHED_AUTHORIZATION_REQUEST, + ]; + + /** + * @var string[] + */ + private const USES_INTEGERS = [ + self::CONFIG_TOKEN_MAX_AGE, + self::CONFIG_TOKEN_LEEWAY, + self::CONFIG_TOKEN_CACHE_TTL, + self::CONFIG_HTTP_MAX_RETRIES, + self::CONFIG_COOKIE_EXPIRES, + ]; + + /** + * @var string + */ + public const CONFIG_AUDIENCE = 'audience'; + + /** + * @var string + */ + public const CONFIG_CLIENT_ASSERTION_SIGNING_ALGORITHM = 'clientAssertionSigningAlgorithm'; + + /** + * @var string + */ + public const CONFIG_CLIENT_ASSERTION_SIGNING_KEY = 'clientAssertionSigningKey'; + + /** + * @var string + */ + public const CONFIG_CLIENT_ID = 'clientId'; + + /** + * @var string + */ + public const CONFIG_CLIENT_SECRET = 'clientSecret'; + + /** + * @var string + */ + public const CONFIG_COOKIE_DOMAIN = 'cookieDomain'; + + /** + * @var string + */ + public const CONFIG_COOKIE_EXPIRES = 'cookieExpires'; + + /** + * @var string + */ + public const CONFIG_COOKIE_PATH = 'cookiePath'; + + /** + * @var string + */ + public const CONFIG_COOKIE_SAME_SITE = 'cookieSameSite'; + + /** + * @var string + */ + public const CONFIG_COOKIE_SECRET = 'cookieSecret'; + + /** + * @var string + */ + public const CONFIG_COOKIE_SECURE = 'cookieSecure'; + + /** + * @var string + */ + public const CONFIG_CUSTOM_DOMAIN = 'customDomain'; + + /** + * @var string + */ + public const CONFIG_DOMAIN = 'domain'; + + /** + * @var string + */ + public const CONFIG_HTTP_MAX_RETRIES = 'httpMaxRetries'; + + /** + * @var string + */ + public const CONFIG_HTTP_TELEMETRY = 'httpTelemetry'; + + /** + * @var string + */ + public const CONFIG_MANAGEMENT_TOKEN = 'managementToken'; + + /** + * @var string + */ + public const CONFIG_MANAGEMENT_TOKEN_CACHE = 'managementTokenCache'; + + /** + * @var string + */ + public const CONFIG_ORGANIZATION = 'organization'; + + /** + * @var string + */ + public const CONFIG_PUSHED_AUTHORIZATION_REQUEST = 'pushedAuthorizationRequest'; + + /** + * @var string + */ + public const CONFIG_REDIRECT_URI = 'redirectUri'; + + /** + * @var string + */ + public const CONFIG_RESPONSE_MODE = 'responseMode'; + + /** + * @var string + */ + public const CONFIG_RESPONSE_TYPE = 'responseType'; + + /** + * @var string + */ + public const CONFIG_SCOPE = 'scope'; + + /** + * @var string + */ + public const CONFIG_SESSION_STORAGE = 'sessionStorage'; + + /** + * @var string + */ + public const CONFIG_SESSION_STORAGE_ID = 'sessionStorageId'; + + /** + * @var string + */ + public const CONFIG_STRATEGY = 'strategy'; + + /** + * @var string + */ + public const CONFIG_TOKEN_ALGORITHM = 'tokenAlgorithm'; + + /** + * @var string + */ + public const CONFIG_TOKEN_CACHE = 'tokenCache'; + + /** + * @var string + */ + public const CONFIG_TOKEN_CACHE_TTL = 'tokenCacheTtl'; + + /** + * @var string + */ + public const CONFIG_TOKEN_JWKS_URI = 'tokenJwksUri'; + + /** + * @var string + */ + public const CONFIG_TOKEN_LEEWAY = 'tokenLeeway'; + + /** + * @var string + */ + public const CONFIG_TOKEN_MAX_AGE = 'tokenMaxAge'; + + /** + * @var string + */ + public const CONFIG_TRANSIENT_STORAGE = 'transientStorage'; + + /** + * @var string + */ + public const CONFIG_TRANSIENT_STORAGE_ID = 'transientStorageId'; + + /** + * @var string + */ + public const CONFIG_USE_PKCE = 'usePkce'; + + /** + * @var array + */ + public const VERSION_2 = ['AUTH0_CONFIG_VERSION' => 2]; + + private static ?array $environment = null; + + private static ?array $json = null; + + private static ?string $path = null; + + public static function get( + string $setting, + array | string | int | bool | null $default = null, + ): array | string | int | bool | null { + if (in_array($setting, self::USES_ARRAYS, true)) { + $value = self::getValue($setting, $default); + + if (! is_string($value)) { + return $default; + } + + return self::stringToArrayOrNull($value, ',') ?? $default; + } + + if (in_array($setting, self::USES_BOOLEANS, true)) { + $value = self::getValue($setting, $default); + + if (! is_bool($value) && ! is_string($value)) { + return $default; + } + + return self::stringToBoolOrNull($value) ?? $default; + } + + if (in_array($setting, self::USES_INTEGERS, true)) { + $value = self::getValue($setting, $default); + + if (! is_int($value) && ! is_string($value)) { + return $default; + } + + return self::stringOrIntToIntOrNull($value) ?? $default; + } + + $result = null; + $value = self::getValue($setting) ?? $default; + + if (is_string($value) || is_int($value) || null === $value) { + $result = self::stringOrNull($value) ?? $default; + } + + if (self::CONFIG_DOMAIN === $setting && null === $result) { + // Fallback to extracting the tenant domain from the signing key subject. + $temp = self::getJson()['signing_keys.0.subject'] ?? ''; + $temp = explode('=', $temp); + + if (isset($temp[1]) && str_ends_with($temp[1], '.auth0.com')) { + $result = $temp[1]; // @codeCoverageIgnore + } + } + + return $result ?? $default; + } + + /** + * @codeCoverageIgnore + */ + public static function getEnvironment(): array + { + if (null === self::$environment) { + $path = self::getPath(); + $laravelEnvironment = env('APP_ENV'); + $laravelEnvironment = is_string($laravelEnvironment) && '' !== trim($laravelEnvironment) ? trim($laravelEnvironment) : 'local'; + + $env = []; + $files = ['.env', '.env.auth0']; + $files[] = '.env.' . $laravelEnvironment; + $files[] = '.env.auth0.' . $laravelEnvironment; + + foreach ($files as $file) { + if (! file_exists($path . $file)) { + continue; + } + + $contents = file($path . $file, FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES); + + if (! is_array($contents)) { + continue; + } + + if ([] === $contents) { + continue; + } + + foreach ($contents as $content) { + [$k,$v] = explode('=', $content); + $v = trim($v); + + if ('' === $v) { + $v = null; + } elseif ('empty' === $v) { + $v = null; + } elseif ('(empty)' === $v) { + $v = null; + } elseif ('null' === $v) { + $v = null; + } elseif ('(null)' === $v) { + $v = null; + } elseif ('true' === $v) { + $v = true; + } elseif ('(true)' === $v) { + $v = true; + } elseif ('false' === $v) { + $v = false; + } elseif ('(false)' === $v) { + $v = false; + } + + $env[trim($k)] = $v; + } + } + + self::$environment = $env; + } + + return self::$environment; + } + + /** + * @codeCoverageIgnore + */ + public static function getJson(): array { + if (null === self::$json) { + $path = self::getPath(); + $laravelEnvironment = env('APP_ENV'); + $laravelEnvironment = is_string($laravelEnvironment) && '' !== trim($laravelEnvironment) ? trim($laravelEnvironment) : 'local'; + + $configuration = []; + $files = ['.auth0.json', '.auth0.api.json', '.auth0.app.json']; + $files[] = '.auth0.' . $laravelEnvironment . '.json'; + $files[] = '.auth0.' . $laravelEnvironment . '.api.json'; + $files[] = '.auth0.' . $laravelEnvironment . '.app.json'; + + foreach ($files as $file) { + if (file_exists($path . $file)) { + $content = file_get_contents($path . $file); + + if (is_string($content)) { + $json = json_decode($content, true, 512); + + if (is_array($json)) { + $configuration = array_merge($configuration, $json); + } + } + } + } + + self::$json = Arr::dot($configuration); + } + + return self::$json; + } + + public static function getPath(): string + { + if (null === self::$path) { + self::$path = base_path() . DIRECTORY_SEPARATOR; + } + + return self::$path; + } + + public static function stringOrIntToIntOrNull( + int | string $value, + int | null $default = null, + ): int | null { + if (is_int($value)) { + return $value; + } + + $value = trim($value); + + if ('' === $value) { + return $default; + } + + if (ctype_digit($value)) { + return (int) $value; + } + + return $default; + } + + public static function stringOrNull( + string | int | null $value, + string | int | null $default = null, + ): string | int | null { + if (! is_string($value)) { + return $default; + } + + $value = trim($value); + + if ('' === $value) { + return $default; + } + + if ('empty' === $value) { + return $default; + } + + if ('(empty)' === $value) { + return $default; + } + + if ('null' === $value) { + return $default; + } + + if ('(null)' === $value) { + return $default; + } + + return $value; + } + + public static function stringToArray(array | string | null $config, string $delimiter = ' '): array + { + if (is_array($config)) { + return $config; + } + if (is_string($config) && '' !== $config && '' !== $delimiter) { $response = explode($delimiter, $config); @@ -28,8 +473,12 @@ public static function stringToArray(?string $config, string $delimiter = ' '): return []; } - public static function stringToArrayOrNull(?string $config, string $delimiter = ' '): ?array + public static function stringToArrayOrNull(array | string | null $config, string $delimiter = ' '): ?array { + if (is_array($config) && [] !== $config) { + return $config; + } + if (is_string($config) && '' !== $config && '' !== $delimiter) { $response = explode($delimiter, $config); @@ -42,8 +491,12 @@ public static function stringToArrayOrNull(?string $config, string $delimiter = return null; } - public static function stringToBoolOrNull(?string $config, ?bool $default = null): ?bool + public static function stringToBoolOrNull(bool | string | null $config, ?bool $default = null): ?bool { + if (is_bool($config)) { + return $config; + } + if (is_string($config) && '' !== $config) { $config = mb_strtolower(trim($config)); @@ -58,4 +511,30 @@ public static function stringToBoolOrNull(?string $config, ?bool $default = null return $default; } + + public static function version(): int + { + $version = config('auth0.AUTH0_CONFIG_VERSION', 1); + + return is_int($version) ? $version : 1; + } + + private static function getValue( + string $setting, + array | bool | string | int | null $default = null, + ): array | bool | string | int | null { + if (defined('AUTH0_OVERRIDE_CONFIGURATION')) { + $override = constant('AUTH0_OVERRIDE_CONFIGURATION'); + + if (is_string($override)) { + $value = config($override . '.' . $setting); + } + } else { + $env = 'AUTH0_' . mb_strtoupper(Str::snake($setting)); + $json = self::CONFIG_AUDIENCE === $setting ? 'identifier' : Str::snake($setting); + $value = self::getEnvironment()[$env] ?? self::getJson()[$json] ?? $default; + } + + return $value ?? $default; + } } diff --git a/src/ConfigurationContract.php b/src/ConfigurationContract.php new file mode 100644 index 00000000..3c638880 --- /dev/null +++ b/src/ConfigurationContract.php @@ -0,0 +1,47 @@ +|string $config + * @param string $delimiter + */ + public static function stringToArrayOrNull(array | string | null $config, string $delimiter = ' '): ?array; + + /** + * Converts a truthy string representation into a boolean. + * + * @param null|bool|string $config + * @param ?bool $default + */ + public static function stringToBoolOrNull(string | bool | null $config, ?bool $default = null): ?bool; +} diff --git a/src/Contract/Auth/User/Provider.php b/src/Contract/Auth/User/Provider.php deleted file mode 100644 index ffa08313..00000000 --- a/src/Contract/Auth/User/Provider.php +++ /dev/null @@ -1,15 +0,0 @@ -guard(); - if (! $guard instanceof GuardContract || $guard->check()) { - return redirect()->intended(config('auth0.routes.home', '/')); + if (! $guard instanceof GuardAbstract) { + logger()->error(sprintf('A request implementing the `%s` controller was not routed through a Guard configured with an Auth0 driver. The incorrectly assigned Guard was: %s', self::class, $guard::class), $request->toArray()); + + throw new ControllerException(ControllerException::ROUTED_USING_INCOMPATIBLE_GUARD); } - $code = $request->query('code'); - $state = $request->query('state'); - $code = is_string($code) ? trim($code) : ''; - $state = is_string($state) ? trim($state) : ''; + $code = $request->query('code'); + $state = $request->query('state'); + $code = is_string($code) ? trim($code) : ''; + $state = is_string($state) ? trim($state) : ''; $success = false; if ('' === $code) { @@ -49,29 +53,28 @@ public function __invoke( $state = null; } - /* - * @var string|null $code - * @var string|null $state + /** + * @var null|string $code + * @var null|string $state */ - try { if (null !== $code && null !== $state) { event(new Attempting($guard::class, ['code' => $code, 'state' => $state], true)); - $success = $this->getSdk()->exchange( + $success = $guard->sdk()->exchange( code: $code, state: $state, ); } } catch (Throwable $throwable) { - $credentials = $this->getSdk()->getUser() ?? []; - $credentials['code'] = $code; + $credentials = $guard->sdk()->getUser() ?? []; + $credentials['code'] = $code; $credentials['state'] = $state; $credentials['error'] = ['description' => $throwable->getMessage()]; event(new Failed($guard::class, $guard->user(), $credentials)); - $this->getSdk()->clear(); + $guard->sdk()->clear(); // Throw hookable $event to allow custom error handling scenarios. $event = new AuthenticationFailed($throwable, true); @@ -85,27 +88,27 @@ public function __invoke( if (null !== $request->query('error') && null !== $request->query('error_description')) { // Workaround to aid static analysis, due to the mixed formatting of the query() response: - $error = $request->query('error', ''); + $error = $request->query('error', ''); $errorDescription = $request->query('error_description', ''); - $error = is_string($error) ? $error : ''; + $error = is_string($error) ? $error : ''; $errorDescription = is_string($errorDescription) ? $errorDescription : ''; event(new Attempting($guard::class, ['code' => $code, 'state' => $state], true)); event(new Failed($guard::class, $guard->user(), [ - 'code' => $code, + 'code' => $code, 'state' => $state, - 'error' => ['error' => $error, 'description' => $errorDescription] + 'error' => ['error' => $error, 'description' => $errorDescription], ])); // Clear the local session via the Auth0-PHP SDK: - $this->getSdk()->clear(); + $guard->sdk()->clear(); // Create a dynamic exception to report the API error response - $exception = new CallbackException(sprintf(CallbackException::MSG_API_RESPONSE, $error, $errorDescription)); + $exception = new CallbackControllerException(sprintf(CallbackControllerException::MSG_API_RESPONSE, $error, $errorDescription)); // Store the API exception in the session as a flash variable, in case the application wants to access it. - session()->flash('auth0.callback.error', sprintf(CallbackException::MSG_API_RESPONSE, $error, $errorDescription)); + session()->flash('auth0.callback.error', sprintf(CallbackControllerException::MSG_API_RESPONSE, $error, $errorDescription)); // Throw hookable $event to allow custom error handling scenarios: $event = new AuthenticationFailed($exception, true); @@ -118,14 +121,19 @@ public function __invoke( } if (! $success) { - return redirect()->intended(config('auth0.routes.login', '/')); + return redirect()->intended('/login'); } - $credential = $guard->find(Guard::SOURCE_SESSION); - $user = $credential?->getUser(); + $credential = ($guard instanceof Guard) ? $guard->find(Guard::SOURCE_SESSION) : $guard->find(); - if ($credential instanceof Credential && $user instanceof Authenticatable) { + $user = $credential?->getUser(); + + if ($credential instanceof CredentialEntityContract && $user instanceof Authenticatable) { event(new Validated($guard::class, $user)); + + /** + * @var Guard $guard + */ $guard->login($credential, Guard::SOURCE_SESSION); $request->session()->regenerate(); @@ -141,6 +149,6 @@ public function __invoke( } } - return redirect()->intended(config('auth0.routes.home', '/')); + return redirect()->intended('/'); } } diff --git a/src/Contract/Http/Controller/Stateful/Callback.php b/src/Controllers/CallbackControllerContract.php similarity index 77% rename from src/Contract/Http/Controller/Stateful/Callback.php rename to src/Controllers/CallbackControllerContract.php index cfc0d7a2..90a16075 100644 --- a/src/Contract/Http/Controller/Stateful/Callback.php +++ b/src/Controllers/CallbackControllerContract.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Http\Controller\Stateful; +namespace Auth0\Laravel\Controllers; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; -interface Callback +interface CallbackControllerContract extends ControllerContract { /** * Process the session for the end user after returning from authenticating with Auth0. diff --git a/src/Controllers/ControllerAbstract.php b/src/Controllers/ControllerAbstract.php new file mode 100644 index 00000000..a921c0cb --- /dev/null +++ b/src/Controllers/ControllerAbstract.php @@ -0,0 +1,23 @@ +guard(); + + if (! $guard instanceof GuardAbstract) { + logger()->error(sprintf('A request implementing the `%s` controller was not routed through a Guard configured with an Auth0 driver. The incorrectly assigned Guard was: %s', self::class, $guard::class), $request->toArray()); + + throw new ControllerException(ControllerException::ROUTED_USING_INCOMPATIBLE_GUARD); + } + + $loggedIn = $guard->check() ? true : null; + $loggedIn ??= (($guard instanceof Guard) ? $guard->find(Guard::SOURCE_SESSION) : $guard->find()) instanceof CredentialEntityContract; + + if ($loggedIn) { + return redirect()->intended('/'); + } + + $event = new LoginAttempting(); + event($event); + + $url = $guard->sdk()->login( + params: $event->getParameters(), + ); + + return redirect()->away($url); + } +} diff --git a/src/Contract/Http/Controller/Stateful/Login.php b/src/Controllers/LoginControllerContract.php similarity index 80% rename from src/Contract/Http/Controller/Stateful/Login.php rename to src/Controllers/LoginControllerContract.php index 661e4c17..d401ac6f 100644 --- a/src/Contract/Http/Controller/Stateful/Login.php +++ b/src/Controllers/LoginControllerContract.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Http\Controller\Stateful; +namespace Auth0\Laravel\Controllers; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; -interface Login +interface LoginControllerContract extends ControllerContract { /** * Redirect to the configured Auth0 Universal Login Page if a session is not available. diff --git a/src/Controllers/LogoutController.php b/src/Controllers/LogoutController.php new file mode 100644 index 00000000..b3ee19c5 --- /dev/null +++ b/src/Controllers/LogoutController.php @@ -0,0 +1,14 @@ +guard(); + + if (! $guard instanceof GuardAbstract) { + logger()->error(sprintf('A request implementing the `%s` controller was not routed through a Guard configured with an Auth0 driver. The incorrectly assigned Guard was: %s', self::class, $guard::class), $request->toArray()); + + throw new ControllerException(ControllerException::ROUTED_USING_INCOMPATIBLE_GUARD); + } + + $loggedIn = $guard->check() ? true : null; + $loggedIn ??= (($guard instanceof Guard) ? $guard->find(Guard::SOURCE_SESSION) : $guard->find()) instanceof CredentialEntityContract; + + if ($loggedIn) { + session()->invalidate(); + $guard->logout(); /** @phpstan-ignore-line */ + $route = (string) url('http://github.com/'); /** @phpstan-ignore-line */ + $url = $guard->sdk()->authentication()->getLogoutLink($route); + + return redirect()->away($url); + } + + return redirect()->intended('/'); + } +} diff --git a/src/Contract/Http/Controller/Stateful/Logout.php b/src/Controllers/LogoutControllerContract.php similarity index 78% rename from src/Contract/Http/Controller/Stateful/Logout.php rename to src/Controllers/LogoutControllerContract.php index 34145a3f..098ba20b 100644 --- a/src/Contract/Http/Controller/Stateful/Logout.php +++ b/src/Controllers/LogoutControllerContract.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Http\Controller\Stateful; +namespace Auth0\Laravel\Controllers; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; -interface Logout +interface LogoutControllerContract extends ControllerContract { /** * Redirect to Auth0's logout endpoint if a session is available. diff --git a/src/Entities/Credential.php b/src/Entities/Credential.php deleted file mode 100644 index 483f3a28..00000000 --- a/src/Entities/Credential.php +++ /dev/null @@ -1,167 +0,0 @@ - $accessTokenScope The access token scope for this credential. - * @param null|int $accessTokenExpiration The access token expiration for this credential. - * @param null|string $refreshToken The refresh token for this credential. - */ - public function __construct( - private ?Authenticatable $user = null, - private ?string $idToken = null, - private ?string $accessToken = null, - private ?array $accessTokenScope = null, - private ?int $accessTokenExpiration = null, - private ?string $refreshToken = null, - ) { - } - - public function clear(): self - { - $this->user = null; - $this->idToken = null; - $this->accessToken = null; - $this->accessTokenScope = null; - $this->accessTokenExpiration = null; - $this->refreshToken = null; - - return $this; - } - - public function getAccessToken(): ?string - { - return $this->accessToken; - } - - public function getAccessTokenExpiration(): ?int - { - return $this->accessTokenExpiration; - } - - public function getAccessTokenExpired(): ?bool - { - $expires = $this->getAccessTokenExpiration(); - - if (null === $expires || $expires <= 0) { - return null; - } - - return time() >= $expires; - } - - /** - * @psalm-suppress MixedReturnTypeCoercion - */ - public function getAccessTokenScope(): ?array - { - return $this->accessTokenScope; - } - - public function getIdToken(): ?string - { - return $this->idToken; - } - - public function getRefreshToken(): ?string - { - return $this->refreshToken; - } - - public function getUser(): ?Authenticatable - { - return $this->user; - } - - /** - * @return array{user: false|string, idToken: null|string, accessToken: null|string, accessTokenScope: null|string[], accessTokenExpiration: null|int, accessTokenExpired: null|bool, refreshToken: null|string} - */ - public function jsonSerialize(): mixed - { - return [ - 'user' => json_encode($this->getUser(), JSON_FORCE_OBJECT), - 'idToken' => $this->getIdToken(), - 'accessToken' => $this->getAccessToken(), - 'accessTokenScope' => $this->getAccessTokenScope(), - 'accessTokenExpiration' => $this->getAccessTokenExpiration(), - 'accessTokenExpired' => $this->getAccessTokenExpired(), - 'refreshToken' => $this->getRefreshToken(), - ]; - } - - public function setAccessToken( - ?string $accessToken = null, - ): self { - $this->accessToken = $accessToken; - - return $this; - } - - public function setAccessTokenExpiration( - ?int $accessTokenExpiration = null, - ): self { - $this->accessTokenExpiration = $accessTokenExpiration; - - return $this; - } - - public function setAccessTokenScope( - ?array $accessTokenScope = null, - ): self { - $this->accessTokenScope = $accessTokenScope; - - return $this; - } - - public function setIdToken( - ?string $idToken = null, - ): self { - $this->idToken = $idToken; - - return $this; - } - - public function setRefreshToken( - ?string $refreshToken = null, - ): self { - $this->refreshToken = $refreshToken; - - return $this; - } - - public function setUser( - ?Authenticatable $user = null, - ): self { - $this->user = $user; - - return $this; - } - - public static function create( - ?Authenticatable $user = null, - ?string $idToken = null, - ?string $accessToken = null, - ?array $accessTokenScope = null, - ?int $accessTokenExpiration = null, - ?string $refreshToken = null, - ): self { - return new self( - $user, - $idToken, - $accessToken, - $accessTokenScope, - $accessTokenExpiration, - $refreshToken, - ); - } -} diff --git a/src/Entities/CredentialEntity.php b/src/Entities/CredentialEntity.php new file mode 100644 index 00000000..e6ec27f3 --- /dev/null +++ b/src/Entities/CredentialEntity.php @@ -0,0 +1,118 @@ +user = null; + $this->idToken = null; + $this->accessToken = null; + $this->accessTokenDecoded = null; + $this->accessTokenScope = null; + $this->accessTokenExpiration = null; + $this->refreshToken = null; + + return $this; + } + + public function setAccessToken( + ?string $accessToken = null, + ): self { + $this->accessToken = $accessToken; + + return $this; + } + + public function setAccessTokenDecoded( + ?array $accessTokenDecoded = null, + ): self { + $this->accessTokenDecoded = $accessTokenDecoded; + + return $this; + } + + public function setAccessTokenExpiration( + ?int $accessTokenExpiration = null, + ): self { + $this->accessTokenExpiration = $accessTokenExpiration; + + return $this; + } + + public function setAccessTokenScope( + ?array $accessTokenScope = null, + ): self { + $this->accessTokenScope = $accessTokenScope; + + return $this; + } + + public function setIdToken( + ?string $idToken = null, + ): self { + $this->idToken = $idToken; + + return $this; + } + + public function setRefreshToken( + ?string $refreshToken = null, + ): self { + $this->refreshToken = $refreshToken; + + return $this; + } + + public function setUser( + ?Authenticatable $user = null, + ): self { + $this->user = $user; + + return $this; + } + + /** + * Create a new Credential instance. + * + * @param null|Authenticatable $user The user entity this credential represents. + * @param null|string $idToken The ID token for this credential. + * @param null|string $accessToken The access token for this credential. + * @param null|array $accessTokenScope The access token scope for this credential. + * @param null|int $accessTokenExpiration The access token expiration for this credential. + * @param null|string $refreshToken The refresh token for this credential. + * @param null|array $accessTokenDecoded The decoded access token for this credential. + */ + public static function create( + ?Authenticatable $user = null, + ?string $idToken = null, + ?string $accessToken = null, + ?array $accessTokenScope = null, + ?int $accessTokenExpiration = null, + ?string $refreshToken = null, + ?array $accessTokenDecoded = null, + ): self { + return new self( + $user, + $idToken, + $accessToken, + $accessTokenScope, + $accessTokenExpiration, + $refreshToken, + $accessTokenDecoded, + ); + } +} diff --git a/src/Entities/CredentialEntityAbstract.php b/src/Entities/CredentialEntityAbstract.php new file mode 100644 index 00000000..ca5c5b9c --- /dev/null +++ b/src/Entities/CredentialEntityAbstract.php @@ -0,0 +1,132 @@ + $accessTokenScope The access token scope for this credential. + * @param null|int $accessTokenExpiration The access token expiration for this credential. + * @param null|string $refreshToken The refresh token for this credential. + * @param null|array $accessTokenDecoded The decoded access token for this credential. + */ + public function __construct( + protected ?Authenticatable $user = null, + protected ?string $idToken = null, + protected ?string $accessToken = null, + protected ?array $accessTokenScope = null, + protected ?int $accessTokenExpiration = null, + protected ?string $refreshToken = null, + protected ?array $accessTokenDecoded = null, + ) { + } + + final public function getAccessToken(): ?string + { + return $this->accessToken; + } + + /** + * @psalm-suppress MixedReturnTypeCoercion + */ + final public function getAccessTokenDecoded(): ?array + { + return $this->accessTokenDecoded; + } + + final public function getAccessTokenExpiration(): ?int + { + return $this->accessTokenExpiration; + } + + final public function getAccessTokenExpired(): ?bool + { + $expires = $this->getAccessTokenExpiration(); + + if (null === $expires || $expires <= 0) { + return null; + } + + return time() >= $expires; + } + + /** + * @psalm-suppress MixedReturnTypeCoercion + */ + final public function getAccessTokenScope(): ?array + { + return $this->accessTokenScope; + } + + final public function getIdToken(): ?string + { + return $this->idToken; + } + + final public function getRefreshToken(): ?string + { + return $this->refreshToken; + } + + final public function getUser(): ?Authenticatable + { + return $this->user; + } + + /** + * @return array{user: false|string, idToken: null|string, accessToken: null|string, accessTokenDecoded: null|array, accessTokenScope: null|array, accessTokenExpiration: null|int, accessTokenExpired: null|bool, refreshToken: null|string} + */ + final public function jsonSerialize(): mixed + { + return [ + 'user' => json_encode($this->getUser(), JSON_FORCE_OBJECT), + 'idToken' => $this->getIdToken(), + 'accessToken' => $this->getAccessToken(), + 'accessTokenDecoded' => $this->getAccessTokenDecoded(), + 'accessTokenScope' => $this->getAccessTokenScope(), + 'accessTokenExpiration' => $this->getAccessTokenExpiration(), + 'accessTokenExpired' => $this->getAccessTokenExpired(), + 'refreshToken' => $this->getRefreshToken(), + ]; + } + + abstract public function clear(): self; + + abstract public function setAccessToken( + ?string $accessToken = null, + ): self; + + abstract public function setAccessTokenDecoded( + ?array $accessTokenDecoded = null, + ): self; + + abstract public function setAccessTokenExpiration( + ?int $accessTokenExpiration = null, + ): self; + + abstract public function setAccessTokenScope( + ?array $accessTokenScope = null, + ): self; + + abstract public function setIdToken( + ?string $idToken = null, + ): self; + + abstract public function setRefreshToken( + ?string $refreshToken = null, + ): self; + + abstract public function setUser( + ?Authenticatable $user = null, + ): self; +} diff --git a/src/Contract/Entities/Credential.php b/src/Entities/CredentialEntityContract.php similarity index 68% rename from src/Contract/Entities/Credential.php rename to src/Entities/CredentialEntityContract.php index a00b89c7..1e75fc93 100644 --- a/src/Contract/Entities/Credential.php +++ b/src/Entities/CredentialEntityContract.php @@ -2,12 +2,14 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Entities; +namespace Auth0\Laravel\Entities; use Illuminate\Contracts\Auth\Authenticatable; -use JsonSerializable; -interface Credential extends JsonSerializable +/** + * @api + */ +interface CredentialEntityContract extends EntityContract { /** * Clear all values from this Credential instance. @@ -19,6 +21,13 @@ public function clear(): self; */ public function getAccessToken(): ?string; + /** + * Get the decoded access token content for this credential. + * + * @return null|array + */ + public function getAccessTokenDecoded(): ?array; + /** * Get the access token expiration for this credential. */ @@ -32,7 +41,7 @@ public function getAccessTokenExpired(): ?bool; /** * Get the access token scope for this credential. * - * @return null|array + * @return null|array */ public function getAccessTokenScope(): ?array; @@ -60,6 +69,15 @@ public function setAccessToken( ?string $accessToken = null, ): self; + /** + * Set the decoded access token content for this credential. + * + * @param null|array $accessTokenDecoded The decoded access token content for this credential. + */ + public function setAccessTokenDecoded( + ?array $accessTokenDecoded = null, + ): self; + /** * Set the access token expiration for this credential. * @@ -72,7 +90,7 @@ public function setAccessTokenExpiration( /** * Set the access token scope for this credential. * - * @param null|array $accessTokenScope The access token scope for this credential. + * @param null|array $accessTokenScope The access token scope for this credential. */ public function setAccessTokenScope( ?array $accessTokenScope = null, @@ -104,23 +122,4 @@ public function setRefreshToken( public function setUser( ?Authenticatable $user = null, ): self; - - /** - * Create a new Credential instance. - * - * @param null|Authenticatable $user The user entity this credential represents. - * @param null|string $idToken The ID token for this credential. - * @param null|string $accessToken The access token for this credential. - * @param null|array $accessTokenScope The access token scope for this credential. - * @param null|int $accessTokenExpiration The access token expiration for this credential. - * @param null|string $refreshToken The refresh token for this credential. - */ - public static function create( - ?Authenticatable $user = null, - ?string $idToken = null, - ?string $accessToken = null, - ?array $accessTokenScope = null, - ?int $accessTokenExpiration = null, - ?string $refreshToken = null, - ): self; } diff --git a/src/Entities/EntityAbstract.php b/src/Entities/EntityAbstract.php new file mode 100644 index 00000000..65d88867 --- /dev/null +++ b/src/Entities/EntityAbstract.php @@ -0,0 +1,12 @@ +configuration instanceof SdkConfiguration) { + $configuration = []; + + if (2 === Configuration::version()) { + $defaultConfiguration = config('auth0.guards.default'); + $guardConfiguration = []; + + if (null !== $this->guardConfigurationKey && '' !== $this->guardConfigurationKey && 'default' !== $this->guardConfigurationKey) { + $guardConfiguration = config('auth0.guards.' . $this->guardConfigurationKey) ?? []; + } + + if (is_array($defaultConfiguration) && [] !== $defaultConfiguration) { + $configuration = array_merge($configuration, array_filter($defaultConfiguration)); + } + + if (is_array($guardConfiguration) && [] !== $guardConfiguration) { + $configuration = array_merge($configuration, array_filter($guardConfiguration)); + } + } + + if (2 !== Configuration::version()) { + $configuration = config('auth0'); + + if (! is_array($configuration)) { + $configuration = []; + } + } + + $this->configuration = $this->createConfiguration($configuration); + } + + return $this->configuration; + } + + final public function getCredentials(): ?object + { + return $this->getSdk()->getCredentials(); + } + + final public function getGuardConfigurationKey(): ?string + { + return $this->guardConfigurationKey; + } + + final public function getSdk(): Auth0Interface + { + if (! $this->sdk instanceof Auth0Interface) { + return $this->setSdk(new Auth0($this->getConfiguration())); + } + + return $this->sdk; + } + + final public function management(): ManagementInterface + { + return $this->getSdk()->management(); + } + + final public function setGuardConfigurationKey( + ?string $guardConfigurationKey = null, + ): self { + $this->guardConfigurationKey = $guardConfigurationKey; + + return $this; + } + + final public function setSdk(Auth0Interface $sdk): Auth0Interface + { + $this->configuration = $sdk->configuration(); + $this->sdk = $sdk; + + $this->setSdkTelemetry(); + + return $this->sdk; + } + + abstract public function reset(): self; + + /** + * @param null|array|SdkConfiguration $configuration + */ + abstract public function setConfiguration( + SdkConfiguration | array | null $configuration = null, + ): self; + + protected function bootManagementTokenCache(array $config): array + { + $managementTokenCache = $config['managementTokenCache'] ?? null; + $this->getManagementTokenCachePool(); + + // if (false === $managementTokenCache) { + // unset($config['managementTokenCache']); + + // return $config; + // } + + // if (null === $managementTokenCache) { + // $managementTokenCache = $this->getManagementTokenCachePool(); + // } + + // if (is_string($managementTokenCache)) { + // $managementTokenCache = app(trim($managementTokenCache)); + // } + + $config['managementTokenCache'] = $managementTokenCache instanceof CacheItemPoolInterface ? $managementTokenCache : null; + + return $config; + } + + protected function bootSessionStorage(array $config): array + { + $sessionStorage = $config['sessionStorage'] ?? null; + $sessionStorageId = $config['sessionStorageId'] ?? 'auth0_session'; + + if (false === $sessionStorage) { + unset($config['sessionStorage']); + + return $config; + } + + if (null === $sessionStorage) { + $sessionStorage = app(SessionBridge::class, [ + 'prefix' => $sessionStorageId, + ]); + } + + if (is_string($sessionStorage)) { + $sessionStorage = app(trim($sessionStorage), [ + 'prefix' => $sessionStorageId, + ]); + } + + $config['sessionStorage'] = $sessionStorage instanceof StoreInterface ? $sessionStorage : null; + + return $config; + } + + protected function bootStrategy(array $config): array + { + $strategy = $config['strategy'] ?? SdkConfiguration::STRATEGY_REGULAR; + + if (! is_string($strategy)) { + $strategy = SdkConfiguration::STRATEGY_REGULAR; + } + + $config['strategy'] = $strategy; + + return $config; + } + + protected function bootTokenCache(array $config): array + { + $tokenCache = $config['tokenCache'] ?? null; + + if (false === $tokenCache) { + unset($config['tokenCache']); + + return $config; + } + + if (null === $tokenCache) { + $tokenCache = $this->getTokenCachePool(); + } + + if (is_string($tokenCache)) { + $tokenCache = app(trim($tokenCache)); + } + + $config['tokenCache'] = $tokenCache instanceof CacheItemPoolInterface ? $tokenCache : null; + + return $config; + } + + protected function bootTransientStorage(array $config): array + { + $transientStorage = $config['transientStorage'] ?? null; + $transientStorageId = $config['transientStorageId'] ?? 'auth0_transient'; + + if (false === $transientStorage) { + unset($config['transientStorage']); + + return $config; + } + + if (null === $transientStorage) { + $transientStorage = app(SessionBridge::class, [ + 'prefix' => $transientStorageId, + ]); + } + + if (is_string($transientStorage)) { + $transientStorage = app(trim($transientStorage), [ + 'prefix' => $transientStorageId, + ]); + } + + $config['transientStorage'] = $transientStorage instanceof StoreInterface ? $transientStorage : null; + + return $config; + } + + protected function createConfiguration( + array $configuration, + ): SdkConfiguration { + // Give host application an opportunity to update the configuration before building configuration. + $event = new BuildingConfigurationEvent($configuration); + event($event); + $configuration = $event->getConfiguration(); + + $configuration = $this->bootStrategy($configuration); + $configuration = $this->bootTokenCache($configuration); + $configuration = $this->bootManagementTokenCache($configuration); + + if (in_array($configuration['strategy'], SdkConfiguration::STRATEGIES_USING_SESSIONS, true)) { + $configuration = $this->bootSessionStorage($configuration); + $configuration = $this->bootTransientStorage($configuration); + } + + $configuration = new SdkConfiguration($configuration); + + // Give host application an opportunity to update the configuration before applying it. + $event = new BuiltConfigurationEvent($configuration); + event($event); + + return $event->getConfiguration(); + } + + protected function getManagementTokenCachePool(): CacheItemPoolInterface + { + if (! $this->managementTokenCachePool instanceof CacheItemPoolInterface) { + $this->managementTokenCachePool = app(CacheBridge::class); + } + + return $this->managementTokenCachePool; + } + + protected function getTokenCachePool(): CacheItemPoolInterface + { + if (! $this->tokenCachePool instanceof CacheItemPoolInterface) { + $this->tokenCachePool = app(CacheBridge::class); + } + + return $this->tokenCachePool; + } + + /** + * Updates the Auth0 PHP SDK's telemetry to include the correct Laravel markers. + */ + protected function setSdkTelemetry(): self + { + HttpTelemetry::setEnvProperty('Laravel', app()->version()); + HttpTelemetry::setPackage('laravel-auth0', Service::VERSION); + + return $this; + } +} diff --git a/src/Contract/Auth0.php b/src/Entities/InstanceEntityContract.php similarity index 53% rename from src/Contract/Auth0.php rename to src/Entities/InstanceEntityContract.php index 6a944a0f..a808d667 100644 --- a/src/Contract/Auth0.php +++ b/src/Entities/InstanceEntityContract.php @@ -2,23 +2,26 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract; +namespace Auth0\Laravel\Entities; -use Auth0\SDK\Configuration\SdkConfiguration as Configuration; +use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\SDK\Contract\API\ManagementInterface; -use Auth0\SDK\Contract\Auth0Interface as SDK; +use Auth0\SDK\Contract\Auth0Interface; -interface Auth0 +/** + * @api + */ +interface InstanceEntityContract extends EntityContract { /** * Create/return instance of the Auth0-PHP SdkConfiguration. */ - public function getConfiguration(): Configuration; + public function getConfiguration(): SdkConfiguration; /** * Create/return instance of the Auth0-PHP SDK. */ - public function getSdk(): SDK; + public function getSdk(): Auth0Interface; /** * Returns an instance of the Management API class. @@ -33,14 +36,14 @@ public function reset(): self; /** * Assign the Auth0-PHP SdkConfiguration. * - * @param Configuration $configuration + * @param null|array|SdkConfiguration $configuration */ - public function setConfiguration(Configuration $configuration): self; + public function setConfiguration(SdkConfiguration | array | null $configuration): self; /** * Create/return instance of the Auth0-PHP SDK. * - * @param SDK $sdk + * @param Auth0Interface $sdk */ - public function setSdk(SDK $sdk): SDK; + public function setSdk(Auth0Interface $sdk): Auth0Interface; } diff --git a/src/Entities/InstanceEntityTrait.php b/src/Entities/InstanceEntityTrait.php new file mode 100644 index 00000000..43faa890 --- /dev/null +++ b/src/Entities/InstanceEntityTrait.php @@ -0,0 +1,62 @@ +sdk, $this->configuration); + + $this->sdk = null; + $this->configuration = null; + + return $this; + } + + /** + * @param null|array|SdkConfiguration $configuration + */ + public function setConfiguration( + SdkConfiguration | array | null $configuration = null, + ): self { + if (is_array($configuration)) { + $configuration = $this->createConfiguration($configuration); + } + + $this->configuration = $configuration; + + if ($this->configuration instanceof \Auth0\SDK\Configuration\SdkConfiguration && $this->sdk instanceof Auth0Interface) { + $this->sdk->setConfiguration($this->configuration); + } + + return $this; + } + + public static function create( + SdkConfiguration | array | null $configuration = null, + ?string $guardConfigurationName = null, + ): self { + $instance = new self(); + + if (null !== $guardConfigurationName) { + $instance->setGuardConfigurationKey($guardConfigurationName); + } + + if (null !== $configuration) { + $instance->setConfiguration($configuration); + } + + return $instance; + } +} diff --git a/src/Event/Configuration/Building.php b/src/Event/Configuration/Building.php deleted file mode 100644 index 678f383b..00000000 --- a/src/Event/Configuration/Building.php +++ /dev/null @@ -1,27 +0,0 @@ -configuration; - } - - public function setConfiguration(array $configuration): self - { - $this->configuration = $configuration; - - return $this; - } -} diff --git a/src/Event/Configuration/Built.php b/src/Event/Configuration/Built.php deleted file mode 100644 index b2c23dc2..00000000 --- a/src/Event/Configuration/Built.php +++ /dev/null @@ -1,28 +0,0 @@ -configuration; - } - - public function setConfiguration(Configuration $configuration): self - { - $this->configuration = $configuration; - - return $this; - } -} diff --git a/src/Event/Middleware/StatefulRequest.php b/src/Event/Middleware/StatefulRequest.php deleted file mode 100644 index c58d00fe..00000000 --- a/src/Event/Middleware/StatefulRequest.php +++ /dev/null @@ -1,19 +0,0 @@ -exception; - } - - public function getThrowException(): bool - { - return $this->throwException; - } - - public function setException(Throwable $exception): self - { - $this->exception = $exception; - $this->mutated = true; - - return $this; - } - - public function setThrowException(bool $throwException): self - { - $this->throwException = $throwException; - - return $this; - } -} diff --git a/src/Event/Stateful/AuthenticationSucceeded.php b/src/Event/Stateful/AuthenticationSucceeded.php deleted file mode 100644 index a4e8c4c7..00000000 --- a/src/Event/Stateful/AuthenticationSucceeded.php +++ /dev/null @@ -1,29 +0,0 @@ -user; - } - - public function setUser(Authenticatable $user): self - { - $this->user = $user; - $this->mutated = true; - - return $this; - } -} diff --git a/src/Event/Stateful/LoginAttempting.php b/src/Event/Stateful/LoginAttempting.php deleted file mode 100644 index c99ea177..00000000 --- a/src/Event/Stateful/LoginAttempting.php +++ /dev/null @@ -1,28 +0,0 @@ -parameters; - } - - public function setParameters(array $parameters): self - { - $this->parameters = $parameters; - - return $this; - } -} diff --git a/src/Event/Stateful/TokenExpired.php b/src/Event/Stateful/TokenExpired.php deleted file mode 100644 index 0602fbc2..00000000 --- a/src/Event/Stateful/TokenExpired.php +++ /dev/null @@ -1,12 +0,0 @@ -token; - } - - public function setToken(string $token): self - { - $this->token = $token; - $this->mutated = true; - - return $this; - } -} diff --git a/src/Event/Stateless/TokenVerificationFailed.php b/src/Event/Stateless/TokenVerificationFailed.php deleted file mode 100644 index 72dc8993..00000000 --- a/src/Event/Stateless/TokenVerificationFailed.php +++ /dev/null @@ -1,28 +0,0 @@ -exception; - } - - public function getToken(): string - { - return $this->token; - } -} diff --git a/src/Event/Stateless/TokenVerificationSucceeded.php b/src/Event/Stateless/TokenVerificationSucceeded.php deleted file mode 100644 index cf820645..00000000 --- a/src/Event/Stateless/TokenVerificationSucceeded.php +++ /dev/null @@ -1,27 +0,0 @@ -payload; - } - - public function getToken(): string - { - return $this->token; - } -} diff --git a/src/Events/Auth0EventContract.php b/src/Events/Auth0EventContract.php new file mode 100644 index 00000000..2cbb72ce --- /dev/null +++ b/src/Events/Auth0EventContract.php @@ -0,0 +1,16 @@ +exception; + } + + final public function getThrowException(): bool + { + return $this->throwException; + } + + final public function setException(Throwable $exception): void + { + $this->exception = $exception; + $this->mutated = true; + } + + final public function setThrowException(bool $throwException): void + { + $this->throwException = $throwException; + } +} diff --git a/src/Contract/Event/Stateful/AuthenticationFailed.php b/src/Events/AuthenticationFailedContract.php similarity index 80% rename from src/Contract/Event/Stateful/AuthenticationFailed.php rename to src/Events/AuthenticationFailedContract.php index a35a7c42..9eb231d2 100644 --- a/src/Contract/Event/Stateful/AuthenticationFailed.php +++ b/src/Events/AuthenticationFailedContract.php @@ -2,11 +2,14 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Event\Stateful; +namespace Auth0\Laravel\Events; use Throwable; -interface AuthenticationFailed +/** + * @api + */ +interface AuthenticationFailedContract extends EventContract { /** * AuthenticationFailed constructor. @@ -31,12 +34,12 @@ public function getThrowException(): bool; * * @param Throwable $exception an exception instance in which to throw for the authentication failure */ - public function setException(Throwable $exception): self; + public function setException(Throwable $exception): void; /** * Determine whether the provided exception will be thrown by the SDK. * * @param bool $throwException whether or not $exception will be thrown */ - public function setThrowException(bool $throwException): self; + public function setThrowException(bool $throwException): void; } diff --git a/src/Events/AuthenticationSucceeded.php b/src/Events/AuthenticationSucceeded.php new file mode 100644 index 00000000..301e304b --- /dev/null +++ b/src/Events/AuthenticationSucceeded.php @@ -0,0 +1,14 @@ +user; + } + + final public function setUser(Authenticatable $user): void + { + $this->user = $user; + $this->mutated = true; + } +} diff --git a/src/Contract/Event/Stateful/AuthenticationSucceeded.php b/src/Events/AuthenticationSucceededContract.php similarity index 77% rename from src/Contract/Event/Stateful/AuthenticationSucceeded.php rename to src/Events/AuthenticationSucceededContract.php index c62284a6..098484a9 100644 --- a/src/Contract/Event/Stateful/AuthenticationSucceeded.php +++ b/src/Events/AuthenticationSucceededContract.php @@ -2,11 +2,14 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Event\Stateful; +namespace Auth0\Laravel\Events; use Illuminate\Contracts\Auth\Authenticatable; -interface AuthenticationSucceeded +/** + * @api + */ +interface AuthenticationSucceededContract extends EventContract { /** * AuthenticationSucceeded constructor. @@ -25,5 +28,5 @@ public function getUser(): Authenticatable; * * @param Authenticatable $user an instance of Authenticatable representing the authenticated user */ - public function setUser(Authenticatable $user): self; + public function setUser(Authenticatable $user): void; } diff --git a/src/Events/Configuration/BuildingConfigurationEvent.php b/src/Events/Configuration/BuildingConfigurationEvent.php new file mode 100644 index 00000000..e3b0a1df --- /dev/null +++ b/src/Events/Configuration/BuildingConfigurationEvent.php @@ -0,0 +1,14 @@ +configuration; + } + + final public function setConfiguration(array $configuration): void + { + $this->configuration = $configuration; + } +} diff --git a/src/Events/Configuration/BuildingConfigurationEventContract.php b/src/Events/Configuration/BuildingConfigurationEventContract.php new file mode 100644 index 00000000..42f7ac38 --- /dev/null +++ b/src/Events/Configuration/BuildingConfigurationEventContract.php @@ -0,0 +1,32 @@ + $configuration a configuration array for use with the Auth0-PHP SDK + */ + public function __construct(array $configuration); + + /** + * Returns the exception to be thrown. + */ + public function getConfiguration(): array; + + /** + * Determine whether the provided exception will be thrown by the SDK. + * + * @param array $configuration an configuration array for use with the Auth0-PHP SDK + */ + public function setConfiguration(array $configuration): void; +} diff --git a/src/Events/Configuration/BuiltConfigurationEvent.php b/src/Events/Configuration/BuiltConfigurationEvent.php new file mode 100644 index 00000000..92e68c29 --- /dev/null +++ b/src/Events/Configuration/BuiltConfigurationEvent.php @@ -0,0 +1,14 @@ +configuration; + } + + final public function setConfiguration(SdkConfiguration $configuration): void + { + $this->configuration = $configuration; + } +} diff --git a/src/Contract/Event/Configuration/Built.php b/src/Events/Configuration/BuiltConfigurationEventContract.php similarity index 79% rename from src/Contract/Event/Configuration/Built.php rename to src/Events/Configuration/BuiltConfigurationEventContract.php index f0cf4076..0bb3bac7 100644 --- a/src/Contract/Event/Configuration/Built.php +++ b/src/Events/Configuration/BuiltConfigurationEventContract.php @@ -2,11 +2,15 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Event\Configuration; +namespace Auth0\Laravel\Events\Configuration; +use Auth0\Laravel\Events\EventContract; use Auth0\SDK\Configuration\SdkConfiguration; -interface Built +/** + * @api + */ +interface BuiltConfigurationEventContract extends EventContract { /** * AuthenticationFailed constructor. @@ -25,5 +29,5 @@ public function getConfiguration(): SdkConfiguration; * * @param SdkConfiguration $configuration an instance of SdkConfiguration for use with the Auth0-PHP SDK */ - public function setConfiguration(SdkConfiguration $configuration): self; + public function setConfiguration(SdkConfiguration $configuration): void; } diff --git a/src/Event/Auth0Event.php b/src/Events/EventAbstract.php similarity index 65% rename from src/Event/Auth0Event.php rename to src/Events/EventAbstract.php index caf58650..6aec1603 100644 --- a/src/Event/Auth0Event.php +++ b/src/Events/EventAbstract.php @@ -2,14 +2,14 @@ declare(strict_types=1); -namespace Auth0\Laravel\Event; - -use Auth0\Laravel\Contract\Event\Auth0Event as EventAuth0Event; +namespace Auth0\Laravel\Events; /** - * @codeCoverageIgnore + * Base event class. + * + * @api */ -abstract class Auth0Event implements EventAuth0Event +abstract class EventAbstract { /** * Tracks whether an event payload has been overwritten. diff --git a/src/Contract/Event/Auth0Event.php b/src/Events/EventContract.php similarity index 68% rename from src/Contract/Event/Auth0Event.php rename to src/Events/EventContract.php index 9bce4066..16e3a1c8 100644 --- a/src/Contract/Event/Auth0Event.php +++ b/src/Events/EventContract.php @@ -2,9 +2,12 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Event; +namespace Auth0\Laravel\Events; -interface Auth0Event +/** + * @api + */ +interface EventContract { /** * Returns whether an event payload has been overwritten. diff --git a/src/Events/LoginAttempting.php b/src/Events/LoginAttempting.php new file mode 100644 index 00000000..b211e4db --- /dev/null +++ b/src/Events/LoginAttempting.php @@ -0,0 +1,14 @@ +parameters; + } + + final public function setParameters(array $parameters): void + { + $this->parameters = $parameters; + } +} diff --git a/src/Contract/Event/Stateful/LoginAttempting.php b/src/Events/LoginAttemptingContract.php similarity index 70% rename from src/Contract/Event/Stateful/LoginAttempting.php rename to src/Events/LoginAttemptingContract.php index 3c278d0b..163f6a74 100644 --- a/src/Contract/Event/Stateful/LoginAttempting.php +++ b/src/Events/LoginAttemptingContract.php @@ -2,9 +2,12 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Event\Stateful; +namespace Auth0\Laravel\Events; -interface LoginAttempting +/** + * @api + */ +interface LoginAttemptingContract extends EventContract { /** * @param array $parameters The login parameters array. @@ -23,5 +26,5 @@ public function getParameters(): array; * * @param array $parameters */ - public function setParameters(array $parameters): self; + public function setParameters(array $parameters): void; } diff --git a/src/Events/Middleware/StatefulMiddlewareRequest.php b/src/Events/Middleware/StatefulMiddlewareRequest.php new file mode 100644 index 00000000..8a8987f8 --- /dev/null +++ b/src/Events/Middleware/StatefulMiddlewareRequest.php @@ -0,0 +1,9 @@ +token; + } + + final public function setToken(string $token): void + { + $this->token = $token; + $this->mutated = true; + } +} diff --git a/src/Contract/Event/Stateless/TokenVerificationAttempting.php b/src/Events/TokenVerificationAttemptingContract.php similarity index 71% rename from src/Contract/Event/Stateless/TokenVerificationAttempting.php rename to src/Events/TokenVerificationAttemptingContract.php index b032a925..1a61f755 100644 --- a/src/Contract/Event/Stateless/TokenVerificationAttempting.php +++ b/src/Events/TokenVerificationAttemptingContract.php @@ -2,9 +2,12 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Event\Stateless; +namespace Auth0\Laravel\Events; -interface TokenVerificationAttempting +/** + * @api + */ +interface TokenVerificationAttemptingContract extends EventContract { /** * AuthenticationSucceeded constructor. @@ -23,5 +26,5 @@ public function getToken(): string; * * @param string $token a bearer JSON web token */ - public function setToken(string $token): self; + public function setToken(string $token): void; } diff --git a/src/Events/TokenVerificationFailed.php b/src/Events/TokenVerificationFailed.php new file mode 100644 index 00000000..c332978c --- /dev/null +++ b/src/Events/TokenVerificationFailed.php @@ -0,0 +1,14 @@ +exception; + } + + final public function getToken(): string + { + return $this->token; + } +} diff --git a/src/Contract/Event/Stateless/TokenVerificationFailed.php b/src/Events/TokenVerificationFailedContract.php similarity index 84% rename from src/Contract/Event/Stateless/TokenVerificationFailed.php rename to src/Events/TokenVerificationFailedContract.php index a40fe97a..0b88514a 100644 --- a/src/Contract/Event/Stateless/TokenVerificationFailed.php +++ b/src/Events/TokenVerificationFailedContract.php @@ -2,11 +2,14 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Event\Stateless; +namespace Auth0\Laravel\Events; use Throwable; -interface TokenVerificationFailed +/** + * @api + */ +interface TokenVerificationFailedContract extends EventContract { /** * AuthenticationFailed constructor. diff --git a/src/Events/TokenVerificationSucceeded.php b/src/Events/TokenVerificationSucceeded.php new file mode 100644 index 00000000..284242e7 --- /dev/null +++ b/src/Events/TokenVerificationSucceeded.php @@ -0,0 +1,14 @@ +payload; + } + + final public function getToken(): string + { + return $this->token; + } +} diff --git a/src/Contract/Event/Stateless/TokenVerificationSucceeded.php b/src/Events/TokenVerificationSucceededContract.php similarity index 82% rename from src/Contract/Event/Stateless/TokenVerificationSucceeded.php rename to src/Events/TokenVerificationSucceededContract.php index 9a114668..f2a2c493 100644 --- a/src/Contract/Event/Stateless/TokenVerificationSucceeded.php +++ b/src/Events/TokenVerificationSucceededContract.php @@ -2,9 +2,12 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Event\Stateless; +namespace Auth0\Laravel\Events; -interface TokenVerificationSucceeded +/** + * @api + */ +interface TokenVerificationSucceededContract extends EventContract { /** * AuthenticationSucceeded constructor. diff --git a/src/Exception/AuthenticationException.php b/src/Exception/AuthenticationException.php deleted file mode 100644 index ab018a37..00000000 --- a/src/Exception/AuthenticationException.php +++ /dev/null @@ -1,16 +0,0 @@ -isImpersonating()) { + return $this->getImposter(); + } + + return $this->findSession(); + } + + public function findSession(): ?CredentialEntityContract + { + if ($this->isImpersonating()) { + return $this->getImposter(); + } + + $this->getSession(); + $session = $this->pullState(); + $user = $session?->getUser(); + + if ($session instanceof CredentialEntityContract && $user instanceof Authenticatable) { + $user = $this->getProvider()->retrieveByCredentials($this->normalizeUserArray($user)); + + if ($user instanceof Authenticatable) { + $scope = $session->getAccessTokenScope(); + $decoded = $session->getAccessTokenDecoded(); + + /** + * @var array $scope + * @var array $decoded + */ + $credential = CredentialEntity::create( + user: $user, + idToken: $session->getIdToken(), + accessToken: $session->getAccessToken(), + accessTokenDecoded: $decoded, + accessTokenScope: $scope, + accessTokenExpiration: $session->getAccessTokenExpiration(), + refreshToken: $session->getRefreshToken(), + ); + + return $this->refreshSession($credential); + } + } + + return null; + } + + public function forgetUser(): self + { + $this->setCredential(); + + return $this; + } + + public function getCredential(): ?CredentialEntityContract + { + if ($this->isImpersonating()) { + return $this->getImposter(); + } + + if ($this->credential instanceof CredentialEntityContract) { + $updated = $this->findSession(); + $this->setCredential($updated); + $this->pushState($updated); + } + + return $this->credential; + } + + public function login( + ?CredentialEntityContract $credential, + ): self { + $this->stopImpersonating(); + + $this->setCredential($credential); + $this->pushState($credential); + + if ($credential instanceof CredentialEntityContract) { + $user = $credential->getUser(); + + if ($user instanceof Authenticatable) { + event(new Login(self::class, $user, true)); + } + } + + return $this; + } + + public function logout(): self + { + $user = $this->user(); + + if ($user instanceof Authenticatable) { + event(new Logout(self::class, $user)); + } + + $this->stopImpersonating(); + $this->setCredential(); + $this->pushState(); + $this->forgetUser(); + + return $this; + } + + public function pushState( + ?CredentialEntityContract $credential = null, + ): self { + $sdk = $this->sdk(); + $credential ??= $this->getCredential(); + + if (! $credential instanceof CredentialEntityContract) { + $sdk->clear(true); + + return $this; + } + + $user = $credential->getUser(); + $idToken = $credential->getIdToken(); + $accessToken = $credential->getAccessToken(); + $accessTokenScope = $credential->getAccessTokenScope(); + $accessTokenExpiration = $credential->getAccessTokenExpiration(); + $refreshToken = $credential->getRefreshToken(); + + if ($user instanceof Authenticatable) { + $update = $this->normalizeUserArray($user); + $current = $sdk->getUser() ?? []; + + if (count($update) !== count($current) || [] !== array_diff(array_map('serialize', $update), array_map('serialize', $current))) { + $sdk->setUser($update); + } + } + + if (null !== $idToken && $idToken !== $sdk->getIdToken()) { + $sdk->setIdToken($idToken); + } + + if (null !== $accessToken && $accessToken !== $sdk->getAccessToken()) { + $sdk->setAccessToken($accessToken); + } + + if (null !== $accessTokenScope && $accessTokenScope !== $sdk->getAccessTokenScope()) { + /** + * @var array $accessTokenScope + */ + $sdk->setAccessTokenScope($accessTokenScope); + } + + if (null !== $accessTokenExpiration && $accessTokenExpiration !== $sdk->getAccessTokenExpiration()) { + $sdk->setAccessTokenExpiration($accessTokenExpiration); + } + + if (null !== $refreshToken && $refreshToken !== $sdk->getRefreshToken()) { + $sdk->setRefreshToken($refreshToken); + } + + return $this; + } + + public function refreshUser(): void + { + if ($this->isImpersonating()) { + return; + } + + if ($this->check()) { + $credential = $this->getCredential(); + $accessToken = $credential?->getAccessToken(); + + if (! $credential instanceof CredentialEntityContract || null === $accessToken) { + return; + } + + $response = $this->sdk()->authentication()->userInfo($accessToken); + + if (HttpResponse::wasSuccessful($response)) { + $response = HttpResponse::decodeContent($response); + + if (! is_array($response)) { + return; + } + + $user = $this->getProvider()->retrieveByCredentials($response); + $scope = $credential->getAccessTokenScope(); + $decoded = $credential->getAccessTokenDecoded(); + + /** + * @var array $scope + * @var array $decoded + */ + $this->pushState(CredentialEntity::create( + user: $user, + idToken: $credential->getIdToken(), + accessToken: $credential->getAccessToken(), + accessTokenScope: $scope, + accessTokenDecoded: $decoded, + accessTokenExpiration: $credential->getAccessTokenExpiration(), + refreshToken: $credential->getRefreshToken(), + )); + } + } + } + + public function setCredential( + ?CredentialEntityContract $credential = null, + ): self { + $this->stopImpersonating(); + + $this->credential = $credential; + + return $this; + } + + /** + * @param CredentialEntityContract $credential + */ + public function setImpersonating( + CredentialEntityContract $credential, + ): self { + $this->impersonationSource = self::SOURCE_SESSION; + $this->impersonating = $credential; + + return $this; + } + + public function setUser( + Authenticatable $user, + ): void { + if ($this->isImpersonating()) { + if ($this->getImposter()?->getUser() === $user) { + return; + } + + $this->stopImpersonating(); + } + + $credential = $this->getCredential() ?? CredentialEntity::create(); + $credential->setUser($user); + + $this->setCredential($credential); + $this->pushState($credential); + } + + public function user(): ?Authenticatable + { + if ($this->isImpersonating()) { + return $this->getImposter()?->getUser(); + } + + $currentUser = $this->getCredential()?->getUser(); + + if ($currentUser instanceof Authenticatable) { + return $currentUser; + } + + $session = $this->find(); + + if ($session instanceof CredentialEntityContract) { + $this->login($session); + + return $this->getCredential()?->getUser(); + } + + return null; + } + + private function pullState(): ?CredentialEntityContract + { + $sdk = $this->sdk(); + $sdk->refreshState(); + + $credentials = $sdk->getCredentials(); + + /** @var mixed $credentials */ + if (is_object($credentials) && property_exists($credentials, 'user') && property_exists($credentials, 'idToken') && property_exists($credentials, 'accessToken') && property_exists($credentials, 'accessTokenScope') && property_exists($credentials, 'accessTokenExpiration') && property_exists($credentials, 'refreshToken')) { + $decoded = null; + + if (null !== $credentials->accessToken) { + $decoded = (new Parser(new SdkConfiguration(strategy: SdkConfiguration::STRATEGY_NONE), $credentials->accessToken))->export(); + } + + /** + * @var null|array $decoded + */ + + return CredentialEntity::create( + user: new StatefulUser($credentials->user), + idToken: $credentials->idToken, + accessToken: $credentials->accessToken, + accessTokenDecoded: $decoded, + accessTokenScope: $credentials->accessTokenScope, + accessTokenExpiration: $credentials->accessTokenExpiration, + refreshToken: $credentials->refreshToken, + ); + } + + return null; + } + + private function refreshSession( + ?CredentialEntityContract $credential, + ): ?CredentialEntityContract { + if (! $credential instanceof CredentialEntityContract || true !== $credential->getAccessTokenExpired()) { + return $credential; + } + + if (null === $credential->getRefreshToken()) { + return null; + } + + try { + $this->sdk()->renew(); + $session = $this->pullState(); + } catch (\Throwable) { + event(new TokenRefreshFailed()); + $session = null; + } + + if ($session instanceof CredentialEntityContract) { + event(new TokenRefreshSucceeded()); + $user = $session->getUser(); + + // @codeCoverageIgnoreStart + if (! $user instanceof Authenticatable) { + return null; + } + // @codeCoverageIgnoreEnd + + $user = $this->getProvider()->retrieveByCredentials($this->normalizeUserArray($user)); + + if ($user instanceof Authenticatable) { + $decoded = null; + $accessToken = $session->getAccessToken(); + + if (null !== $accessToken) { + $decoded = (new Parser(new SdkConfiguration(strategy: SdkConfiguration::STRATEGY_NONE), $accessToken))->export(); + } + + $scope = $session->getAccessTokenScope(); + + /** + * @var array $scope + * @var null|array $decoded + */ + + return CredentialEntity::create( + user: $user, + idToken: $session->getIdToken(), + accessToken: $session->getAccessToken(), + accessTokenDecoded: $decoded, + accessTokenScope: $scope, + accessTokenExpiration: $session->getAccessTokenExpiration(), + refreshToken: $session->getRefreshToken(), + ); + } + } + + $this->setCredential(null); + $this->pushState(); + + return null; + } +} diff --git a/src/Guards/AuthenticationGuardContract.php b/src/Guards/AuthenticationGuardContract.php new file mode 100644 index 00000000..65d857b1 --- /dev/null +++ b/src/Guards/AuthenticationGuardContract.php @@ -0,0 +1,37 @@ +isImpersonating()) { + return $this->getImposter(); + } + + return $this->findToken(); + } + + public function findToken(): ?CredentialEntityContract + { + if ($this->isImpersonating()) { + return $this->getImposter(); + } + + $token = trim(app('request')->bearerToken() ?? ''); + + if ('' === $token) { + return null; + } + + $decoded = $this->processToken( + token: $token, + ); + + /** + * @var null|array $decoded + */ + if (null === $decoded) { + return null; + } + + $provider = $this->getProvider(); + + // @codeCoverageIgnoreStart + if (! $provider instanceof UserProviderContract) { + return null; + } + // @codeCoverageIgnoreEnd + + $user = $provider->getRepository()->fromAccessToken( + user: $decoded, + ); + + // @codeCoverageIgnoreStart + if (! $user instanceof Authenticatable) { + return null; + } + // @codeCoverageIgnoreEnd + + $data = $this->normalizeUserArray($user); + + // @codeCoverageIgnoreStart + if ([] === $data) { + return null; + } + // @codeCoverageIgnoreEnd + + $scope = isset($data['scope']) && is_string($data['scope']) ? explode(' ', $data['scope']) : []; + $exp = isset($data['exp']) && is_numeric($data['exp']) ? (int) $data['exp'] : null; + + return CredentialEntity::create( + user: $user, + accessToken: $token, + accessTokenScope: $scope, + accessTokenExpiration: $exp, + accessTokenDecoded: $decoded, + ); + } + + public function forgetUser(): self + { + $this->setCredential(); + + return $this; + } + + public function getCredential(): ?CredentialEntityContract + { + if ($this->isImpersonating()) { + return $this->getImposter(); + } + + return $this->credential; + } + + public function login( + ?CredentialEntityContract $credential, + ): self { + $this->stopImpersonating(); + + $this->setCredential($credential); + + return $this; + } + + public function logout(): self + { + $this->stopImpersonating(); + + $this->setCredential(); + $this->forgetUser(); + + return $this; + } + + public function refreshUser(): void + { + if ($this->isImpersonating()) { + return; + } + + if ($this->check()) { + $credential = $this->getCredential(); + $accessToken = $credential?->getAccessToken(); + + if (! $credential instanceof CredentialEntityContract || null === $accessToken) { + return; + } + + $response = $this->sdk()->authentication()->userInfo($accessToken); + + if (HttpResponse::wasSuccessful($response)) { + $response = HttpResponse::decodeContent($response); + + if (! is_array($response)) { + return; + } + + $user = $this->getProvider()->retrieveByCredentials($response); + $scope = $credential->getAccessTokenScope(); + + /** + * @var array $scope + */ + $this->setCredential(CredentialEntity::create( + user: $user, + idToken: $credential->getIdToken(), + accessToken: $credential->getAccessToken(), + accessTokenScope: $scope, + accessTokenExpiration: $credential->getAccessTokenExpiration(), + refreshToken: $credential->getRefreshToken(), + )); + } + } + } + + public function setCredential( + ?CredentialEntityContract $credential = null, + ): self { + $this->stopImpersonating(); + + $this->credential = $credential; + + return $this; + } + + /** + * @param CredentialEntityContract $credential + */ + public function setImpersonating( + CredentialEntityContract $credential, + ): self { + $this->impersonationSource = self::SOURCE_TOKEN; + $this->impersonating = $credential; + + return $this; + } + + public function setUser( + Authenticatable $user, + ): void { + if ($this->isImpersonating()) { + if ($this->getImposter()?->getUser() === $user) { + return; + } + + $this->stopImpersonating(); + } + + $credential = $this->getCredential() ?? CredentialEntity::create(); + $credential->setUser($user); + + $this->setCredential($credential); + } + + public function user(): ?Authenticatable + { + if ($this->isImpersonating()) { + return $this->getImposter()?->getUser(); + } + + $currentUser = $this->getCredential()?->getUser(); + + if ($currentUser instanceof Authenticatable) { + return $currentUser; + } + + $token = $this->find(); + + if ($token instanceof CredentialEntityContract) { + $this->login($token); + + return $this->getCredential()?->getUser(); + } + + return null; + } +} diff --git a/src/Guards/AuthorizationGuardContract.php b/src/Guards/AuthorizationGuardContract.php new file mode 100644 index 00000000..8b762eef --- /dev/null +++ b/src/Guards/AuthorizationGuardContract.php @@ -0,0 +1,33 @@ +user()) instanceof Authenticatable) { + return $user; + } + + throw new AuthenticationException(AuthenticationException::UNAUTHENTICATED); + } + + final public function check(): bool + { + return $this->hasUser(); + } + + final public function getImposter(): ?CredentialEntityContract + { + return $this->impersonating; + } + + final public function getImposterSource(): ?int + { + return $this->impersonationSource; + } + + final public function getName(): string + { + return $this->name; + } + + final public function getProvider(): UserProvider + { + if ($this->provider instanceof UserProvider) { + return $this->provider; + } + + $providerName = $this->config['provider'] ?? ''; + + if (! is_string($providerName) || '' === $providerName) { + // @codeCoverageIgnoreStart + throw new GuardException(GuardExceptionContract::USER_PROVIDER_UNCONFIGURED); + // @codeCoverageIgnoreEnd + } + + $providerName = trim($providerName); + $provider = app('auth')->createUserProvider($providerName); + + if ($provider instanceof UserProvider) { + $this->provider = $provider; + + return $provider; + } + + // @codeCoverageIgnoreStart + throw new GuardException(sprintf(GuardExceptionContract::USER_PROVIDER_UNAVAILABLE, $providerName)); + // @codeCoverageIgnoreEnd + } + + final public function getRefreshedUser(): ?Authenticatable + { + $this->refreshUser(); + + return $this->user(); + } + + final public function getSession(): Session + { + if (! $this->session instanceof Session) { + $store = app('session.store'); + $request = app('request'); + + if (! $request->hasSession(true)) { + $request->setLaravelSession($store); + } + + if (! $store->isStarted()) { + $store->start(); + } + + $this->session = $store; + } + + return $this->session; + } + + final public function guest(): bool + { + return ! $this->check(); + } + + final public function hasPermission( + string $permission, + ?CredentialEntityContract $credential = null, + ): bool { + $permission = trim($permission); + + if ('*' === $permission) { + return true; + } + + $available = $credential?->getAccessTokenDecoded() ?? $this->getCredential()?->getAccessTokenDecoded() ?? []; + $available = $available['permissions'] ?? []; + + /** + * @var mixed $available + */ + if (! is_array($available) || [] === $available) { + return false; + } + + return in_array($permission, $available, true); + } + + final public function hasScope( + string $scope, + ?CredentialEntityContract $credential = null, + ): bool { + $scope = trim($scope); + + if ('*' === $scope) { + return true; + } + + $available = $credential?->getAccessTokenScope() ?? $this->getCredential()?->getAccessTokenScope() ?? []; + + if ([] !== $available) { + return in_array($scope, $available, true); + } + + return false; + } + + final public function hasUser(): bool + { + return $this->user() instanceof Authenticatable; + } + + final public function id(): string | null + { + $user = $this->user()?->getAuthIdentifier(); + + if (is_string($user) || is_int($user)) { + return (string) $user; + } + + return null; + } + + final public function isImpersonating(): bool + { + return $this->impersonating instanceof CredentialEntityContract; + } + + final public function management(): ManagementInterface + { + return $this->sdk()->management(); + } + + final public function processToken( + string $token, + ): ?array { + $event = new TokenVerificationAttempting($token); + event($event); + $token = $event->getToken(); + $decoded = null; + + try { + $decoded = $this->sdk()->decode(token: $token, tokenType: Token::TYPE_ACCESS_TOKEN)->toArray(); + } catch (InvalidTokenException $invalidTokenException) { + event(new TokenVerificationFailed($token, $invalidTokenException)); + + return null; + } + + event(new TokenVerificationSucceeded($token, $decoded)); + + return $decoded; + } + + final public function sdk( + bool $reset = false, + ): Auth0Interface { + if (! $this->sdk instanceof InstanceEntityContract || $reset) { + $configurationName = $this->config['configuration'] ?? $this->name; + + $this->sdk = InstanceEntity::create( + guardConfigurationName: $configurationName, + ); + } + + return $this->sdk->getSdk(); + } + + final public function stopImpersonating(): void + { + $this->impersonating = null; + $this->impersonationSource = null; + } + + /** + * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + * + * @param array $credentials + */ + final public function validate( + array $credentials = [], + ): bool { + return false; + } + + final public function viaRemember(): bool + { + return false; + } + + abstract public function find(): ?CredentialEntityContract; + + abstract public function forgetUser(): self; + + abstract public function getCredential(): ?CredentialEntityContract; + + abstract public function login(?CredentialEntityContract $credential): GuardContract; + + abstract public function logout(): GuardContract; + + abstract public function refreshUser(): void; + + abstract public function setCredential(?CredentialEntityContract $credential = null): GuardContract; + + /** + * Toggle the Guard's impersonation state. This should only be used by the Impersonate trait, and is not intended for use by end-users. It is public to allow for testing. + * + * @param CredentialEntityContract $credential + */ + abstract public function setImpersonating( + CredentialEntityContract $credential, + ): self; + + abstract public function setUser( + Authenticatable $user, + ): void; + + abstract public function user(): ?Authenticatable; + + /** + * Normalize a user model object for easier storage or comparison. + * + * @param Authenticatable $user User model object. + * + * @throws Exception If the user model object cannot be normalized. + * + * @return array Normalized user model object. + * + * @psalm-suppress TypeDoesNotContainType, UndefinedDocblockClass, UndefinedInterfaceMethod + * + * @codeCoverageIgnore + */ + protected function normalizeUserArray( + Authenticatable $user, + ): array { + $response = null; + $implements = class_implements($user, true); + $implements = is_array($implements) ? $implements : []; + + if (isset($implements[JsonSerializable::class])) { + /** + * @var JsonSerializable $user + */ + $response = json_encode($user->jsonSerialize(), JSON_THROW_ON_ERROR); + } + + if (null === $response && isset($implements[Jsonable::class])) { + /** + * @var Jsonable $user + */ + $response = $user->toJson(); + } + + if (null === $response && isset($implements[Arrayable::class])) { + /** + * @var Arrayable $user + */ + try { + $response = json_encode($user->toArray(), JSON_THROW_ON_ERROR); + } catch (\Exception) { + } + } + + // if (null === $response && (new ReflectionClass($user))->hasMethod('attributesToArray')) { + // try { + // // @phpstan-ignore-next-line + // $response = json_encode($user->attributesToArray(), JSON_THROW_ON_ERROR); + // } catch (\Exception) { + // } + // } + + if (is_string($response)) { + try { + $response = json_decode($response, true, 512, JSON_THROW_ON_ERROR); + + if (is_array($response) && [] !== $response) { + /** + * @var array $response + */ + return $response; + } + } catch (\Exception) { + } + } + + throw new GuardException(GuardExceptionContract::USER_MODEL_NORMALIZATION_FAILURE); + } +} diff --git a/src/Contract/Auth/Guard.php b/src/Guards/GuardContract.php similarity index 50% rename from src/Contract/Auth/Guard.php rename to src/Guards/GuardContract.php index ab10c48e..6b44fcf2 100644 --- a/src/Contract/Auth/Guard.php +++ b/src/Guards/GuardContract.php @@ -2,15 +2,32 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Auth; +namespace Auth0\Laravel\Guards; -use Auth0\Laravel\Contract\Entities\Credential; +use Auth0\Laravel\Entities\CredentialEntityContract; +use Auth0\SDK\Contract\API\ManagementInterface; +use Auth0\SDK\Contract\Auth0Interface; use Illuminate\Auth\AuthenticationException; -use Illuminate\Contracts\Auth\{Authenticatable, Guard as GuardContract, UserProvider}; +use Illuminate\Contracts\Auth\{Authenticatable, UserProvider}; +use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Contracts\Session\Session; +use Psr\Container\{ContainerExceptionInterface, NotFoundExceptionInterface}; -interface Guard extends GuardContract +/** + * @api + */ +interface GuardContract { + /** + * @var int Credential source is a stateful session. + */ + public const SOURCE_SESSION = 2; + + /** + * @var int Credential source is a stateless token. + */ + public const SOURCE_TOKEN = 1; + /** * Returns the currently authenticated user for the guard. If none is set, throws an exception. * @@ -23,15 +40,6 @@ public function authenticate(): Authenticatable; */ public function check(): bool; - /** - * Searches for an available credential from a specified source in the current request context. - * - * @param int $source The source to search for a credential in. One of the Guard::SOURCE_* constants. - */ - public function find( - int $source, - ): ?Credential; - /** * Clears the currently authenticated user for the guard. This will not clear a session, if one is set. */ @@ -40,18 +48,28 @@ public function forgetUser(): self; /** * Returns the Guard's currently configured Credential, or null if no Credential is configured. */ - public function getCredential(): ?Credential; + public function getCredential(): ?CredentialEntityContract; /** - * Returns the Guard's currently configured credential source, or null if no source is configured. One of the Guard::SOURCE_* constants. + * Get the currently impersonated user, if any. */ - public function getCredentialSource(): ?int; + public function getImposter(): ?CredentialEntityContract; + + /** + * Returns the source context from which the guard is currently impersonating another user. + */ + public function getImposterSource(): ?int; /** * Returns the Guard's currently configured UserProvider. */ public function getProvider(): UserProvider; + /** + * Queries the /userinfo endpoint, updates the currently authenticated user for the guard, and returns a new Authenticatable user representing the updated user. + */ + public function getRefreshedUser(): ?Authenticatable; + /** * Returns a Laravel session store from the current Request context. Note that this will start a session if one is not already started. */ @@ -63,14 +81,25 @@ public function getSession(): Session; public function guest(): bool; /** - * Returns whether a provided credential has a specified scope. + * Returns whether a credential has a specified permission, such as "read:users". Note that RBAC must be enabled for this to work. + * + * @param string $permission The permission to check for. + * @param null|CredentialEntityContract $credential Optional. The Credential to check. If omitted, the currently authenticated Credential will be used. + */ + public function hasPermission( + string $permission, + ?CredentialEntityContract $credential = null, + ): bool; + + /** + * Returns whether a credential has a specified scope, such as "read:users". Note that RBAC must be enabled for this to work. * - * @param string $scope The scope to check for. - * @param Credential $credential The Credential to check. + * @param string $scope The scope to check for. + * @param null|CredentialEntityContract $credential Optional. The Credential to check. If omitted, the currently authenticated Credential will be used. */ public function hasScope( string $scope, - Credential $credential, + ?CredentialEntityContract $credential = null, ): bool; /** @@ -83,22 +112,30 @@ public function hasUser(): bool; */ public function id(): int | string | null; + /** + * Returns whether the user is currently impersonating another user. + */ + public function isImpersonating(): bool; + /** * Sets the currently authenticated user for the guard. * - * @param null|Credential $credential The Credential to set. - * @param null|int $source The source of the Credential. + * @param null|CredentialEntityContract $credential Optional. The credential to use. */ public function login( - ?Credential $credential, - ?int $source = null, - ): self; + ?CredentialEntityContract $credential, + ): ?self; /** * Clears the currently authenticated user for the guard. If a credential is set, it will be cleared. If a session is set, it will be cleared. */ public function logout(): self; + /** + * Get an Auth0 Management API instance. + */ + public function management(): ManagementInterface; + /** * Processes a JWT token and returns the decoded token, or null if the token is invalid. * @@ -116,23 +153,34 @@ public function processToken( public function refreshUser(): void; /** - * Sets the Guard's currently configured Credential and source. + * Get an Auth0 PHP SDK instance. + * + * @param bool $reset Optional. Whether to reset the SDK instance. * - * @param null|Credential $credential The Credential to set. - * @param null|int $source The source of the Credential. + * @throws BindingResolutionException If the Auth0 class cannot be resolved. + * @throws NotFoundExceptionInterface If the Auth0 service cannot be found. + * @throws ContainerExceptionInterface If the Auth0 service cannot be resolved. + * + * @return Auth0Interface Auth0 PHP SDK instance. */ - public function setCredential( - ?Credential $credential, - ?int $source = null, - ): self; + public function sdk( + bool $reset = false, + ): Auth0Interface; + + /** + * Sets the guard's currently configured credential. + * + * @param null|CredentialEntityContract $credential Optional. The credential to assign. + */ + public function setCredential(?CredentialEntityContract $credential = null): self; /** * Toggle the Guard's impersonation state. This should only be used by the Impersonate trait, and is not intended for use by end-users. It is public to allow for testing. * - * @param bool $impersonate Whether or not the Guard should be impersonating. + * @param CredentialEntityContract $credential */ public function setImpersonating( - bool $impersonate = false, + CredentialEntityContract $credential, ): self; /** @@ -144,6 +192,11 @@ public function setUser( Authenticatable $user, ): void; + /** + * Stop impersonating a user. + */ + public function stopImpersonating(): void; + /** * Returns the currently authenticated user for the guard, if available. */ diff --git a/src/Http/Controller/ControllerAbstract.php b/src/Http/Controller/ControllerAbstract.php deleted file mode 100644 index 2ecb57ef..00000000 --- a/src/Http/Controller/ControllerAbstract.php +++ /dev/null @@ -1,29 +0,0 @@ -getSdk(); - } - - // @phpstan-ignore-next-line - return Auth0::getSdk(); - } -} diff --git a/src/Http/Controller/Stateful/Login.php b/src/Http/Controller/Stateful/Login.php deleted file mode 100644 index 1979b4b3..00000000 --- a/src/Http/Controller/Stateful/Login.php +++ /dev/null @@ -1,47 +0,0 @@ -guard(); - - if (! $guard instanceof GuardContract) { - return redirect()->intended(config('auth0.routes.home', '/')); - } - - $loggedIn = $guard->check() ? true : $guard->find(Guard::SOURCE_SESSION) instanceof Credential; - - if ($loggedIn) { - return redirect()->intended(config('auth0.routes.home', '/')); - } - - $event = new LoginAttempting(); - event($event); - - $url = $this->getSdk()->login( - params: $event->getParameters(), - ); - - return redirect()->away($url); - } -} diff --git a/src/Http/Controller/Stateful/Logout.php b/src/Http/Controller/Stateful/Logout.php deleted file mode 100644 index e665870a..00000000 --- a/src/Http/Controller/Stateful/Logout.php +++ /dev/null @@ -1,49 +0,0 @@ -guard(); - - if (! $guard instanceof GuardContract) { - return redirect()->intended(config('auth0.routes.home', '/')); - } - - $loggedIn = $guard->check() ? true : $guard->find(Guard::SOURCE_SESSION) instanceof Credential; - - if ($loggedIn) { - session()->invalidate(); - $guard->logout(); - - $route = config('auth0.routes.home'); - $route = is_string($route) ? $route : '/'; - $route = (string) url(http://github.com/$route); /** @phpstan-ignore-line */ - $url = $this->getSdk()->authentication()->getLogoutLink($route); - - return redirect()->away($url); - } - - return redirect()->intended(config('auth0.routes.home', '/')); - } -} diff --git a/src/Http/Middleware/MiddlewareAbstract.php b/src/Http/Middleware/MiddlewareAbstract.php deleted file mode 100644 index 27831ad3..00000000 --- a/src/Http/Middleware/MiddlewareAbstract.php +++ /dev/null @@ -1,21 +0,0 @@ -guard(); - - if (! $guard instanceof GuardContract) { - abort(Response::HTTP_INTERNAL_SERVER_ERROR, 'Internal Server Error'); - } - - /** @var Guard $guard */ - event(new StatefulRequest($request, $guard)); - - $credential = $guard->find(Guard::SOURCE_SESSION); - - if ($credential instanceof Credential) { - if ('' === $scope || $guard->hasScope($scope, $credential)) { - $guard->login($credential, Guard::SOURCE_SESSION); - - return $next($request); - } - - abort(Response::HTTP_FORBIDDEN, 'Forbidden'); - } - - return redirect() - ->setIntendedUrl($request->fullUrl()) - ->to(config('auth0.routes.login', 'login')); // @phpstan-ignore-line - } -} diff --git a/src/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Http/Middleware/Stateful/AuthenticateOptional.php deleted file mode 100644 index 1a34186d..00000000 --- a/src/Http/Middleware/Stateful/AuthenticateOptional.php +++ /dev/null @@ -1,46 +0,0 @@ -guard(); - - if (! $guard instanceof GuardContract) { - abort(Response::HTTP_INTERNAL_SERVER_ERROR, 'Internal Server Error'); - } - - /** @var Guard $guard */ - event(new StatefulRequest($request, $guard)); - - $credential = $guard->find(Guard::SOURCE_SESSION); - - if ($credential instanceof Credential && ('' === $scope || $guard->hasScope($scope, $credential))) { - $guard->login($credential, Guard::SOURCE_SESSION); - } - - return $next($request); - } -} diff --git a/src/Http/Middleware/Stateless/Authorize.php b/src/Http/Middleware/Stateless/Authorize.php deleted file mode 100644 index 1653200b..00000000 --- a/src/Http/Middleware/Stateless/Authorize.php +++ /dev/null @@ -1,51 +0,0 @@ -guard(); - - if (! $guard instanceof GuardContract) { - return $next($request); - } - - /** @var Guard $guard */ - event(new StatelessRequest($request, $guard)); - - $credential = $guard->find(Guard::SOURCE_TOKEN); - - if ($credential instanceof Credential) { - if ('' === $scope || $guard->hasScope($scope, $credential)) { - $guard->login($credential, Guard::SOURCE_TOKEN); - - return $next($request); - } - - abort(Response::HTTP_FORBIDDEN, 'Forbidden'); - } - - abort(Response::HTTP_UNAUTHORIZED, 'Unauthorized'); - } -} diff --git a/src/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Http/Middleware/Stateless/AuthorizeOptional.php deleted file mode 100644 index 4151cdeb..00000000 --- a/src/Http/Middleware/Stateless/AuthorizeOptional.php +++ /dev/null @@ -1,46 +0,0 @@ -guard(); - - if (! $guard instanceof GuardContract) { - return $next($request); - } - - /** @var Guard $guard */ - event(new StatelessRequest($request, $guard)); - - $credential = $guard->find(Guard::SOURCE_TOKEN); - - if ($credential instanceof Credential && ('' === $scope || $guard->hasScope($scope, $credential))) { - $guard->login($credential, Guard::SOURCE_TOKEN); - - return $next($request); - } - - return $next($request); - } -} diff --git a/src/Middleware/AuthenticateMiddleware.php b/src/Middleware/AuthenticateMiddleware.php new file mode 100644 index 00000000..4d81dab8 --- /dev/null +++ b/src/Middleware/AuthenticateMiddleware.php @@ -0,0 +1,14 @@ +guard(); + $scope = trim($scope); + + if (! $guard instanceof GuardContract) { + abort(Response::HTTP_INTERNAL_SERVER_ERROR, 'Internal Server Error'); + } + + /** @var Guard $guard */ + event(new StatefulMiddlewareRequest($request, $guard)); + + $credential = $guard->find(GuardContract::SOURCE_SESSION); + + if ($credential instanceof CredentialEntityContract) { + if ('' === $scope || $guard->hasScope($scope, $credential)) { + $guard->login($credential); + + return $next($request); + } + + abort(Response::HTTP_FORBIDDEN, 'Forbidden'); + } + + return redirect() + ->setIntendedUrl($request->fullUrl()) + ->to('/login'); // @phpstan-ignore-line + } +} diff --git a/src/Contract/Http/Middleware/Stateful/Authenticate.php b/src/Middleware/AuthenticateMiddlewareContract.php similarity index 58% rename from src/Contract/Http/Middleware/Stateful/Authenticate.php rename to src/Middleware/AuthenticateMiddlewareContract.php index 93cdb41a..c821d0cb 100644 --- a/src/Contract/Http/Middleware/Stateful/Authenticate.php +++ b/src/Middleware/AuthenticateMiddlewareContract.php @@ -2,13 +2,18 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Http\Middleware\Stateful; +namespace Auth0\Laravel\Middleware; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; -interface Authenticate +/** + * @deprecated 7.8.0 This middleware is no longer necessary when using Auth0\Laravel\Guards\AuthenticationGuard. Use Laravel's standard `auth` middleware instead. + * + * @api + */ +interface AuthenticateMiddlewareContract extends MiddlewareContract { /** * Handle an incoming request. diff --git a/src/Middleware/AuthenticateOptionalMiddleware.php b/src/Middleware/AuthenticateOptionalMiddleware.php new file mode 100644 index 00000000..78104074 --- /dev/null +++ b/src/Middleware/AuthenticateOptionalMiddleware.php @@ -0,0 +1,14 @@ +guard(); + + if (! $guard instanceof GuardContract) { + abort(Response::HTTP_INTERNAL_SERVER_ERROR, 'Internal Server Error'); + } + + /** @var Guard $guard */ + event(new StatefulMiddlewareRequest($request, $guard)); + + $credential = $guard->find(GuardContract::SOURCE_SESSION); + + if ($credential instanceof CredentialEntityContract && ('' === $scope || $guard->hasScope($scope, $credential))) { + $guard->login($credential); + } + + return $next($request); + } +} diff --git a/src/Contract/Http/Middleware/Stateless/Authorize.php b/src/Middleware/AuthenticateOptionalMiddlewareContract.php similarity index 61% rename from src/Contract/Http/Middleware/Stateless/Authorize.php rename to src/Middleware/AuthenticateOptionalMiddlewareContract.php index a8282410..aaed8377 100644 --- a/src/Contract/Http/Middleware/Stateless/Authorize.php +++ b/src/Middleware/AuthenticateOptionalMiddlewareContract.php @@ -2,13 +2,18 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Http\Middleware\Stateless; +namespace Auth0\Laravel\Middleware; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; -interface Authorize +/** + * @deprecated 7.8.0 This middleware is no longer necessary when using Auth0\Laravel\Guards\AuthenticationGuard. + * + * @api + */ +interface AuthenticateOptionalMiddlewareContract extends MiddlewareContract { /** * Handle an incoming request. diff --git a/src/Middleware/AuthenticatorMiddleware.php b/src/Middleware/AuthenticatorMiddleware.php new file mode 100644 index 00000000..f4177f90 --- /dev/null +++ b/src/Middleware/AuthenticatorMiddleware.php @@ -0,0 +1,26 @@ +shouldUse('auth0-session'); + + return $next($request); + } +} diff --git a/src/Middleware/AuthenticatorMiddlewareContract.php b/src/Middleware/AuthenticatorMiddlewareContract.php new file mode 100644 index 00000000..5ddb10a0 --- /dev/null +++ b/src/Middleware/AuthenticatorMiddlewareContract.php @@ -0,0 +1,12 @@ +guard(); + + if (! $guard instanceof GuardContract) { + return $next($request); + } + + /** @var Guard $guard */ + event(new StatelessMiddlewareRequest($request, $guard)); + + $credential = $guard->find(GuardContract::SOURCE_TOKEN); + + if ($credential instanceof CredentialEntityContract) { + if ('' === $scope || $guard->hasScope($scope, $credential)) { + $guard->login($credential); + + return $next($request); + } + + abort(Response::HTTP_FORBIDDEN, 'Forbidden'); + } + + abort(Response::HTTP_UNAUTHORIZED, 'Unauthorized'); + } +} diff --git a/src/Contract/Http/Middleware/Stateless/AuthorizeOptional.php b/src/Middleware/AuthorizeMiddlewareContract.php similarity index 58% rename from src/Contract/Http/Middleware/Stateless/AuthorizeOptional.php rename to src/Middleware/AuthorizeMiddlewareContract.php index cef476d4..30f26e51 100644 --- a/src/Contract/Http/Middleware/Stateless/AuthorizeOptional.php +++ b/src/Middleware/AuthorizeMiddlewareContract.php @@ -2,13 +2,18 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Http\Middleware\Stateless; +namespace Auth0\Laravel\Middleware; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; -interface AuthorizeOptional +/** + * @deprecated 7.8.0 This middleware is no longer necessary when using Auth0\Laravel\Guards\AuthorizationGuard. Use Laravel's standard `auth` middleware instead. + * + * @api + */ +interface AuthorizeMiddlewareContract extends MiddlewareContract { /** * Handle an incoming request. diff --git a/src/Middleware/AuthorizeOptionalMiddleware.php b/src/Middleware/AuthorizeOptionalMiddleware.php new file mode 100644 index 00000000..4db5ed11 --- /dev/null +++ b/src/Middleware/AuthorizeOptionalMiddleware.php @@ -0,0 +1,14 @@ +guard(); + + if (! $guard instanceof GuardContract) { + return $next($request); + } + + /** @var Guard $guard */ + event(new StatelessMiddlewareRequest($request, $guard)); + + $credential = $guard->find(GuardContract::SOURCE_TOKEN); + + if ($credential instanceof CredentialEntityContract && ('' === $scope || $guard->hasScope($scope, $credential))) { + $guard->login($credential); + + return $next($request); + } + + return $next($request); + } +} diff --git a/src/Contract/Http/Middleware/Stateful/AuthenticateOptional.php b/src/Middleware/AuthorizeOptionalMiddlewareContract.php similarity index 62% rename from src/Contract/Http/Middleware/Stateful/AuthenticateOptional.php rename to src/Middleware/AuthorizeOptionalMiddlewareContract.php index a8abdd39..ee62c7a3 100644 --- a/src/Contract/Http/Middleware/Stateful/AuthenticateOptional.php +++ b/src/Middleware/AuthorizeOptionalMiddlewareContract.php @@ -2,13 +2,18 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Http\Middleware\Stateful; +namespace Auth0\Laravel\Middleware; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; -interface AuthenticateOptional +/** + * @deprecated 7.8.0 This middleware is no longer necessary when using Auth0\Laravel\Guards\AuthorizationGuard. + * + * @api + */ +interface AuthorizeOptionalMiddlewareContract extends MiddlewareContract { /** * Handle an incoming request. diff --git a/src/Middleware/AuthorizerMiddleware.php b/src/Middleware/AuthorizerMiddleware.php new file mode 100644 index 00000000..3701edf1 --- /dev/null +++ b/src/Middleware/AuthorizerMiddleware.php @@ -0,0 +1,26 @@ +shouldUse('auth0-api'); + + return $next($request); + } +} diff --git a/src/Middleware/AuthorizerMiddlewareContract.php b/src/Middleware/AuthorizerMiddlewareContract.php new file mode 100644 index 00000000..1fe11534 --- /dev/null +++ b/src/Middleware/AuthorizerMiddlewareContract.php @@ -0,0 +1,12 @@ +shouldUse($this->defaultGuard); - - return $next($request); + $guard = $this->defaultGuard; } auth()->shouldUse($guard); diff --git a/src/Middleware/GuardMiddlewareContract.php b/src/Middleware/GuardMiddlewareContract.php new file mode 100644 index 00000000..b903a45e --- /dev/null +++ b/src/Middleware/GuardMiddlewareContract.php @@ -0,0 +1,12 @@ + + */ + final public static function json(ResponseInterface $response): ?array + { + if (! in_array($response->getStatusCode(), [200, 201], true)) { + return null; + } + + $json = json_decode((string) $response->getBody(), true); + + if (! is_array($json)) { + return null; + } + + return $json; + } + + /** + * Register the SDK's authentication routes and controllers. + * + * @param string $authenticationGuard The name of the authentication guard to use. + */ + final public static function routes( + string $authenticationGuard = 'auth0-session', + ): void { + Route::group(['middleware' => ['web', 'guard:' . $authenticationGuard]], static function (): void { + Route::get('/login', LoginController::class)->name('login'); + Route::get('/logout', LogoutController::class)->name('logout'); + Route::get('/callback', CallbackController::class)->name('callback'); + }); + } +} diff --git a/src/ServiceContract.php b/src/ServiceContract.php new file mode 100644 index 00000000..fa87aa0a --- /dev/null +++ b/src/ServiceContract.php @@ -0,0 +1,11 @@ +mergeConfigFrom(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'config', 'auth0.php']), 'auth0'); - $this->publishes([implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'config', 'auth0.php']) => config_path('auth0.php')], 'auth0-config'); - - $auth->extend('auth0.guard', static fn (Application $app, string $name, array $config): Guard => new Guard($name, $config)); - $auth->provider('auth0.provider', static fn (Application $app, array $config): Provider => new Provider($config)); - - $router->aliasMiddleware('auth0.authenticate.optional', AuthenticateOptional::class); - $router->aliasMiddleware('auth0.authenticate', Authenticate::class); - $router->aliasMiddleware('auth0.authorize.optional', AuthorizeOptional::class); - $router->aliasMiddleware('auth0.authorize', Authorize::class); - $router->aliasMiddleware('guard', ShouldUseMiddleware::class); - - return $this; - } - - public function provides() - { - return [ - Auth0::class, - Authenticate::class, - AuthenticateOptional::class, - Authorize::class, - AuthorizeOptional::class, - Callback::class, - Guard::class, - LaravelSession::class, - Login::class, - Logout::class, - Provider::class, - Repository::class, - ShouldUseMiddleware::class - ]; - } - - public function register(): self - { - $this->app->singleton(Auth0::class, static fn (): Auth0 => new Auth0()); - $this->app->singleton(Authenticate::class, static fn (): Authenticate => new Authenticate()); - $this->app->singleton(AuthenticateOptional::class, static fn (): AuthenticateOptional => new AuthenticateOptional()); - $this->app->singleton(Authorize::class, static fn (): Authorize => new Authorize()); - $this->app->singleton(AuthorizeOptional::class, static fn (): AuthorizeOptional => new AuthorizeOptional()); - $this->app->singleton(Callback::class, static fn (): Callback => new Callback()); - $this->app->singleton(Login::class, static fn (): Login => new Login()); - $this->app->singleton(Logout::class, static fn (): Logout => new Logout()); - $this->app->singleton(Provider::class, static fn (): Provider => new Provider()); - $this->app->singleton(Repository::class, static fn (): Repository => new Repository()); - $this->app->singleton(ShouldUseMiddleware::class, static fn (): ShouldUseMiddleware => new ShouldUseMiddleware()); - - $this->app->singleton('auth0', static fn (): Auth0 => app(Auth0::class)); - $this->app->singleton('auth0.guard', static fn (): Guard => app(Guard::class)); - $this->app->singleton('auth0.provider', static fn (): Provider => app(Provider::class)); - $this->app->singleton('auth0.repository', static fn (): Repository => app(Repository::class)); - - return $this; - } } diff --git a/src/ServiceProviderAbstract.php b/src/ServiceProviderAbstract.php new file mode 100644 index 00000000..fcf9884c --- /dev/null +++ b/src/ServiceProviderAbstract.php @@ -0,0 +1,234 @@ +mergeConfigFrom(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'config', 'auth0.php']), 'auth0'); + $this->publishes([implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'config', 'auth0.php']) => config_path('auth0.php')], 'auth0'); + + $auth->extend('auth0.authenticator', static fn (Application $app, string $name, array $config): AuthenticationGuard => new AuthenticationGuard($name, $config)); + $auth->extend('auth0.authorizer', static fn (Application $app, string $name, array $config): AuthorizationGuard => new AuthorizationGuard($name, $config)); + $auth->provider('auth0.provider', static fn (Application $app, array $config): UserProvider => new UserProvider($config)); + + $router->aliasMiddleware('guard', GuardMiddleware::class); + + $gate->define('scope', static function (Authenticatable $user, string $scope, ?GuardContract $guard = null): bool { + $guard ??= auth()->guard(); + + if (! $guard instanceof GuardContract) { + return false; + } + + return $guard->hasScope($scope); + }); + + $gate->define('permission', static function (Authenticatable $user, string $permission, ?GuardContract $guard = null): bool { + $guard ??= auth()->guard(); + + if (! $guard instanceof GuardContract) { + return false; + } + + return $guard->hasPermission($permission); + }); + + $gate->before(static function (?Authenticatable $user, ?string $ability) { + $guard = auth()->guard(); + + if (! $guard instanceof GuardContract || ! $user instanceof Authenticatable || ! is_string($ability)) { + return; + } + + if (str_starts_with($ability, 'scope:')) { + if ($guard->hasScope(mb_substr($ability, 6))) { + return Response::allow(); + } + + return Response::deny(); + } + + if (str_contains($ability, ':')) { + if ($guard->hasPermission($ability)) { + return Response::allow(); + } + + return Response::deny(); + } + }); + + $this->registerDeprecated($router, $auth); + $this->registerMiddleware($router); + $this->registerRoutes(); + + return $this; + } + + final public function provides() + { + return [ + Auth0::class, + AuthenticateMiddleware::class, + AuthenticateOptionalMiddleware::class, + AuthenticationGuard::class, + AuthenticatorMiddleware::class, + AuthorizationGuard::class, + AuthorizeMiddleware::class, + AuthorizeOptionalMiddleware::class, + AuthorizerMiddleware::class, + CacheBridge::class, + CacheItemBridge::class, + CallbackController::class, + Configuration::class, + Guard::class, + GuardMiddleware::class, + LoginController::class, + LogoutController::class, + Service::class, + SessionBridge::class, + UserProvider::class, + UserRepository::class, + ]; + } + + final public function register(): self + { + $this->registerGuards(); + + $this->app->singleton(Auth0::class, static fn (): Service => new Service()); + $this->app->singleton(Service::class, static fn (): Service => new Service()); + $this->app->singleton(Configuration::class, static fn (): Configuration => new Configuration()); + $this->app->singleton(Service::class, static fn (): Service => new Service()); + $this->app->singleton(AuthenticatorMiddleware::class, static fn (): AuthenticatorMiddleware => new AuthenticatorMiddleware()); + $this->app->singleton(AuthorizerMiddleware::class, static fn (): AuthorizerMiddleware => new AuthorizerMiddleware()); + $this->app->singleton(AuthenticateMiddleware::class, static fn (): AuthenticateMiddleware => new AuthenticateMiddleware()); + $this->app->singleton(AuthenticateOptionalMiddleware::class, static fn (): AuthenticateOptionalMiddleware => new AuthenticateOptionalMiddleware()); + $this->app->singleton(AuthorizeMiddleware::class, static fn (): AuthorizeMiddleware => new AuthorizeMiddleware()); + $this->app->singleton(AuthorizeOptionalMiddleware::class, static fn (): AuthorizeOptionalMiddleware => new AuthorizeOptionalMiddleware()); + $this->app->singleton(GuardMiddleware::class, static fn (): GuardMiddleware => new GuardMiddleware()); + $this->app->singleton(CallbackController::class, static fn (): CallbackController => new CallbackController()); + $this->app->singleton(LoginController::class, static fn (): LoginController => new LoginController()); + $this->app->singleton(LogoutController::class, static fn (): LogoutController => new LogoutController()); + $this->app->singleton(UserProvider::class, static fn (): UserProvider => new UserProvider()); + $this->app->singleton(UserRepository::class, static fn (): UserRepository => new UserRepository()); + + $this->app->singleton('auth0', static fn (): Service => app(Service::class)); + $this->app->singleton('auth0.repository', static fn (): UserRepository => app(UserRepository::class)); + + return $this; + } + + final public function registerDeprecated( + Router $router, + AuthManager $auth, + ): void { + $auth->extend('auth0.guard', static fn (Application $app, string $name, array $config): Guard => new Guard($name, $config)); + + $router->aliasMiddleware('auth0.authenticate.optional', AuthenticateOptionalMiddleware::class); + $router->aliasMiddleware('auth0.authenticate', AuthenticateMiddleware::class); + $router->aliasMiddleware('auth0.authorize.optional', AuthorizeOptionalMiddleware::class); + $router->aliasMiddleware('auth0.authorize', AuthorizeMiddleware::class); + } + + /** + * @codeCoverageIgnore + */ + final public function registerGuards(): void + { + if (true === config('auth0.registerGuards')) { + if (null === config('auth.guards.auth0-session')) { + config([ + 'auth.guards.auth0-session' => [ + 'driver' => 'auth0.authenticator', + 'configuration' => 'web', + 'provider' => 'auth0-provider', + ], + ]); + } + + if (null === config('auth.guards.auth0-api')) { + config([ + 'auth.guards.auth0-api' => [ + 'driver' => 'auth0.authorizer', + 'configuration' => 'api', + 'provider' => 'auth0-provider', + ], + ]); + } + + if (null === config('auth.providers.auth0-provider')) { + config([ + 'auth.providers.auth0-provider' => [ + 'driver' => 'auth0.provider', + 'repository' => 'auth0.repository', + ], + ]); + } + } + } + + /** + * @codeCoverageIgnore + * + * @param Router $router + */ + final public function registerMiddleware( + Router $router, + ): void { + if (true === config('auth0.registerMiddleware')) { + $kernel = $this->app->make(Kernel::class); + /** + * @var \Illuminate\Foundation\Http\Kernel $kernel + */ + if (! defined('AUTH0_LARAVEL_RUNNING_TESTS')) { + $kernel->pushMiddleware(AuthenticatorMiddleware::class); + $kernel->pushMiddleware(AuthenticatorMiddleware::class); + } + + $kernel->appendMiddlewareToGroup('web', AuthenticatorMiddleware::class); + $kernel->appendMiddlewareToGroup('api', AuthorizerMiddleware::class); + + $router->pushMiddlewareToGroup('web', AuthenticatorMiddleware::class); + $router->pushMiddlewareToGroup('api', AuthorizerMiddleware::class); + } + } + + final public function registerRoutes(): void + { + if (true === config('auth0.registerAuthenticationRoutes')) { + Route::group(['middleware' => 'web'], static function (): void { + Route::get('/login', LoginController::class)->name('login'); + Route::get('/logout', LogoutController::class)->name('logout'); + Route::get('/callback', CallbackController::class)->name('callback'); + }); + } + } +} diff --git a/src/ServiceProviderContract.php b/src/ServiceProviderContract.php new file mode 100644 index 00000000..16cc09c2 --- /dev/null +++ b/src/ServiceProviderContract.php @@ -0,0 +1,44 @@ + 'some-auth0-user-id', - 'azp' => 'some-auth0-application-client-id', + 'sub' => 'some-auth0-user-id', + 'azp' => 'some-auth0-application-client-id', 'scope' => '', ]; /** - * Set the currently logged in user for the application. + * Set the currently logged in user for the application. Only intended for unit testing. * * @param array $attributes The attributes to use for the user. * @param null|string $guard The guard to impersonate with. - * - * @return $this The current test case instance. + * @param ?int $source */ public function actingAsAuth0User( array $attributes = [], - ?string $guard = 'auth0', - ) { - $issued = time(); - $expires = $issued + 60 * 60; + ?string $guard = null, + ?int $source = GuardContract::SOURCE_TOKEN, + ): self { + $issued = time(); + $expires = $issued + 60 * 60; $timestamps = ['iat' => $issued, 'exp' => $expires]; $attributes = array_merge($this->defaultActingAsAttributes, $timestamps, $attributes); + $scope = $attributes['scope'] ? explode(' ', $attributes['scope']) : []; + unset($attributes['scope']); $instance = auth()->guard($guard); - $user = new Imposter($attributes); - if ($instance instanceof GuardContract) { - $credential = Credential::create( - user: $user, - accessTokenScope: $attributes['scope'] ? explode(' ', $attributes['scope']) : [], - ); + if (! $instance instanceof GuardContract) { + $user = new ImposterUser($attributes); + + return $this->actingAs($user, $guard); + } + + $provider = new UserProvider(); - $instance->setCredential($credential, Guard::SOURCE_IMPERSONATE); - $instance->setImpersonating(true); + if (GuardContract::SOURCE_SESSION === $source) { + $user = $provider->getRepository()->fromSession($attributes); + } else { + $user = $provider->getRepository()->fromAccessToken($attributes); } + $credential = CredentialEntity::create( + user: $user, + accessTokenScope: $scope, + ); + + $instance->setImpersonating($credential, $source); + return $this->actingAs($user, $guard); } diff --git a/src/Traits/Impersonate.php b/src/Traits/Impersonate.php index 6566498c..1539c879 100644 --- a/src/Traits/Impersonate.php +++ b/src/Traits/Impersonate.php @@ -4,33 +4,82 @@ namespace Auth0\Laravel\Traits; -use Auth0\Laravel\Contract\Auth\Guard; -use Auth0\Laravel\Entities\Credential; -use Auth0\Laravel\Model\Stateless\User; +use Auth0\Laravel\Entities\CredentialEntityContract; +use Auth0\Laravel\Guards\GuardContract; +use Auth0\Laravel\Users\ImposterUser; use Illuminate\Contracts\Auth\Authenticatable; +/** + * Pretend to be an authenticated user or a bearer token-established stateless user for the request. Only intended for unit testing. + * + * @api + */ trait Impersonate { /** - * Set the currently logged in user for the application. + * Pretend to be an authenticated user or a bearer token-established stateless user for the request. Only intended for unit testing. * - * @param Credential $credential The Credential to impersonate. - * @param null|int $source The source of the Credential. - * @param null|string $guard The guard to impersonate with. + * @param CredentialEntityContract $credential The Credential to impersonate. + * @param null|int $source The source of the Credential. + * @param null|string $guard The guard to impersonate with. * * @return $this The current test case instance. */ public function impersonate( - Credential $credential, + CredentialEntityContract $credential, ?int $source = null, ?string $guard = null, + ): self { + if (GuardContract::SOURCE_SESSION === $source || null === $source) { + $this->impersonateSession($credential, $guard); + } + + if (GuardContract::SOURCE_TOKEN === $source || null === $source) { + $this->impersonateToken($credential, $guard); + } + + return $this; + } + + /** + * Pretend to be an authenticated user for the request. Only intended for unit testing. + * + * @param CredentialEntityContract $credential The Credential to impersonate. + * @param null|string $guard The guard to impersonate with. + * + * @return $this The current test case instance. + */ + public function impersonateSession( + CredentialEntityContract $credential, + ?string $guard = null, + ): self { + $instance = auth()->guard($guard); + $user = $credential->getUser() ?? new ImposterUser([]); + + if ($instance instanceof GuardContract) { + $instance->setImpersonating($credential, GuardContract::SOURCE_SESSION); + } + + return $this->actingAs($user, $guard); + } + + /** + * Pretend to be a bearer token-established stateless user for the request. Only intended for unit testing. + * + * @param CredentialEntityContract $credential The Credential to impersonate. + * @param null|string $guard The guard to impersonate with. + * + * @return $this The current test case instance. + */ + public function impersonateToken( + CredentialEntityContract $credential, + ?string $guard = null, ): self { $instance = auth()->guard($guard); - $user = $credential->getUser() ?? new User([]); + $user = $credential->getUser() ?? new ImposterUser([]); - if ($instance instanceof Guard) { - $instance->setCredential($credential, $source); - $instance->setImpersonating(true); + if ($instance instanceof GuardContract) { + $instance->setImpersonating($credential, GuardContract::SOURCE_TOKEN); } return $this->actingAs($user, $guard); diff --git a/src/UserProvider.php b/src/UserProvider.php new file mode 100644 index 00000000..5f466b7e --- /dev/null +++ b/src/UserProvider.php @@ -0,0 +1,16 @@ +config[$key] ?? null; - } - - private function getRepositoryName(): string - { - return $this->repositoryName; - } - - private function resolveRepository( - ?string $repositoryName = null, - ): RepositoryContract { - $model = $repositoryName; - $model ??= $this->getConfiguration('model'); - $model ??= $this->getConfiguration('repository'); - $model ??= Repository::class; - - if ($model === $this->getRepositoryName()) { - return $this->getRepository(); - } - - if (! is_string($model)) { - throw new BindingResolutionException('The configured Repository could not be loaded.'); - } - - if (! app()->bound($model)) { - try { - app()->make($model); - } catch (BindingResolutionException) { - throw new BindingResolutionException(sprintf('The configured Repository %s could not be loaded.', $model)); - } - } - - $this->setRepositoryName($model); - - return $this->repository = app($model); - } - - private function setConfiguration( - string $key, - mixed $value, - ): void { - $this->config[$key] = $value; - } - - private function setRepositoryName(string $repositoryName): void - { - $this->setConfiguration('model', $repositoryName); - $this->repositoryName = $repositoryName; - } - - public function getRepository(): RepositoryContract + final public function getRepository(): UserRepositoryContract { return $this->repository ?? $this->resolveRepository(); } @@ -84,7 +38,7 @@ public function getRepository(): RepositoryContract * * @param array $credentials */ - public function retrieveByCredentials(array $credentials): ?Authenticatable + final public function retrieveByCredentials(array $credentials): ?Authenticatable { return $this->getRepository()->fromSession($credentials); } @@ -96,7 +50,7 @@ public function retrieveByCredentials(array $credentials): ?Authenticatable * * @param mixed $identifier */ - public function retrieveById($identifier): ?Authenticatable + final public function retrieveById($identifier): ?Authenticatable { return null; } @@ -109,7 +63,7 @@ public function retrieveById($identifier): ?Authenticatable * @param mixed $identifier * @param mixed $token */ - public function retrieveByToken($identifier, $token): ?Authenticatable + final public function retrieveByToken($identifier, $token): ?Authenticatable { // @phpstan-ignore-next-line if (! is_string($token)) { @@ -118,24 +72,16 @@ public function retrieveByToken($identifier, $token): ?Authenticatable $guard = auth()->guard(); - if (! $guard instanceof Guard) { + if (! $guard instanceof GuardContract) { return null; } - $user = $guard->processToken( - token: $token, - ); - - if (null === $user) { - return null; - } + $user = $guard->processToken($token); - return $this->getRepository()->fromAccessToken( - user: $user, - ); + return null !== $user ? $this->getRepository()->fromAccessToken($user) : null; } - public function setRepository(string $repository): void + final public function setRepository(string $repository): void { $this->resolveRepository($repository); } @@ -148,7 +94,7 @@ public function setRepository(string $repository): void * @param Authenticatable $user * @param mixed $token */ - public function updateRememberToken(Authenticatable $user, $token): void + final public function updateRememberToken(Authenticatable $user, $token): void { } @@ -158,10 +104,63 @@ public function updateRememberToken(Authenticatable $user, $token): void * @param Authenticatable $user * @param array $credentials */ - public function validateCredentials( + final public function validateCredentials( Authenticatable $user, array $credentials, ): bool { return false; } + + protected function getConfiguration( + string $key, + ): array | string | null { + return $this->config[$key] ?? null; + } + + protected function getRepositoryName(): string + { + return $this->repositoryName; + } + + protected function resolveRepository( + ?string $repositoryName = null, + ): UserRepositoryContract { + $model = $repositoryName; + $model ??= $this->getConfiguration('model'); + $model ??= $this->getConfiguration('repository'); + $model ??= UserRepository::class; + + if ($model === $this->getRepositoryName()) { + return $this->getRepository(); + } + + if (! is_string($model)) { + throw new BindingResolutionException('The configured Repository could not be loaded.'); + } + + if (! app()->bound($model)) { + try { + app()->make($model); + } catch (BindingResolutionException) { + throw new BindingResolutionException(sprintf('The configured Repository %s could not be loaded.', $model)); + } + } + + $this->setRepositoryName($model); + + return $this->repository = app($model); + } + + protected function setConfiguration( + string $key, + string $value, + ): void { + $this->config[$key] = $value; + } + + protected function setRepositoryName(string $repositoryName): void + { + $this->setConfiguration('model', $repositoryName); + $this->repositoryName = $repositoryName; + } } diff --git a/src/UserProviderContract.php b/src/UserProviderContract.php new file mode 100644 index 00000000..6025a28e --- /dev/null +++ b/src/UserProviderContract.php @@ -0,0 +1,18 @@ +fill($attributes); } @@ -19,21 +20,12 @@ public function __get(string $key): mixed return $this->getAttribute($key); } - public function __set(string $key, $value): void + public function __set(string $key, mixed $value): void { $this->setAttribute($key, $value); } - final public function fill(array $attributes): self - { - foreach ($attributes as $key => $value) { - $this->setAttribute($key, $value); - } - - return $this; - } - - final public function getAttribute(string $key, $default = null): mixed + final public function getAttribute(string $key, mixed $default = null): mixed { return $this->attributes[$key] ?? $default; } @@ -73,19 +65,14 @@ final public function jsonSerialize(): mixed return $this->attributes; } - final public function setAttribute(string $key, mixed $value): self - { - $this->attributes[$key] = $value; - - return $this; - } - /** - * @inheritdoc - * * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter */ - final public function setRememberToken($value): void + final public function setRememberToken(mixed $value): void { } + + abstract public function fill(array $attributes): self; + + abstract public function setAttribute(string $key, mixed $value): self; } diff --git a/src/Contract/Model/User.php b/src/Users/UserContract.php similarity index 72% rename from src/Contract/Model/User.php rename to src/Users/UserContract.php index 97167eeb..b078f409 100644 --- a/src/Contract/Model/User.php +++ b/src/Users/UserContract.php @@ -2,11 +2,12 @@ declare(strict_types=1); -namespace Auth0\Laravel\Contract\Model; +namespace Auth0\Laravel\Users; +use Illuminate\Contracts\Auth\Authenticatable; use JsonSerializable; -interface User extends JsonSerializable +interface UserContract extends Authenticatable, JsonSerializable { /** * @param array $attributes attributes representing the user data @@ -26,7 +27,7 @@ public function __get(string $key): mixed; * @param mixed $value * @param string $key */ - public function __set(string $key, $value): void; + public function __set(string $key, mixed $value): void; /** * Fill the model with an array of attributes. @@ -38,10 +39,10 @@ public function fill(array $attributes): self; /** * Get an attribute from the model. * - * @param null|mixed $default - * @param string $key + * @param mixed $default + * @param string $key */ - public function getAttribute(string $key, $default = null): mixed; + public function getAttribute(string $key, mixed $default = null): mixed; /** * Set a given attribute on the model. diff --git a/src/Users/UserTrait.php b/src/Users/UserTrait.php new file mode 100644 index 00000000..3c414a2a --- /dev/null +++ b/src/Users/UserTrait.php @@ -0,0 +1,27 @@ + $value) { + $this->setAttribute($key, $value); + } + + return $this; + } + + final public function setAttribute(string $key, mixed $value): self + { + $this->attributes[$key] = $value; + + return $this; + } +} diff --git a/tests/Pest.php b/tests/Pest.php index beca627f..e17ff371 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,11 +1,11 @@ in(__DIR__); +define('AUTH0_LARAVEL_RUNNING_TESTS', 1); -// uses()->afterEach(function (): void { -// $commands = ['optimize:clear']; +uses(TestCase::class)->in(__DIR__); -// foreach ($commands as $command) { -// Artisan::call($command); -// } -// })->in(__DIR__); +uses()->beforeAll(function (): void { + // ray()->clearAll(); +})->in(__DIR__); uses()->beforeEach(function (): void { $this->events = []; @@ -35,6 +33,14 @@ }); })->in(__DIR__); +// uses()->afterEach(function (): void { +// $commands = ['optimize:clear']; + +// foreach ($commands as $command) { +// Artisan::call($command); +// } +// })->in(__DIR__); + uses()->compact(); /* @@ -68,3 +74,90 @@ // // .. // } +function mockIdToken( + string $algorithm = Token::ALGO_RS256, + array $claims = [], + array $headers = [] +): string { + $secret = createRsaKeys()->private; + + $claims = array_merge([ + "iss" => 'https://' . config('auth0.guards.default.domain') . '/', + 'sub' => 'hello|world', + 'aud' => config('auth0.guards.default.clientId'), + 'exp' => time() + 60, + 'iat' => time(), + 'email' => 'john.doe@somewhere.test' + ], $claims); + + return (string) Generator::create($secret, $algorithm, $claims, $headers); +} + +function mockAccessToken( + string $algorithm = Token::ALGO_RS256, + array $claims = [], + array $headers = [] +): string { + $secret = createRsaKeys()->private; + + $claims = array_merge([ + "iss" => 'https://' . config('auth0.guards.default.domain') . '/', + 'sub' => 'hello|world', + 'aud' => config('auth0.guards.default.clientId'), + 'iat' => time(), + 'exp' => time() + 60, + 'azp' => config('auth0.guards.default.clientId'), + 'scope' => 'openid profile email', + ], $claims); + + return (string) Generator::create($secret, $algorithm, $claims, $headers); +} + +function createRsaKeys( + string $digestAlg = 'sha256', + int $keyType = OPENSSL_KEYTYPE_RSA, + int $bitLength = 2048 +): object +{ + $config = [ + 'digest_alg' => $digestAlg, + 'private_key_type' => $keyType, + 'private_key_bits' => $bitLength, + ]; + + $privateKeyResource = openssl_pkey_new($config); + + if ($privateKeyResource === false) { + throw new RuntimeException("OpenSSL reported an error: " . getSslError()); + } + + $export = openssl_pkey_export($privateKeyResource, $privateKey); + + if ($export === false) { + throw new RuntimeException("OpenSSL reported an error: " . getSslError()); + } + + $publicKey = openssl_pkey_get_details($privateKeyResource); + + $resCsr = openssl_csr_new([], $privateKeyResource); + $resCert = openssl_csr_sign($resCsr, null, $privateKeyResource, 30); + openssl_x509_export($resCert, $x509); + + return (object) [ + 'private' => $privateKey, + 'public' => $publicKey['key'], + 'cert' => $x509, + 'resource' => $privateKeyResource, + ]; +} + +function getSslError(): string +{ + $errors = []; + + while ($error = openssl_error_string()) { + $errors[] = $error; + } + + return implode(', ', $errors); +} diff --git a/tests/TestCase.php b/tests/TestCase.php index bdd75619..b1ee391f 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -4,17 +4,22 @@ namespace Auth0\Laravel\Tests; -use Orchestra\Testbench\TestCase as BaseTestCase; +use Illuminate\Foundation\Testing\TestCase as BaseTestCase; use Auth0\Laravel\ServiceProvider; +use Orchestra\Testbench\Concerns\CreatesApplication; +use Spatie\LaravelRay\RayServiceProvider; class TestCase extends BaseTestCase { + use CreatesApplication; + protected $enablesPackageDiscoveries = true; protected $events = []; protected function getPackageProviders($app) { return [ + RayServiceProvider::class, ServiceProvider::class, ]; } @@ -23,7 +28,7 @@ protected function getEnvironmentSetUp($app): void { $app['config']->set('auth', [ 'defaults' => [ - 'guard' => 'testGuard', + 'guard' => 'legacyGuard', 'passwords' => 'users', ], 'guards' => [ @@ -31,9 +36,20 @@ protected function getEnvironmentSetUp($app): void 'driver' => 'session', 'provider' => 'users', ], - 'testGuard' => [ + 'legacyGuard' => [ 'driver' => 'auth0.guard', - 'provider' => 'testProvider', + 'configuration' => 'web', + 'provider' => 'auth0-provider', + ], + 'auth0-session' => [ + 'driver' => 'auth0.authenticator', + 'configuration' => 'web', + 'provider' => 'auth0-provider', + ], + 'auth0-api' => [ + 'driver' => 'auth0.authorizer', + 'configuration' => 'api', + 'provider' => 'auth0-provider', ], ], 'providers' => [ @@ -41,15 +57,15 @@ protected function getEnvironmentSetUp($app): void 'driver' => 'eloquent', 'model' => App\Models\User::class, ], - 'testProvider' => [ + 'auth0-provider' => [ 'driver' => 'auth0.provider', - 'model' => 'auth0.repository', + 'repository' => 'auth0.repository', ], ], ]); // Set a random key for testing - $app['config']->set('app.key', 'base64:' . base64_encode(random_bytes(32))); + $_ENV['APP_KEY'] = 'base64:' . base64_encode(random_bytes(32)); // Setup database for testing (currently unused) $app['config']->set('database.default', 'testbench'); @@ -69,20 +85,27 @@ protected function getEnvironmentSetUp($app): void */ protected function assertDispatched(string $expectedEvent, int $times = 0, ?string $followingEvent = null) { - $this->assertTrue(\in_array($expectedEvent, $this->events), 'Event ' . $expectedEvent . ' was not dispatched.'); + expect($this->events) + ->toBeArray() + ->toContain($expectedEvent); if ($times > 0) { - $this->assertTrue(array_count_values($this->events)[$expectedEvent] === $times, 'Event ' . $expectedEvent . ' was not dispatched ' . $times . ' times.'); + expect(array_count_values($this->events)[$expectedEvent]) + ->toBeInt() + ->toBe($times); } if (null !== $followingEvent) { - $this->assertTrue(\in_array($followingEvent, $this->events)); + expect($this->events) + ->toContain($followingEvent); $indexExpected = array_search($expectedEvent, $this->events); $indexFollowing = array_search($followingEvent, $this->events); if ($indexExpected !== false && $indexFollowing !== false) { - $this->assertTrue($indexExpected > $indexFollowing, 'Event ' . $expectedEvent . ' was not dispatched after ' . $followingEvent . '.'); + expect($indexExpected) + ->toBeInt() + ->toBeGreaterThan($indexFollowing); } } } @@ -98,8 +121,11 @@ protected function assertDispatchedOrdered(array $events) foreach ($events as $event) { $index = array_search($event, $this->events); - $this->assertTrue($index !== false); - $this->assertTrue($index > $previousIndex); + + expect($index) + ->toBeInt() + ->toBeGreaterThan($previousIndex); + $previousIndex = $index; } } diff --git a/tests/Unit/Auth/GuardStatefulTest.php b/tests/Unit/Auth/GuardStatefulTest.php index 30c95c9f..857db265 100644 --- a/tests/Unit/Auth/GuardStatefulTest.php +++ b/tests/Unit/Auth/GuardStatefulTest.php @@ -3,10 +3,10 @@ declare(strict_types=1); use Auth0\Laravel\Auth\Guard; -use Auth0\Laravel\Entities\Credential; -use Auth0\Laravel\Model\Stateful\User; +use Auth0\Laravel\Entities\CredentialEntity; +use Auth0\Laravel\Users\StatefulUser; use Auth0\SDK\Configuration\SdkConfiguration; -use Auth0\SDK\Exception\NetworkException; +use Auth0\SDK\Token\Generator; use Illuminate\Http\Response; use Illuminate\Support\Facades\Route; use PsrMock\Psr18\Client as MockHttpClient; @@ -22,25 +22,25 @@ $this->secret = uniqid(); config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.clientSecret' => $this->secret, - 'auth0.cookieSecret' => uniqid(), - 'auth0.routes.home' => '/' . uniqid(), + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), ]); $this->laravel = app('auth0'); - $this->guard = $guard = auth('testGuard'); + $this->guard = $guard = auth('legacyGuard'); $this->sdk = $this->laravel->getSdk(); $this->config = $this->sdk->configuration(); $this->session = $this->config->getSessionStorage(); - $this->user = new User(['sub' => uniqid('auth0|')]); + $this->user = new StatefulUser(['sub' => uniqid('auth0|')]); $this->session->set('user', ['sub' => 'hello|world']); - $this->session->set('idToken', uniqid()); - $this->session->set('accessToken', uniqid()); + $this->session->set('idToken', (string) Generator::create((createRsaKeys())->private)); + $this->session->set('accessToken', (string) Generator::create((createRsaKeys())->private)); $this->session->set('accessTokenScope', [uniqid()]); $this->session->set('accessTokenExpiration', time() + 60); @@ -137,10 +137,10 @@ ->user()->getAuthIdentifier()->toBe('hello|world|4'); $identifier = uniqid('auth0|'); - $user = new User(['sub' => $identifier]); + $user = new StatefulUser(['sub' => $identifier]); // Overwrite state using the Guard's login() - $this->guard->login(Credential::create( + $this->guard->login(CredentialEntity::create( user: $user ), Guard::SOURCE_SESSION); @@ -158,39 +158,39 @@ it('creates a session from login()', function (): void { $identifier = uniqid('auth0|'); - $idToken = uniqid('id-token-'); - $accessToken = uniqid('access-token-'); + // $idToken = uniqid('id-token-'); + // $accessToken = uniqid('access-token-'); $accessTokenScope = [uniqid('access-token-scope-')]; $accessTokenExpiration = time() + 60; $this->session->set('user', ['sub' => $identifier]); - $this->session->set('idToken', $idToken); - $this->session->set('accessToken', $accessToken); + // $this->session->set('idToken', $idToken); + // $this->session->set('accessToken', $accessToken); $this->session->set('accessTokenScope', $accessTokenScope); $this->session->set('accessTokenExpiration', $accessTokenExpiration); $found = $this->guard->find(Guard::SOURCE_SESSION); expect($found) - ->toBeInstanceOf(Credential::class); + ->toBeInstanceOf(CredentialEntity::class); $this->guard->login($found, Guard::SOURCE_SESSION); expect($this->session) ->get('user')->toBe(['sub' => $identifier]) - ->get('idToken')->toBe($idToken) - ->get('accessToken')->toBe($accessToken) + // ->get('idToken')->toBe($idToken) + // ->get('accessToken')->toBe($accessToken) ->get('accessTokenScope')->toBe($accessTokenScope) ->get('accessTokenExpiration')->toBe($accessTokenExpiration) ->get('refreshToken')->toBeNull(); - $user = new User(['sub' => $identifier]); + $user = new StatefulUser(['sub' => $identifier]); $changedIdToken = uniqid('CHANGED-id-token-'); $changedRefreshToken = uniqid('CHANGED-refresh-token-'); // Overwrite state using the Guard's login() - $this->guard->login(Credential::create( + $this->guard->login(CredentialEntity::create( user: $user, idToken: $changedIdToken, refreshToken: $changedRefreshToken @@ -202,7 +202,7 @@ expect($this->session) ->get('user')->toBe(['sub' => $identifier]) ->get('idToken')->toBe($changedIdToken) - ->get('accessToken')->toBe($accessToken) + // ->get('accessToken')->toBe($accessToken) ->get('accessTokenScope')->toBe($accessTokenScope) ->get('accessTokenExpiration')->toBe($accessTokenExpiration) ->get('refreshToken')->toBe($changedRefreshToken); @@ -210,14 +210,14 @@ it('queries the /userinfo endpoint for refreshUser()', function (): void { $identifier = uniqid('auth0|'); - $idToken = uniqid('id-token-'); - $accessToken = uniqid('access-token-'); + // $idToken = uniqid('id-token-'); + // $accessToken = uniqid('access-token-'); $accessTokenScope = [uniqid('access-token-scope-')]; $accessTokenExpiration = time() + 60; $this->session->set('user', ['sub' => $identifier]); - $this->session->set('idToken', $idToken); - $this->session->set('accessToken', $accessToken); + // $this->session->set('idToken', $idToken); + // $this->session->set('accessToken', $accessToken); $this->session->set('accessTokenScope', $accessTokenScope); $this->session->set('accessTokenExpiration', $accessTokenExpiration); @@ -227,26 +227,25 @@ expect($this->session) ->get('user')->toBe(['sub' => $identifier]); - $requestFactory = new MockRequestFactory; - $responseFactory = new MockResponseFactory; - $streamFactory = new MockStreamFactory; - - $response = $responseFactory->createResponse(200); - $response->getBody()->write(json_encode( - [ - 'sub' => $identifier, - 'name' => 'John Doe', - 'email' => '...', - ], - JSON_PRETTY_PRINT - )); - - $client = new MockHttpClient(fallbackResponse: $response); - - $this->config->setHttpRequestFactory($requestFactory); - $this->config->setHttpResponseFactory($responseFactory); - $this->config->setHttpStreamFactory($streamFactory); - $this->config->setHttpClient($client); + $response = (new MockResponseFactory)->createResponse(); + + $this->guard + ->sdk() + ->configuration() + ->getHttpClient() + ->addResponseWildcard($response->withBody( + (new MockStreamFactory)->createStream( + json_encode( + value: [ + 'sub' => $identifier, + 'name' => 'John Doe', + 'email' => '...', + ], + flags: JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR + ) + ) + ) + ); $this->guard->refreshUser(); @@ -263,12 +262,12 @@ it('does not query the /userinfo endpoint for refreshUser() if an access token is not available', function (): void { $identifier = uniqid('auth0|'); - $idToken = uniqid('id-token-'); + // $idToken = uniqid('id-token-'); $accessTokenScope = [uniqid('access-token-scope-')]; $accessTokenExpiration = time() + 60; $this->session->set('user', ['sub' => $identifier]); - $this->session->set('idToken', $idToken); + // $this->session->set('idToken', $idToken); $this->session->set('accessToken', null); $this->session->set('accessTokenScope', $accessTokenScope); $this->session->set('accessTokenExpiration', $accessTokenExpiration); @@ -293,12 +292,13 @@ JSON_PRETTY_PRINT )); - $client = new MockHttpClient(fallbackResponse: $response, requestLimit: 0); + $http = new MockHttpClient(fallbackResponse: $response, requestLimit: 0); + $http->addResponseWildcard($response); $this->config->setHttpRequestFactory($requestFactory); $this->config->setHttpResponseFactory($responseFactory); $this->config->setHttpStreamFactory($streamFactory); - $this->config->setHttpClient($client); + $this->config->setHttpClient($http); $this->guard->refreshUser(); @@ -313,14 +313,14 @@ it('rejects bad responses from the /userinfo endpoint for refreshUser()', function (): void { $identifier = uniqid('auth0|'); - $idToken = uniqid('id-token-'); - $accessToken = uniqid('access-token-'); + // $idToken = uniqid('id-token-'); + // $accessToken = uniqid('access-token-'); $accessTokenScope = [uniqid('access-token-scope-')]; $accessTokenExpiration = time() + 60; $this->session->set('user', ['sub' => $identifier]); - $this->session->set('idToken', $idToken); - $this->session->set('accessToken', $accessToken); + // $this->session->set('idToken', $idToken); + // $this->session->set('accessToken', $accessToken); $this->session->set('accessTokenScope', $accessTokenScope); $this->session->set('accessTokenExpiration', $accessTokenExpiration); @@ -330,19 +330,21 @@ expect($this->session) ->get('user')->toBe(['sub' => $identifier]); - $requestFactory = new MockRequestFactory; - $responseFactory = new MockResponseFactory; - $streamFactory = new MockStreamFactory; - - $response = $responseFactory->createResponse(200); - $response->getBody()->write(json_encode('bad response', JSON_PRETTY_PRINT)); - - $client = new MockHttpClient(fallbackResponse: $response); - - $this->config->setHttpRequestFactory($requestFactory); - $this->config->setHttpResponseFactory($responseFactory); - $this->config->setHttpStreamFactory($streamFactory); - $this->config->setHttpClient($client); + $response = (new MockResponseFactory)->createResponse(); + + $this->guard + ->sdk() + ->configuration() + ->getHttpClient() + ->addResponseWildcard($response->withBody( + (new MockStreamFactory)->createStream( + json_encode( + value: 'bad response', + flags: JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR + ) + ) + ) + ); $this->guard->refreshUser(); @@ -382,26 +384,30 @@ ->get('user')->toBeNull(); }); -it('successfully continues a session when an access token succeeds is renewed', function (): void { +it('successfully continues a session when an access token is successfully refreshed', function (): void { $this->session->set('accessTokenExpiration', time() - 1000); - $this->session->set('refreshToken', uniqid()); - - $http = $this->config->getHttpClient(); - $streamFactory = $this->config->getHttpStreamFactory(); - $responseFactory = $this->config->getHttpResponseFactory(); - - $response = $responseFactory->createResponse(); - - $response = $response->withBody($streamFactory->createStream( - json_encode([ - 'access_token' => uniqid(), - 'expires_in' => 60, - 'scope' => 'openid profile', - 'token_type' => 'Bearer', - ], JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR) - )); - - $http->addResponseWildcard($response); + $this->session->set('refreshToken', (string) Generator::create((createRsaKeys())->private)); + + $response = (new MockResponseFactory)->createResponse(); + + $this->guard + ->sdk() + ->configuration() + ->getHttpClient() + ->addResponseWildcard($response->withBody( + (new MockStreamFactory)->createStream( + json_encode( + value: [ + 'access_token' => (string) Generator::create((createRsaKeys())->private), + 'expires_in' => 60, + 'scope' => 'openid profile', + 'token_type' => 'Bearer', + ], + flags: JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR + ) + ) + ) + ); $found = $this->guard->find(Guard::SOURCE_SESSION); $this->guard->login($found, Guard::SOURCE_SESSION); diff --git a/tests/Unit/Auth/GuardStatelessTest.php b/tests/Unit/Auth/GuardStatelessTest.php index 4b88483f..43cccbe5 100644 --- a/tests/Unit/Auth/GuardStatelessTest.php +++ b/tests/Unit/Auth/GuardStatelessTest.php @@ -3,7 +3,6 @@ declare(strict_types=1); use Auth0\Laravel\Auth\Guard; -use Auth0\Laravel\Contract\Auth\User\Repository; use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\SDK\Token; use Auth0\SDK\Token\Generator; @@ -18,28 +17,28 @@ $this->secret = uniqid(); config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_API, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.audience' => ['https://example.com/health-api'], - 'auth0.clientSecret' => $this->secret, - 'auth0.tokenAlgorithm' => Token::ALGO_HS256, - 'auth0.routes.home' => '/' . uniqid(), + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.audience' => ['https://example.com/health-api'], + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256, ]); $this->laravel = app('auth0'); - $this->guard = auth('testGuard'); + $this->guard = auth('legacyGuard'); $this->sdk = $this->laravel->getSdk(); $this->config = $this->sdk->configuration(); $this->token = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => 'https://' . config('auth0.domain') . '/', + "iss" => 'https://' . config('auth0.guards.default.domain') . '/', "sub" => "auth0|123456", "aud" => [ - config('auth0.audience')[0], + config('auth0.guards.default.audience')[0], "https://my-domain.auth0.com/userinfo" ], - "azp" => config('auth0.clientId'), + "azp" => config('auth0.guards.default.clientId'), "exp" => time() + 60, "iat" => time(), "scope" => "openid profile read:patients read:admin" @@ -81,7 +80,10 @@ }); it('does not get a user from a bad token', function (): void { - $this->config->setAudience(['BAD_AUDIENCE']); + $this->guard + ->sdk() + ->configuration() + ->setAudience(['BAD_AUDIENCE']); expect($this->guard) ->user()->toBeNull(); diff --git a/tests/Unit/Auth/GuardTest.php b/tests/Unit/Auth/GuardTest.php index 68717cdd..8f28142a 100644 --- a/tests/Unit/Auth/GuardTest.php +++ b/tests/Unit/Auth/GuardTest.php @@ -3,12 +3,18 @@ declare(strict_types=1); use Auth0\Laravel\Auth\Guard; -use Auth0\Laravel\Contract\Exception\AuthenticationException as AuthenticationExceptionContract; -use Auth0\Laravel\Exception\AuthenticationException; -use Auth0\Laravel\Entities\Credential; -use Auth0\Laravel\Model\Stateful\User; +use Auth0\Laravel\Exceptions\AuthenticationException; +use Auth0\Laravel\Entities\CredentialEntity; +use Auth0\Laravel\Users\StatefulUser; use Auth0\SDK\Configuration\SdkConfiguration; +use Auth0\SDK\Contract\API\ManagementInterface; +use Auth0\SDK\Exception\ConfigurationException; +use Auth0\SDK\Token; use Illuminate\Support\Facades\Route; +use PsrMock\Psr18\Client as MockHttpClient; +use PsrMock\Psr17\RequestFactory as MockRequestFactory; +use PsrMock\Psr17\ResponseFactory as MockResponseFactory; +use PsrMock\Psr17\StreamFactory as MockStreamFactory; uses()->group('auth', 'auth.guard', 'auth.guard.shared'); @@ -16,21 +22,21 @@ $this->secret = uniqid(); config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.clientSecret' => $this->secret, - 'auth0.cookieSecret' => uniqid(), - 'auth0.routes.home' => '/' . uniqid(), + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), ]); $this->laravel = app('auth0'); - $this->guard = auth('testGuard'); + $this->guard = auth('legacyGuard'); $this->sdk = $this->laravel->getSdk(); $this->config = $this->sdk->configuration(); $this->session = $this->config->getSessionStorage(); - $this->user = new User(['sub' => uniqid('auth0|')]); + $this->user = new StatefulUser(['sub' => uniqid('auth0|')]); Route::middleware('auth:auth0')->get('/test', function () { return 'OK'; @@ -40,7 +46,7 @@ it('returns its configured name', function (): void { expect($this->guard) ->toBeInstanceOf(Guard::class) - ->getName()->toBe('testGuard'); + ->getName()->toBe('legacyGuard'); }); it('assigns a user at login', function (): void { @@ -48,7 +54,7 @@ ->toBeInstanceOf(Guard::class) ->user()->toBeNull(); - $this->guard->login(Credential::create( + $this->guard->login(CredentialEntity::create( user: $this->user )); @@ -64,7 +70,7 @@ ->toBeInstanceOf(Guard::class) ->user()->toBeNull(); - $this->guard->login(Credential::create( + $this->guard->login(CredentialEntity::create( user: $this->user )); @@ -80,11 +86,32 @@ ->id()->toBeNull(); }); +it('forgets a user', function (): void { + expect($this->guard) + ->toBeInstanceOf(Guard::class) + ->user()->toBeNull(); + + $this->guard->login(CredentialEntity::create( + user: $this->user + )); + + expect($this->guard) + ->user()->toBe($this->user); + + $this->guard->forgetUser(); + + expect($this->guard) + ->user()->toBeNull(); + + expect($this->guard) + ->id()->toBeNull(); +}); + it('checks if a user is logged in', function (): void { expect($this->guard) ->check()->toBeFalse(); - $this->guard->login(Credential::create( + $this->guard->login(CredentialEntity::create( user: $this->user )); @@ -96,7 +123,7 @@ expect($this->guard) ->guest()->toBeTrue(); - $this->guard->login(Credential::create( + $this->guard->login(CredentialEntity::create( user: $this->user )); @@ -105,7 +132,7 @@ }); it('gets the user identifier', function (): void { - $this->guard->login(Credential::create( + $this->guard->login(CredentialEntity::create( user: $this->user )); @@ -114,7 +141,7 @@ }); it('validates a user', function (): void { - $this->guard->login(Credential::create( + $this->guard->login(CredentialEntity::create( user: $this->user )); @@ -142,10 +169,26 @@ ->hasUser()->toBeFalse(); }); +it('clears an imposter at logout', function (): void { + $this->guard->setImpersonating(CredentialEntity::create( + user: $this->user + )); + + expect($this->guard) + ->hasUser()->toBeTrue() + ->isImpersonating()->toBeTrue(); + + $this->guard->logout(); + + expect($this->guard) + ->isImpersonating()->toBeFalse() + ->hasUser()->toBeFalse(); +}); + it('has a scope', function (): void { - $this->user = new User(['sub' => uniqid('auth0|'), 'scope' => 'read:users 456']); + $this->user = new StatefulUser(['sub' => uniqid('auth0|'), 'scope' => 'read:users 456']); - $credential = Credential::create( + $credential = CredentialEntity::create( user: $this->user, accessTokenScope: ['read:users', '456'] ); @@ -157,7 +200,7 @@ ->hasScope('789', $credential)->toBeFalse() ->hasScope('*', $credential)->toBeTrue(); - $credential = Credential::create( + $credential = CredentialEntity::create( user: $this->user ); @@ -167,7 +210,7 @@ }); it('checks if a user was authenticated via remember', function (): void { - $this->guard->login(Credential::create( + $this->guard->login(CredentialEntity::create( user: $this->user )); @@ -178,10 +221,10 @@ it('returns null if authenticate() is called without being authenticated', function (): void { $response = $this->guard->authenticate(); expect($response)->toBeNull(); -})->throws(AuthenticationException::class, AuthenticationExceptionContract::UNAUTHENTICATED); +})->throws(AuthenticationException::class, AuthenticationException::UNAUTHENTICATED); it('returns a user from authenticate() if called while authenticated', function (): void { - $this->guard->login(Credential::create( + $this->guard->login(CredentialEntity::create( user: $this->user )); @@ -192,10 +235,10 @@ }); it('gets/sets a credentials', function (): void { - $credential = Credential::create( + $credential = CredentialEntity::create( user: $this->user, - idToken: uniqid(), - accessToken: uniqid(), + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], accessTokenExpiration: time() + 3600 ); @@ -205,3 +248,150 @@ expect($this->guard) ->user()->toBe($this->user); }); + +it('queries the /userinfo endpoint', function (): void { + $credential = CredentialEntity::create( + user: $this->user, + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600 + ); + + $this->guard->setCredential($credential, Guard::SOURCE_TOKEN); + + expect($this->guard) + ->user()->toBe($this->user); + + $identifier = 'updated|' . uniqid(); + + $response = (new MockResponseFactory)->createResponse(); + + $this->guard + ->sdk() + ->configuration() + ->getHttpClient() + ->addResponseWildcard($response->withBody( + (new MockStreamFactory)->createStream( + json_encode( + value: [ + 'sub' => $identifier, + 'name' => 'John Doe', + 'email' => '...', + ], + flags: JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR + ) + ) + ) + ); + + $userAttributes = $this->guard->getRefreshedUser()->getAttributes(); + + expect($userAttributes) + ->toBeArray() + ->toMatchArray([ + 'sub' => $identifier, + ]); +}); + +test('hasPermission(*) returns true for wildcard', function (): void { + $credential = CredentialEntity::create( + user: $this->user, + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600 + ); + + $this->guard->setCredential($credential, Guard::SOURCE_TOKEN); + + expect($this->guard->hasPermission('*')) + ->toBeTrue(); +}); + +test('hasPermission() returns true for matches', function (): void { + $credential = CredentialEntity::create( + user: $this->user, + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenDecoded: [ + 'permissions' => [ + 'read:posts', + 'read:messages', + 'read:users', + ], + ], + accessTokenExpiration: time() + 3600 + ); + + $this->guard->setCredential($credential, Guard::SOURCE_TOKEN); + + expect($this->guard->hasPermission('read:messages')) + ->toBeTrue(); + + expect($this->guard->hasPermission('write:posts')) + ->toBeFalse(); +}); + +test('hasPermission() returns false when there are no permissions', function (): void { + $credential = CredentialEntity::create( + user: $this->user, + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenDecoded: [ + 'permissions' => [], + ], + accessTokenExpiration: time() + 3600 + ); + + $this->guard->setCredential($credential, Guard::SOURCE_TOKEN); + + expect($this->guard->hasPermission('read:messages')) + ->toBeFalse(); +}); + +test('management() returns a Management API class', function (): void { + $credential = CredentialEntity::create( + user: $this->user, + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenDecoded: [ + 'permissions' => [], + ], + accessTokenExpiration: time() + 3600 + ); + + $this->guard->setCredential($credential, Guard::SOURCE_TOKEN); + + expect($this->guard->management()) + ->toBeInstanceOf(ManagementInterface::class); +}); + +test('sdk() uses the guard name to optionally merge configuration data', function (): void { + config([ + 'auth0.guards.default.domain' => 'https://default-domain.com/', + 'auth0.guards.web.strategy' => 'none', + 'auth0.guards.web.domain' => 'https://legacy-domain.com/', + ]); + + expect($this->guard->sdk()->configuration()->getDomain()) + ->toBe('legacy-domain.com'); +}); + +test('sdk() configuration v1 is supported', function (): void { + config(['auth0' => [ + 'strategy' => 'none', + 'domain' => 'https://v1-domain.com/', + ]]); + + expect($this->guard->sdk()->configuration()->getDomain()) + ->toBe('v1-domain.com'); +}); + +test('sdk() configuration v1 defaults to an empty array', function (): void { + config(['auth0' => 123]); + $this->guard->sdk()->configuration()->getDomain(); +})->throws(ConfigurationException::class); diff --git a/tests/Unit/Auth/User/ProviderTest.php b/tests/Unit/Auth/User/ProviderTest.php deleted file mode 100644 index 5cc306c1..00000000 --- a/tests/Unit/Auth/User/ProviderTest.php +++ /dev/null @@ -1,105 +0,0 @@ -group('auth', 'auth.user', 'auth.user.provider'); - -beforeEach(function (): void { - $this->secret = uniqid(); - - config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.clientSecret' => $this->secret, - 'auth0.cookieSecret' => uniqid(), - 'auth0.routes.home' => '/' . uniqid(), - ]); - - $this->laravel = app('auth0'); - $this->guard = auth('testGuard'); - $this->sdk = $this->laravel->getSdk(); -}); - -test('retrieveByToken() returns null when an incompatible guard token is used', function (): void { - config([ - 'auth.defaults.guard' => 'web', - 'auth.guards.testGuard' => null - ]); - - $route = '/' . uniqid(); - - Route::get($route, function () { - $provider = app('auth0.provider'); - $credential = $provider->retrieveByToken('token', ''); - - if (null === $credential) { - return response()->json(['status' => 'OK']); - } - - abort(Response::HTTP_UNAUTHORIZED, 'Unauthorized'); - }); - - $this->getJson($route) - ->assertOK(); -}); - -test('retrieveByToken() returns null when an invalid token is provided', function (): void { - $provider = app('auth0.provider'); - - expect($provider->retrieveByToken('token', '')) - ->toBeNull(); - - expect($provider->retrieveByToken('token', [])) - ->toBeNull(); -}); - -test('validateCredentials() always returns false', function (): void { - $provider = app('auth0.provider'); - $user = new User(); - - expect($provider->validateCredentials($user, [])) - ->toBeFalse(); -}); - -test('getRepository() throws an error when an non-existent repository provider is set', function (): void { - $provider = new Provider(['model' => 'MISSING']); - $provider->getRepository(); -})->throws(BindingResolutionException::class); - -test('getRepository() throws an error when an invalid repository provider is set', function (): void { - $provider = new Provider(['model' => ['ARRAY']]); - $provider->getRepository(); -})->throws(BindingResolutionException::class); - -test('setRepository() sets the repository model', function (): void { - $provider = new Provider(['model' => uniqid()]); - $repository = new Repository(); - $provider->setRepository($repository::class); - - expect($provider->getRepository()) - ->toBeInstanceOf($repository::class); -}); - -test('setRepository() with the same repository identifier uses the cached repository instance', function (): void { - $provider = new Provider(['model' => 'MISSING']); - $repository = new Repository(); - - $provider->setRepository($repository::class); - - expect($provider->getRepository()) - ->toBeInstanceOf($repository::class); - - $provider->setRepository($repository::class); - - expect($provider->getRepository()) - ->toBeInstanceOf($repository::class); -}); diff --git a/tests/Unit/Cache/LaravelCachePoolTest.php b/tests/Unit/Bridges/CacheBridgeTest.php similarity index 77% rename from tests/Unit/Cache/LaravelCachePoolTest.php rename to tests/Unit/Bridges/CacheBridgeTest.php index 12989b30..437de083 100644 --- a/tests/Unit/Cache/LaravelCachePoolTest.php +++ b/tests/Unit/Bridges/CacheBridgeTest.php @@ -2,21 +2,21 @@ declare(strict_types=1); -use Auth0\Laravel\Cache\LaravelCachePool; -use Auth0\Laravel\Cache\LaravelCacheItem; +use Auth0\Laravel\Bridges\CacheBridge; +use Auth0\Laravel\Bridges\CacheItemBridge; use Psr\Cache\CacheItemInterface; uses()->group('cache', 'cache.laravel', 'cache.laravel.pool'); test('getItem(), hasItem() and save() behave as expected', function (): void { - $pool = new LaravelCachePool(); + $pool = new CacheBridge(); $cache = $pool->getItem('testing'); expect($pool) ->hasItem('testing')->toBeFalse(); expect($cache) - ->toBeInstanceOf(LaravelCacheItem::class) + ->toBeInstanceOf(CacheItemBridge::class) ->get()->toBeNull() ->isHit()->toBeFalse(); @@ -34,7 +34,7 @@ $cache = $pool->getItem('testing'); expect($cache) - ->toBeInstanceOf(LaravelCacheItem::class) + ->toBeInstanceOf(CacheItemBridge::class) ->isHit()->toBeTrue() ->get()->toBeNull() ->set(42) @@ -49,7 +49,7 @@ $results = $pool->getItems(['testing' => uniqid()]); expect($results['testing']) - ->toBeInstanceOf(LaravelCacheItem::class) + ->toBeInstanceOf(CacheItemBridge::class) ->isHit()->toBeTrue() ->get()->not()->toBe(42); @@ -63,7 +63,7 @@ ->hasItem('testing')->toBeFalse(); expect($cache) - ->toBeInstanceOf(LaravelCacheItem::class) + ->toBeInstanceOf(CacheItemBridge::class) ->get()->toBeNull() ->isHit()->toBeFalse(); @@ -74,8 +74,8 @@ }); test('save() with a negative expiration value is deleted', function (): void { - $pool = new LaravelCachePool(); - $cache = new LaravelCacheItem('testing', 42, true, new DateTime('now - 1 year')); + $pool = new CacheBridge(); + $cache = new CacheItemBridge('testing', 42, true, new DateTime('now - 1 year')); expect($pool)->hasItem('testing')->toBeFalse(); @@ -85,8 +85,8 @@ }); test('saveDeferred() behaves as expected', function (): void { - $pool = new LaravelCachePool(); - $cache = new LaravelCacheItem('testing', 42, true, new DateTime('now + 1 hour')); + $pool = new CacheBridge(); + $cache = new CacheItemBridge('testing', 42, true, new DateTime('now + 1 hour')); expect($pool) ->hasItem('testing')->toBeFalse() @@ -97,8 +97,8 @@ }); test('save() with a false value is discarded', function (): void { - $pool = new LaravelCachePool(); - $cache = new LaravelCacheItem('testing', false, true, new DateTime('now + 1 hour')); + $pool = new CacheBridge(); + $cache = new CacheItemBridge('testing', false, true, new DateTime('now + 1 hour')); expect($pool) ->hasItem('testing')->toBeFalse() @@ -107,8 +107,8 @@ }); test('saveDeferred() returns false when the wrong type of interface is saved', function (): void { - $pool = new LaravelCachePool(); - $cache = new LaravelCacheItem('testing', 42, true, new DateTime('now + 1 hour')); + $pool = new CacheBridge(); + $cache = new CacheItemBridge('testing', 42, true, new DateTime('now + 1 hour')); $cache = new class implements CacheItemInterface { public function getKey(): string @@ -149,8 +149,8 @@ public function expiresAfter($time): static }); test('deleteItem() behaves as expected', function (): void { - $pool = new LaravelCachePool(); - $cache = new LaravelCacheItem('testing', 42, true, new DateTime('now + 1 minute')); + $pool = new CacheBridge(); + $cache = new CacheItemBridge('testing', 42, true, new DateTime('now + 1 minute')); expect($pool)->hasItem('testing')->toBeFalse(); @@ -177,20 +177,20 @@ public function expiresAfter($time): static }); test('deleteItems() behaves as expected', function (): void { - $pool = new LaravelCachePool(); + $pool = new CacheBridge(); expect($pool) ->hasItem('testing1')->toBeFalse() ->hasItem('testing2')->toBeFalse() ->hasItem('testing3')->toBeFalse(); - $cache = new LaravelCacheItem('testing1', uniqid(), true, new DateTime('now + 1 minute')); + $cache = new CacheItemBridge('testing1', uniqid(), true, new DateTime('now + 1 minute')); $pool->save($cache); - $cache = new LaravelCacheItem('testing2', uniqid(), true, new DateTime('now + 1 minute')); + $cache = new CacheItemBridge('testing2', uniqid(), true, new DateTime('now + 1 minute')); $pool->save($cache); - $cache = new LaravelCacheItem('testing3', uniqid(), true, new DateTime('now + 1 minute')); + $cache = new CacheItemBridge('testing3', uniqid(), true, new DateTime('now + 1 minute')); $pool->save($cache); expect($pool) @@ -217,20 +217,20 @@ public function expiresAfter($time): static }); test('clear() behaves as expected', function (): void { - $pool = new LaravelCachePool(); + $pool = new CacheBridge(); expect($pool) ->hasItem('testing1')->toBeFalse() ->hasItem('testing2')->toBeFalse() ->hasItem('testing3')->toBeFalse(); - $cache = new LaravelCacheItem('testing1', uniqid(), true, new DateTime('now + 1 minute')); + $cache = new CacheItemBridge('testing1', uniqid(), true, new DateTime('now + 1 minute')); $pool->save($cache); - $cache = new LaravelCacheItem('testing2', uniqid(), true, new DateTime('now + 1 minute')); + $cache = new CacheItemBridge('testing2', uniqid(), true, new DateTime('now + 1 minute')); $pool->save($cache); - $cache = new LaravelCacheItem('testing3', uniqid(), true, new DateTime('now + 1 minute')); + $cache = new CacheItemBridge('testing3', uniqid(), true, new DateTime('now + 1 minute')); $pool->save($cache); expect($pool) diff --git a/tests/Unit/Cache/LaravelCacheItemTest.php b/tests/Unit/Bridges/CacheItemBridgeTest.php similarity index 79% rename from tests/Unit/Cache/LaravelCacheItemTest.php rename to tests/Unit/Bridges/CacheItemBridgeTest.php index d3549ced..ff00f699 100644 --- a/tests/Unit/Cache/LaravelCacheItemTest.php +++ b/tests/Unit/Bridges/CacheItemBridgeTest.php @@ -2,52 +2,52 @@ declare(strict_types=1); -use Auth0\Laravel\Cache\LaravelCacheItem; +use Auth0\Laravel\Bridges\CacheItemBridge; uses()->group('cache', 'cache.laravel', 'cache.laravel.item'); test('getKey() returns an expected value', function (): void { - $cacheItem = new LaravelCacheItem('testing', 42, true); + $cacheItem = new CacheItemBridge('testing', 42, true); expect($cacheItem->getKey()) ->toBe('testing'); }); test('get() returns an expected value when hit', function (): void { - $cacheItem = new LaravelCacheItem('testing', 42, true); + $cacheItem = new CacheItemBridge('testing', 42, true); expect($cacheItem->get()) ->toBe(42); }); test('get() returns null when no hit', function (): void { - $cacheItem = new LaravelCacheItem('testing', 42, false); + $cacheItem = new CacheItemBridge('testing', 42, false); expect($cacheItem->get()) ->toBeNull(); }); test('getRawValue() returns an expected value', function (): void { - $cacheItem = new LaravelCacheItem('testing', 42, false); + $cacheItem = new CacheItemBridge('testing', 42, false); expect($cacheItem->getRawValue()) ->toBe(42); }); test('isHit() returns an expected value when hit', function (): void { - $cacheItem = new LaravelCacheItem('testing', 42, true); + $cacheItem = new CacheItemBridge('testing', 42, true); expect($cacheItem->isHit()) ->toBeTrue(); - $cacheItem = new LaravelCacheItem('testing', 42, false); + $cacheItem = new CacheItemBridge('testing', 42, false); expect($cacheItem->isHit()) ->toBeFalse(); }); test('set() alters the stored value as expected', function (): void { - $cacheItem = new LaravelCacheItem('testing', 42, true); + $cacheItem = new CacheItemBridge('testing', 42, true); expect($cacheItem->get()) ->toBe(42); @@ -58,7 +58,7 @@ }); test('expiresAt() defaults to +1 year and accepts changes to its value', function (): void { - $cacheItem = new LaravelCacheItem('testing', 42, true); + $cacheItem = new CacheItemBridge('testing', 42, true); expect($cacheItem->getExpiration()->getTimestamp()) ->toBeGreaterThan((new DateTime('now +1 year -1 minute'))->getTimestamp()) @@ -72,7 +72,7 @@ }); test('expiresAfter() defaults to +1 year and accepts changes to its value', function (): void { - $cacheItem = new LaravelCacheItem('testing', 42, true); + $cacheItem = new CacheItemBridge('testing', 42, true); expect($cacheItem->getExpiration()->getTimestamp()) ->toBeGreaterThan((new DateTime('now +1 year -1 minute'))->getTimestamp()) @@ -86,7 +86,7 @@ }); test('miss() returns a configured instance', function (): void { - $cacheItem = new LaravelCacheItem('testing', 42, true); + $cacheItem = new CacheItemBridge('testing', 42, true); $newCacheItem = $cacheItem->miss('testing123'); expect($cacheItem->getKey()) diff --git a/tests/Unit/Store/LaravelSessionTest.php b/tests/Unit/Bridges/SessionBridgeTest.php similarity index 90% rename from tests/Unit/Store/LaravelSessionTest.php rename to tests/Unit/Bridges/SessionBridgeTest.php index a629f81e..438918f5 100644 --- a/tests/Unit/Store/LaravelSessionTest.php +++ b/tests/Unit/Bridges/SessionBridgeTest.php @@ -2,14 +2,14 @@ declare(strict_types=1); -use Auth0\Laravel\Store\LaravelSession; +use Auth0\Laravel\Bridges\SessionBridge; use Auth0\SDK\Contract\StoreInterface; uses()->group('session-store'); it('throws an exception when an empty prefix is provided', function (): void { expect(function () { - new LaravelSession( + new SessionBridge( prefix: '', ); })->toThrow(InvalidArgumentException::class); @@ -18,7 +18,7 @@ it('accepts and uses a specified prefix', function (): void { $prefix = uniqid(); - $store = new LaravelSession( + $store = new SessionBridge( prefix: $prefix, ); @@ -28,7 +28,7 @@ }); it('allows updating the prefix', function (): void { - $store = new LaravelSession(); + $store = new SessionBridge(); expect($store) ->toBeInstanceOf(StoreInterface::class) @@ -45,7 +45,7 @@ it('supports CRUD operations', function (): void { $prefix = uniqid(); - $store = new LaravelSession( + $store = new SessionBridge( prefix: $prefix, ); diff --git a/tests/Unit/ConfigurationTest.php b/tests/Unit/ConfigurationTest.php index 72499215..8911b96a 100644 --- a/tests/Unit/ConfigurationTest.php +++ b/tests/Unit/ConfigurationTest.php @@ -4,16 +4,29 @@ use Auth0\Laravel\Configuration; -uses()->group('configuration'); +uses()->group('Configuration'); test('stringToArrayOrNull() behaves as expected', function (): void { expect(Configuration::stringToArrayOrNull('foo bar baz')) ->toBe(['foo', 'bar', 'baz']); + + expect(Configuration::stringToArrayOrNull(['foo', 'bar', 'baz'])) + ->toBe(['foo', 'bar', 'baz']); + + expect(Configuration::stringToArrayOrNull(' ')) + ->toBeNull(); }); test('stringToArray() behaves as expected', function (): void { expect(Configuration::stringToArray('foo bar baz')) ->toBe(['foo', 'bar', 'baz']); + + expect(Configuration::stringToArray(['foo', 'bar', 'baz'])) + ->toBe(['foo', 'bar', 'baz']); + + expect(Configuration::stringToArray(' ')) + ->toBeArray() + ->toHaveCount(0); }); test('stringToBoolOrNull() behaves as expected', function (): void { @@ -32,3 +45,83 @@ expect(Configuration::stringToBoolOrNull('foo', false)) ->toBeFalse(); }); + +test('stringOrNull() behaves as expected', function (): void { + expect(Configuration::stringOrNull(123)) + ->toBeNull(); + + expect(Configuration::stringOrNull(' 456 ')) + ->toEqual('456'); + + expect(Configuration::stringOrNull(' ')) + ->toBeNull(); + + expect(Configuration::stringOrNull('empty')) + ->toBeNull(); + + expect(Configuration::stringOrNull('(empty)')) + ->toBeNull(); + + expect(Configuration::stringOrNull('null')) + ->toBeNull(); + + expect(Configuration::stringOrNull('(null)')) + ->toBeNull(); +}); + +test('stringOrIntToIntOrNull() behaves as expected', function (): void { + expect(Configuration::stringOrIntToIntOrNull(123)) + ->toEqual(123); + + expect(Configuration::stringOrIntToIntOrNull(' 456 ')) + ->toEqual(456); + + expect(Configuration::stringOrIntToIntOrNull(' ')) + ->toBeNull(); + + expect(Configuration::stringOrIntToIntOrNull(' abc ')) + ->toBeNull(); +}); + +test('get() behaves as expected', function (): void { + config(['test' => [ + Configuration::CONFIG_AUDIENCE => implode(',', [uniqid(), uniqid()]), + Configuration::CONFIG_SCOPE => [], + Configuration::CONFIG_ORGANIZATION => '', + + Configuration::CONFIG_USE_PKCE => true, + Configuration::CONFIG_HTTP_TELEMETRY => 'true', + Configuration::CONFIG_COOKIE_SECURE => 123, + Configuration::CONFIG_PUSHED_AUTHORIZATION_REQUEST => false, + + 'tokenLeeway' => 123, + ]]); + + define('AUTH0_OVERRIDE_CONFIGURATION', 'test'); + + expect(Configuration::get(Configuration::CONFIG_AUDIENCE)) + ->toBeArray() + ->toHaveCount(2); + + expect(Configuration::get(Configuration::CONFIG_SCOPE)) + ->toBeNull(); + + expect(Configuration::get(Configuration::CONFIG_ORGANIZATION)) + ->toBeNull(); + + expect(Configuration::get(Configuration::CONFIG_USE_PKCE)) + ->toBeTrue(); + + expect(Configuration::get(Configuration::CONFIG_HTTP_TELEMETRY)) + ->toBeTrue(); + + expect(Configuration::get(Configuration::CONFIG_COOKIE_SECURE)) + ->toBeNull(); + + expect(Configuration::get(Configuration::CONFIG_PUSHED_AUTHORIZATION_REQUEST)) + ->toBeFalse(); + + expect(Configuration::get('tokenLeeway')) + ->toBeInt() + ->toEqual(123); +}); diff --git a/tests/Unit/Http/Controller/Stateful/CallbackTest.php b/tests/Unit/Controllers/CallbackControllerTest.php similarity index 61% rename from tests/Unit/Http/Controller/Stateful/CallbackTest.php rename to tests/Unit/Controllers/CallbackControllerTest.php index 95dab2da..96c63a5a 100644 --- a/tests/Unit/Http/Controller/Stateful/CallbackTest.php +++ b/tests/Unit/Controllers/CallbackControllerTest.php @@ -2,23 +2,23 @@ declare(strict_types=1); -use Auth0\Laravel\Event\Stateful\AuthenticationFailed; -use Auth0\Laravel\Event\Stateful\AuthenticationSucceeded; -use Auth0\Laravel\Exception\Stateful\CallbackException; -use Auth0\Laravel\Model\Stateful\User; +use Auth0\Laravel\Controllers\CallbackController; +use Auth0\Laravel\Events\AuthenticationFailed; +use Auth0\Laravel\Events\AuthenticationSucceeded; +use Auth0\Laravel\Exceptions\ControllerException; +use Auth0\Laravel\Exceptions\Controllers\CallbackControllerException; +use Auth0\Laravel\Users\ImposterUser; use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\SDK\Exception\StateException; use Auth0\SDK\Token; use Auth0\SDK\Token\Generator; use Illuminate\Support\Facades\Route; -use Auth0\Laravel\Http\Controller\Stateful\Callback; use Illuminate\Auth\Events\Attempting; use Illuminate\Auth\Events\Authenticated; use Illuminate\Auth\Events\Failed; use Illuminate\Auth\Events\Login; use Illuminate\Auth\Events\Validated; - -use function Pest\Laravel\getJson; +use Illuminate\Http\Response; uses()->group('stateful', 'controller', 'controller.stateful', 'controller.stateful.callback'); @@ -26,33 +26,33 @@ $this->secret = uniqid(); config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.clientSecret' => $this->secret, - 'auth0.cookieSecret' => uniqid(), - 'auth0.routes.home' => '/' . uniqid(), + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), ]); - $this->laravel = app('auth0'); - $this->guard = auth('testGuard'); - $this->sdk = $this->laravel->getSdk(); - $this->config = $this->sdk->configuration(); - - $this->user = new User(['sub' => uniqid('auth0|')]); + $this->guard = auth('legacyGuard'); + $this->sdk = $this->guard->sdk(); + $this->config = $this->guard->sdk()->configuration(); + $this->user = new ImposterUser(['sub' => uniqid('auth0|')]); - Route::get('/auth0/callback', Callback::class)->name('callback'); + Route::get('/auth0/callback', CallbackController::class)->name('callback'); }); it('redirects home if an incompatible guard is active', function (): void { config([ 'auth.defaults.guard' => 'web', - 'auth.guards.testGuard' => null, + 'auth.guards.legacyGuard' => null, ]); - getJson('/auth0/callback') - ->assertFound() - ->assertLocation(config('auth0.routes.home')); + expect(function () { + $this->withoutExceptionHandling() + ->getJson('/auth0/callback') + ->assertStatus(Response::HTTP_INTERNAL_SERVER_ERROR); + })->toThrow(ControllerException::class); }); it('accepts code and state parameters', function (): void { @@ -76,7 +76,7 @@ expect(function () { $this->withoutExceptionHandling() ->getJson('/auth0/callback?error=123&error_description=456'); - })->toThrow(CallbackException::class); + })->toThrow(CallbackControllerException::class); $this->assertDispatched(Attempting::class, 1); $this->assertDispatched(Failed::class, 1); @@ -97,24 +97,24 @@ $nonce = uniqid(); $verifier = uniqid(); - $accessToken = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => 'https://' . config('auth0.domain') . '/', + $idToken = Generator::create($this->secret, Token::ALGO_HS256, [ + "iss" => 'https://' . config('auth0.guards.default.domain') . '/', 'sub' => 'hello|world', - 'aud' => config('auth0.clientId'), + 'aud' => config('auth0.guards.default.clientId'), 'exp' => time() + 60, 'iat' => time(), - 'email' => 'john.doe@somewhere.teset' + 'email' => 'john.doe@somewhere.test', + 'nonce' => $nonce ], []); - $idToken = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => 'https://' . config('auth0.domain') . '/', + $accessToken = Generator::create($this->secret, Token::ALGO_HS256, [ + "iss" => 'https://' . config('auth0.guards.default.domain') . '/', 'sub' => 'hello|world', - 'aud' => config('auth0.clientId'), + 'aud' => config('auth0.guards.default.clientId'), 'iat' => time(), 'exp' => time() + 60, - 'azp' => config('auth0.clientId'), - 'scope' => 'openid profile email', - 'nonce' => $nonce, + 'azp' => config('auth0.guards.default.clientId'), + 'scope' => 'openid profile email' ], []); $factory = $this->config->getHttpResponseFactory(); @@ -127,16 +127,16 @@ ])); $client = $this->config->getHttpClient(); - $client->addResponse('POST', 'https://' . config('auth0.domain') . '/oauth/token', $response); + $client->addResponse('POST', 'https://' . config('auth0.guards.default.domain') . '/oauth/token', $response); $this->withSession([ - 'auth0_transient_state' => $state, - 'auth0_transient_pkce' => $pkce, - 'auth0_transient_nonce' => $nonce, - 'auth0_transient_code_verifier' => $verifier - ])->getJson('/auth0/callback?code=code&state=' . $state) - ->assertFound() - ->assertLocation(config('auth0.routes.home')); + 'auth0_transient_state' => $state, + 'auth0_transient_pkce' => $pkce, + 'auth0_transient_nonce' => $nonce, + 'auth0_transient_code_verifier' => $verifier + ])->getJson('/auth0/callback?code=code&state=' . $state) + ->assertFound() + ->assertLocation('/'); $this->assertDispatched(Attempting::class, 1); $this->assertDispatched(Validated::class, 1); diff --git a/tests/Unit/Http/Controller/Stateful/LoginTest.php b/tests/Unit/Controllers/LoginControllerTest.php similarity index 50% rename from tests/Unit/Http/Controller/Stateful/LoginTest.php rename to tests/Unit/Controllers/LoginControllerTest.php index 4475d3ff..15035a0b 100644 --- a/tests/Unit/Http/Controller/Stateful/LoginTest.php +++ b/tests/Unit/Controllers/LoginControllerTest.php @@ -2,9 +2,13 @@ declare(strict_types=1); +use Auth0\Laravel\Controllers\LoginController; +use Auth0\Laravel\Exceptions\ControllerException; use Auth0\SDK\Configuration\SdkConfiguration; use Illuminate\Support\Facades\Route; use Auth0\Laravel\Http\Controller\Stateful\Login; +use Auth0\SDK\Token\Generator; +use Illuminate\Http\Response; uses()->group('stateful', 'controller', 'controller.stateful', 'controller.stateful.login'); @@ -12,47 +16,46 @@ $this->secret = uniqid(); config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.clientSecret' => $this->secret, - 'auth0.cookieSecret' => uniqid(), - 'auth0.routes.home' => '/' . uniqid(), + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), ]); $this->laravel = app('auth0'); - $this->guard = auth('testGuard'); + $this->guard = auth('legacyGuard'); $this->sdk = $this->laravel->getSdk(); $this->validSession = [ 'auth0_session_user' => ['sub' => 'hello|world'], - 'auth0_session_idToken' => uniqid(), - 'auth0_session_accessToken' => uniqid(), + 'auth0_session_idToken' => (string) Generator::create((createRsaKeys())->private), + 'auth0_session_accessToken' => (string) Generator::create((createRsaKeys())->private), 'auth0_session_accessTokenScope' => [uniqid()], 'auth0_session_accessTokenExpiration' => time() + 60, ]; - Route::get('/login', Login::class); + Route::get('/login', LoginController::class); }); it('redirects to the home route if an incompatible guard is active', function (): void { config($config = [ 'auth.defaults.guard' => 'web', - 'auth.guards.testGuard' => null, + 'auth.guards.legacyGuard' => null, ]); - $this->get('/login') - ->assertRedirect(config('auth0.routes.home')); + expect(function () { + $this->withoutExceptionHandling() + ->getJson('/login') + ->assertStatus(Response::HTTP_INTERNAL_SERVER_ERROR); + })->toThrow(ControllerException::class); }); it('redirects to the home route when a user is already logged in', function (): void { - config($config = [ - 'auth0.routes.home' => '/' . uniqid() - ]); - $this->withSession($this->validSession) ->get('/login') - ->assertRedirect(config('auth0.routes.home')); + ->assertRedirect('/'); }); it('redirects to the Universal Login Page', function (): void { diff --git a/tests/Unit/Controllers/LogoutControllerTest.php b/tests/Unit/Controllers/LogoutControllerTest.php new file mode 100644 index 00000000..a9e1e296 --- /dev/null +++ b/tests/Unit/Controllers/LogoutControllerTest.php @@ -0,0 +1,63 @@ +group('stateful', 'controller', 'controller.stateful', 'controller.stateful.logout'); + +beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), + ]); + + $this->laravel = app('auth0'); + $this->guard = auth('legacyGuard'); + $this->sdk = $this->laravel->getSdk(); + + $this->validSession = [ + 'auth0_session_user' => ['sub' => 'hello|world'], + 'auth0_session_idToken' => (string) Generator::create((createRsaKeys())->private), + 'auth0_session_accessToken' => (string) Generator::create((createRsaKeys())->private), + 'auth0_session_accessTokenScope' => [uniqid()], + 'auth0_session_accessTokenExpiration' => time() + 60, + ]; + + Route::get('/logout', LogoutController::class); +}); + +it('redirects to the home route if an incompatible guard is active', function (): void { + config($config = [ + 'auth.defaults.guard' => 'web', + 'auth.guards.legacyGuard' => null + ]); + + expect(function () { + $this->withoutExceptionHandling() + ->getJson('/logout') + ->assertStatus(Response::HTTP_INTERNAL_SERVER_ERROR); + })->toThrow(ControllerException::class); +}); + +it('redirects to the home route when a user is not already logged in', function (): void { + $this->get('/logout') + ->assertRedirect('/'); +}); + +it('redirects to the Auth0 logout endpoint', function (): void { + $this->withSession($this->validSession) + ->get('/logout') + ->assertRedirectContains('/v2/logout'); +}); diff --git a/tests/Unit/Entities/CredentialTest.php b/tests/Unit/Entities/CredentialEntityTest.php similarity index 64% rename from tests/Unit/Entities/CredentialTest.php rename to tests/Unit/Entities/CredentialEntityTest.php index fb736776..3b0c491f 100644 --- a/tests/Unit/Entities/CredentialTest.php +++ b/tests/Unit/Entities/CredentialEntityTest.php @@ -2,8 +2,8 @@ declare(strict_types=1); -use Auth0\Laravel\Entities\Credential; -use Auth0\Laravel\Model\Stateless\User; +use Auth0\Laravel\Entities\CredentialEntity; +use Auth0\Laravel\Users\StatelessUser; use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\SDK\Token; @@ -13,29 +13,30 @@ $this->secret = uniqid(); config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_API, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.audience' => [uniqid()], - 'auth0.clientSecret' => $this->secret, - 'auth0.tokenAlgorithm' => Token::ALGO_HS256, - 'auth0.routes.home' => '/' . uniqid(), + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.audience' => [uniqid()], + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256, ]); $this->laravel = app('auth0'); - $this->guard = auth('testGuard'); + $this->guard = auth('legacyGuard'); $this->sdk = $this->laravel->getSdk(); - $this->user = new User(['sub' => uniqid('auth0|')]); - $this->idToken = uniqid(); - $this->accessToken = uniqid(); + $this->user = new StatelessUser(['sub' => uniqid('auth0|')]); + $this->idToken = mockIdToken(algorithm: Token::ALGO_HS256); + $this->accessToken = mockAccessToken(algorithm: Token::ALGO_HS256); $this->accessTokenScope = ['openid', 'profile', 'email', uniqid()]; + $this->accessTokenDecoded = [uniqid(), ['hello' => 'world']]; $this->accessTokenExpiration = time() + 3600; $this->refreshToken = uniqid(); }); test('create() returns a properly configured instance', function (): void { - $credential = Credential::create( + $credential = CredentialEntity::create( user: $this->user, idToken: $this->idToken, accessToken: $this->accessToken, @@ -45,7 +46,7 @@ ); expect($credential) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getUser()->toBe($this->user) ->getIdToken()->toBe($this->idToken) ->getAccessToken()->toBe($this->accessToken) @@ -55,7 +56,7 @@ }); it('clear() nullifies all properties', function (): void { - $credential = Credential::create( + $credential = CredentialEntity::create( user: $this->user, idToken: $this->idToken, accessToken: $this->accessToken, @@ -65,7 +66,7 @@ ); expect($credential) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getUser()->toBe($this->user) ->getIdToken()->toBe($this->idToken) ->getAccessToken()->toBe($this->accessToken) @@ -74,7 +75,7 @@ ->getRefreshToken()->toBe($this->refreshToken); expect($credential->clear()) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getUser()->toBeNull() ->getIdToken()->toBeNull() ->getAccessToken()->toBeNull() @@ -84,95 +85,107 @@ }); it('setUser() assigns a correct value', function (): void { - $credential = Credential::create(); + $credential = CredentialEntity::create(); expect($credential) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getUser()->toBeNull(); expect($credential->setUser($this->user)) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getUser()->toBe($this->user); }); it('setIdToken() assigns a correct value', function (): void { - $credential = Credential::create(); + $credential = CredentialEntity::create(); expect($credential) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getIdToken()->toBeNull(); expect($credential->setIdToken($this->idToken)) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getIdToken()->toBe($this->idToken); }); it('setAccessToken() assigns a correct value', function (): void { - $credential = Credential::create(); + $credential = CredentialEntity::create(); expect($credential) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getAccessToken()->toBeNull(); expect($credential->setAccessToken($this->accessToken)) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getAccessToken()->toBe($this->accessToken); }); it('setAccessTokenScope() assigns a correct value', function (): void { - $credential = Credential::create(); + $credential = CredentialEntity::create(); expect($credential) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getAccessTokenScope()->toBeNull(); expect($credential->setAccessTokenScope($this->accessTokenScope)) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getAccessTokenScope()->toBe($this->accessTokenScope); }); +it('setAccessTokenDecoded() assigns a correct value', function (): void { + $credential = CredentialEntity::create(); + + expect($credential) + ->toBeInstanceOf(CredentialEntity::class) + ->getAccessTokenDecoded()->toBeNull(); + + expect($credential->setAccessTokenDecoded($this->accessTokenDecoded)) + ->toBeInstanceOf(CredentialEntity::class) + ->getAccessTokenDecoded()->toBe($this->accessTokenDecoded); +}); + it('setAccessTokenExpiration() assigns a correct value', function (): void { - $credential = Credential::create(); + $credential = CredentialEntity::create(); expect($credential) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getAccessTokenExpiration()->toBeNull(); expect($credential->setAccessTokenExpiration($this->accessTokenExpiration)) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getAccessTokenExpiration()->toBe($this->accessTokenExpiration); }); it('setRefreshToken() assigns a correct value', function (): void { - $credential = Credential::create(); + $credential = CredentialEntity::create(); expect($credential) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getRefreshToken()->toBeNull(); expect($credential->setRefreshToken($this->refreshToken)) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getRefreshToken()->toBe($this->refreshToken); }); it('getAccessTokenExpired() returns a correct value', function (): void { - $credential = Credential::create(); + $credential = CredentialEntity::create(); expect($credential) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getAccessTokenExpired()->toBeNull(); expect($credential->setAccessTokenExpiration($this->accessTokenExpiration)) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getAccessTokenExpired()->toBeFalse(); expect($credential->setAccessTokenExpiration($this->accessTokenExpiration - 3600 * 2)) - ->toBeInstanceOf(Credential::class) + ->toBeInstanceOf(CredentialEntity::class) ->getAccessTokenExpired()->toBeTrue(); }); it('jsonSerialize() returns a correct structure', function (): void { - $credential = Credential::create( + $credential = CredentialEntity::create( user: $this->user, idToken: $this->idToken, accessToken: $this->accessToken, diff --git a/tests/Unit/Entities/InstanceEntityTest.php b/tests/Unit/Entities/InstanceEntityTest.php new file mode 100644 index 00000000..58c7cc3b --- /dev/null +++ b/tests/Unit/Entities/InstanceEntityTest.php @@ -0,0 +1,62 @@ +group('Entities/InstanceEntity'); + +beforeEach(function (): void { +}); + +it('instantiates an empty configuration if a non-array is supplied', function (): void { + config(['auth0' => true]); + + (new InstanceEntity())->getConfiguration(); +})->throws(ConfigurationException::class); + +test('setGuardConfigurationKey() sets the guard configuration key', function (): void { + $key = uniqid(); + $instance = new InstanceEntity(); + $instance->setGuardConfigurationKey($key); + + expect($instance->getGuardConfigurationKey()) + ->toBe($key); +}); + +test('setConfiguration sets the configuration using an SdkConfiguration', function (): void { + $instance = new InstanceEntity(); + $configuration = new SdkConfiguration(['strategy' => 'none', 'domain' => uniqid() . '.auth0.test']); + + $instance->setConfiguration($configuration); + + expect($instance->getConfiguration()) + ->toBe($configuration); +}); + +test('setConfiguration sets the configuration using an array', function (): void { + $instance = new InstanceEntity(); + $configuration = ['strategy' => 'none', 'domain' => uniqid() . '.auth0.test']; + + $instance->setConfiguration($configuration); + + expect($instance->getConfiguration()) + ->toBeInstanceOf(SdkConfiguration::class); +}); + +test('::create() sets the guard configuration key and configuration', function (): void { + $key = uniqid(); + $configuration = new SdkConfiguration(['strategy' => 'none', 'domain' => uniqid() . '.auth0.test']); + $instance = InstanceEntity::create( + configuration: $configuration, + guardConfigurationName: $key, + ); + + expect($instance->getConfiguration()) + ->toBe($configuration); + + expect($instance->getGuardConfigurationKey()) + ->toBe($key); +}); diff --git a/tests/Unit/Guards/AuthenticationGuardTest.php b/tests/Unit/Guards/AuthenticationGuardTest.php new file mode 100644 index 00000000..834fef9f --- /dev/null +++ b/tests/Unit/Guards/AuthenticationGuardTest.php @@ -0,0 +1,431 @@ +group('auth', 'auth.guard', 'auth.guard.session'); + +beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), + ]); + + $this->laravel = app('auth0'); + $this->guard = $guard = auth('auth0-session'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + $this->session = $this->config->getSessionStorage(); + + $this->user = new StatefulUser(['sub' => uniqid('auth0|')]); + + $this->session->set('user', ['sub' => 'hello|world']); + $this->session->set('idToken', (string) Generator::create((createRsaKeys())->private)); + $this->session->set('accessToken', (string) Generator::create((createRsaKeys())->private)); + $this->session->set('accessTokenScope', [uniqid()]); + $this->session->set('accessTokenExpiration', time() + 60); + + $this->route = '/' . uniqid(); + $this->route2 = '/' . uniqid(); + $guard = $this->guard; + + Route::get($this->route, function () use ($guard) { + $credential = $guard->find(Guard::SOURCE_SESSION); + + if (null !== $credential) { + $guard->login($credential, Guard::SOURCE_SESSION); + return response()->json(['status' => 'OK']); + } + + abort(Response::HTTP_UNAUTHORIZED, 'Unauthorized'); + }); + + Route::get($this->route2, function () use ($guard) { + return response()->json(['user' => $guard->user(Guard::SOURCE_SESSION)->getAuthIdentifier()]); + }); +}); + +it('gets a user from a valid session using find()', function (): void { + getJson($this->route) + ->assertStatus(Response::HTTP_OK); + + expect($this->guard) + ->user()->getAuthIdentifier()->toBe('hello|world'); +}); + +it('gets a user from a valid session using user()', function (): void { + getJson($this->route2) + ->assertStatus(Response::HTTP_OK); + + expect($this->guard) + ->user()->getAuthIdentifier()->toBe('hello|world'); +}); + +it('updates internal and session states as appropriate', function (): void { + // Session should be available and populated + expect($this->session) + ->getAll()->not()->toBe([]); + + // Guard should pick up on the session during the HTTP request + getJson($this->route) + ->assertStatus(Response::HTTP_OK); + + // Guard should have it's state populated + expect($this->guard) + ->user()->getAuthIdentifier()->toBe('hello|world'); + + // Empty guard state + $this->guard->logout(); + + // Guard should have had it's state emptied + expect($this->guard) + ->user()->toBeNull(); + + // Session should have been emptied + expect($this->session) + ->getAll()->toBe([]); + + // HTTP request should fail without a session. + getJson($this->route) + ->assertStatus(Response::HTTP_UNAUTHORIZED); + + // Inject a new session into the store + $this->session->set('user', ['sub' => 'hello|world|two']); + + // Session should be available and populated again + expect($this->session) + ->getAll()->not()->toBe([]); + + getJson($this->route) + ->assertStatus(Response::HTTP_OK); + + // Guard should pick up on the session + expect($this->guard) + ->user()->getAuthIdentifier()->toBe('hello|world|two'); + + // Directly wipe the Laravel session, circumventing the Guard APIs + $this->session->purge(); + + // Session should be empty + expect($this->session) + ->getAll()->toBe([]); + + getJson($this->route) + ->assertStatus(Response::HTTP_UNAUTHORIZED); + + // Guard should have it's state emptied + expect($this->guard) + ->user()->toBeNull(); + + $this->session->set('user', ['sub' => 'hello|world|4']); + + // Session should be available + expect($this->session) + ->getAll()->not()->toBe([]); + + getJson($this->route) + ->assertStatus(Response::HTTP_OK); + + // Guard should pick up on the session + expect($this->guard) + ->user()->getAuthIdentifier()->toBe('hello|world|4'); + + $identifier = uniqid('auth0|'); + $user = new StatefulUser(['sub' => $identifier]); + + // Overwrite state using the Guard's login() + $this->guard->login(CredentialEntity::create( + user: $user + ), Guard::SOURCE_SESSION); + + getJson($this->route) + ->assertStatus(Response::HTTP_OK); + + // Guard should have it's state updated + expect($this->guard) + ->user()->getAuthIdentifier()->toBe($identifier); + + // Session should be updated + expect($this->session) + ->get('user')->toBe(['sub' => $identifier]); +}); + +it('creates a session from login()', function (): void { + $identifier = uniqid('auth0|'); + $accessTokenScope = [uniqid('access-token-scope-')]; + $accessTokenExpiration = time() + 60; + + $this->session->set('user', ['sub' => $identifier]); + $this->session->set('accessTokenScope', $accessTokenScope); + $this->session->set('accessTokenExpiration', $accessTokenExpiration); + + $found = $this->guard->find(Guard::SOURCE_SESSION); + + expect($found) + ->toBeInstanceOf(CredentialEntity::class); + + $this->guard->login($found, Guard::SOURCE_SESSION); + + expect($this->session) + ->get('user')->toBe(['sub' => $identifier]) + ->get('accessTokenScope')->toBe($accessTokenScope) + ->get('accessTokenExpiration')->toBe($accessTokenExpiration) + ->get('refreshToken')->toBeNull(); + + $user = new StatefulUser(['sub' => $identifier]); + + $changedRefreshToken = (string) Generator::create((createRsaKeys())->private); + + // Overwrite state using the Guard's login() + $this->guard->login(CredentialEntity::create( + user: $user, + refreshToken: $changedRefreshToken + ), Guard::SOURCE_SESSION); + + expect($this->guard) + ->user()->getAuthIdentifier()->toBe($identifier); + + expect($this->session) + ->get('user')->toBe(['sub' => $identifier]) + ->get('accessTokenScope')->toBe($accessTokenScope) + ->get('accessTokenExpiration')->toBe($accessTokenExpiration) + ->get('refreshToken')->toBe($changedRefreshToken); +}); + +it('queries the /userinfo endpoint for refreshUser()', function (): void { + $identifier = uniqid('auth0|'); + $accessTokenScope = [uniqid('access-token-scope-')]; + $accessTokenExpiration = time() + 60; + + $this->session->set('user', ['sub' => $identifier]); + $this->session->set('accessTokenScope', $accessTokenScope); + $this->session->set('accessTokenExpiration', $accessTokenExpiration); + + $found = $this->guard->find(Guard::SOURCE_SESSION); + $this->guard->login($found, Guard::SOURCE_SESSION); + + expect($this->session) + ->get('user')->toBe(['sub' => $identifier]); + + $response = (new ResponseFactory)->createResponse(); + + $this->guard + ->sdk() + ->configuration() + ->getHttpClient() + ->addResponseWildcard($response->withBody( + (new StreamFactory)->createStream( + json_encode( + value: [ + 'sub' => $identifier, + 'name' => 'John Doe', + 'email' => '...', + ], + flags: JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR + ) + ) + ) + ); + + $this->guard->refreshUser(); + + $userAttributes = $this->guard->user()->getAttributes(); + + expect($userAttributes) + ->toBeArray() + ->toMatchArray([ + 'sub' => $identifier, + 'name' => 'John Doe', + 'email' => '...', + ]); +}); + +it('does not query the /userinfo endpoint for refreshUser() if an access token is not available', function (): void { + $identifier = uniqid('auth0|'); + $accessTokenScope = [uniqid('access-token-scope-')]; + $accessTokenExpiration = time() + 60; + + $this->session->set('user', ['sub' => $identifier]); + $this->session->set('accessToken', null); + $this->session->set('accessTokenScope', $accessTokenScope); + $this->session->set('accessTokenExpiration', $accessTokenExpiration); + + $found = $this->guard->find(Guard::SOURCE_SESSION); + $this->guard->login($found, Guard::SOURCE_SESSION); + + expect($this->session) + ->get('user')->toBe(['sub' => $identifier]); + + $response = (new ResponseFactory)->createResponse(); + + $this->guard + ->sdk() + ->configuration() + ->getHttpClient() + ->addResponseWildcard($response->withBody( + (new StreamFactory)->createStream( + json_encode( + value: [ + 'sub' => $identifier, + 'name' => 'John Doe', + 'email' => '...', + ], + flags: JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR + ) + ) + ) + ); + + $this->guard + ->sdk() + ->configuration() + ->getHttpClient() + ->setRequestLimit(-1); + + $this->guard->refreshUser(); + + $userAttributes = $this->guard->user()->getAttributes(); + + expect($userAttributes) + ->toBeArray() + ->toMatchArray([ + 'sub' => $identifier, + ]); +}); + +it('rejects bad responses from the /userinfo endpoint for refreshUser()', function (): void { + $identifier = uniqid('auth0|'); + $accessTokenScope = [uniqid('access-token-scope-')]; + $accessTokenExpiration = time() + 60; + + $this->session->set('user', ['sub' => $identifier]); + $this->session->set('accessTokenScope', $accessTokenScope); + $this->session->set('accessTokenExpiration', $accessTokenExpiration); + + $found = $this->guard->find(Guard::SOURCE_SESSION); + $this->guard->login($found, Guard::SOURCE_SESSION); + + expect($this->session) + ->get('user')->toBe(['sub' => $identifier]); + + $response = (new ResponseFactory)->createResponse(); + + $this->guard + ->sdk() + ->configuration() + ->getHttpClient() + ->addResponseWildcard($response->withBody( + (new StreamFactory)->createStream( + json_encode( + value: 'bad response', + flags: JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR + ) + ) + ) + ); + + $this->guard->refreshUser(); + + $userAttributes = $this->guard->user()->getAttributes(); + + expect($userAttributes) + ->toBeArray() + ->toMatchArray([ + 'sub' => $identifier, + ]); +}); + +it('immediately invalidates an expired session when a refresh token is not available', function (): void { + $this->session->set('accessTokenExpiration', time() - 1000); + + $found = $this->guard->find(Guard::SOURCE_SESSION); + $this->guard->login($found, Guard::SOURCE_SESSION); + + expect($this->guard) + ->user()->toBeNull(); + + expect($this->session) + ->get('user')->toBeNull(); +}); + +it('invalidates an expired session when an access token fails to refresh', function (): void { + $this->session->set('accessTokenExpiration', time() - 1000); + $this->session->set('refreshToken', uniqid()); + + $found = $this->guard->find(Guard::SOURCE_SESSION); + $this->guard->login($found, Guard::SOURCE_SESSION); + + expect($this->guard) + ->user()->toBeNull(); + + expect($this->session) + ->get('user')->toBeNull(); +}); + +it('successfully continues a session when an access token succeeds is renewed', function (): void { + $this->session->set('accessTokenExpiration', time() - 1000); + $this->session->set('refreshToken', uniqid()); + + $response = (new ResponseFactory)->createResponse(); + + $token = Generator::create((createRsaKeys())->private, Token::ALGO_HS256, [ + "iss" => 'https://' . config('auth0.guards.default.domain') . '/', + "sub" => "auth0|123456", + "aud" => [ + "https://example.com/health-api", + "https://my-domain.auth0.com/userinfo", + config('auth0.guards.default.clientId') + ], + "azp" => config('auth0.guards.default.clientId'), + "exp" => time() + 60, + "iat" => time(), + "scope" => "openid profile read:patients read:admin" + ]); + + $this->guard + ->sdk() + ->configuration() + ->getHttpClient() + ->addResponseWildcard($response->withBody( + (new StreamFactory)->createStream( + json_encode( + value: [ + 'access_token' => $token->toString(), + 'expires_in' => 60, + 'scope' => 'openid profile', + 'token_type' => 'Bearer', + ], + flags: JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR + ) + ) + ) + ); + + $found = $this->guard->find(Guard::SOURCE_SESSION); + $this->guard->login($found, Guard::SOURCE_SESSION); + + expect($this->guard) + ->user()->not()->toBeNull(); + + expect($this->session) + ->get('user')->not()->toBeNull(); +}); diff --git a/tests/Unit/Guards/AuthorizationGuardTest.php b/tests/Unit/Guards/AuthorizationGuardTest.php new file mode 100644 index 00000000..4d8a7c6e --- /dev/null +++ b/tests/Unit/Guards/AuthorizationGuardTest.php @@ -0,0 +1,218 @@ +group('auth', 'auth.guard', 'auth.guard.session'); + +beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.audience' => ['https://example.com/health-api'], + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256, + ]); + + $this->laravel = app('auth0'); + $this->guard = $guard = auth('auth0-api'); + $this->sdk = $this->laravel->getSdk(); + $this->config = $this->sdk->configuration(); + + $this->identifier = 'auth0|' . uniqid(); + + $this->token = Generator::create($this->secret, Token::ALGO_HS256, [ + "iss" => 'https://' . config('auth0.guards.default.domain') . '/', + "sub" => $this->identifier, + "aud" => [ + config('auth0.guards.default.audience')[0], + "https://my-domain.auth0.com/userinfo" + ], + "azp" => config('auth0.guards.default.clientId'), + "exp" => time() + 60, + "iat" => time(), + "scope" => "openid profile read:patients read:admin" + ]); + + $this->bearerToken = ['Authorization' => 'Bearer ' . $this->token->toString()]; + + $this->route = '/' . uniqid(); + $this->route2 = '/' . uniqid(); + $guard = $this->guard; + + Route::get($this->route, function () use ($guard) { + $credential = $guard->find(Guard::SOURCE_TOKEN); + + if (null !== $credential) { + $guard->login($credential, Guard::SOURCE_TOKEN); + + return response()->json(['status' => 'OK', 'user' => $guard->user(Guard::SOURCE_TOKEN)->getAuthIdentifier()]); + } + + abort(Response::HTTP_UNAUTHORIZED, 'Unauthorized'); + }); + + Route::get($this->route2, function () use ($guard) { + return response()->json(['user' => $guard->user(Guard::SOURCE_TOKEN)?->getAuthIdentifier()]); + }); +}); + +it('assigns a user with login() from a good token', function (): void { + expect($this->guard) + ->user()->toBeNull(); + + getJson($this->route, $this->bearerToken) + ->assertStatus(Response::HTTP_OK); + + expect($this->guard) + ->user()->not()->toBeNull(); +}); + +it('assigns a user with user() from a good token', function (): void { + expect($this->guard) + ->user()->toBeNull(); + + getJson($this->route2, $this->bearerToken) + ->assertStatus(Response::HTTP_OK); + + expect($this->guard) + ->user()->not()->toBeNull(); +}); + +// it('does not assign a user from a empty token', function (): void { +// getJson($this->route, ['Authorization' => 'Bearer ']) +// ->assertStatus(Response::HTTP_UNAUTHORIZED); + +// expect($this->guard) +// ->user()->toBeNull(); +// }); + +// it('does not get a user from a bad token', function (): void { +// $this->config->setAudience(['BAD_AUDIENCE']); + +// expect($this->guard) +// ->user()->toBeNull(); + +// getJson($this->route, $this->bearerToken) +// ->assertStatus(Response::HTTP_UNAUTHORIZED); + +// expect($this->guard) +// ->user()->toBeNull(); +// }); + +it('does not query the /userinfo endpoint for refreshUser() without a bearer token', function (): void { + expect($this->guard) + ->user()->toBeNull(); + + $this->guard->setCredential(new CredentialEntity( + user: new StatelessUser(['sub' => $this->identifier]), + )); + + expect($this->guard) + ->user()->not()->toBeNull(); + + $client = new MockHttpClient(requestLimit: 0); + + $this->config->setHttpClient($client); + + $this->guard->refreshUser(); + + expect($this->guard) + ->user()->not()->toBeNull(); +}); + +it('aborts querying the /userinfo endpoint for refreshUser() when a bad response is received', function (): void { + expect($this->guard) + ->user()->toBeNull(); + + getJson($this->route2, $this->bearerToken) + ->assertStatus(Response::HTTP_OK); + + expect($this->guard) + ->user()->getAuthIdentifier()->toBe($this->identifier); + + $response = (new MockResponseFactory)->createResponse(); + + $this->guard + ->sdk() + ->configuration() + ->getHttpClient() + ->addResponseWildcard($response->withBody( + (new MockStreamFactory)->createStream( + json_encode( + value: true, + flags: JSON_PRETTY_PRINT + ) + ) + ) + ); + + $this->guard->refreshUser(); + + $userAttributes = $this->guard->user()->getAttributes(); + + expect($userAttributes) + ->toBeArray() + ->toHaveKey('sub', $this->identifier); +}); + +it('queries the /userinfo endpoint for refreshUser()', function (): void { + expect($this->guard) + ->user()->toBeNull(); + + getJson($this->route2, $this->bearerToken) + ->assertStatus(Response::HTTP_OK); + + expect($this->guard) + ->user()->getAuthIdentifier()->toBe($this->identifier); + + $response = (new MockResponseFactory)->createResponse(); + + $this->guard + ->sdk() + ->configuration() + ->getHttpClient() + ->addResponseWildcard($response->withBody( + (new MockStreamFactory)->createStream( + json_encode( + value: [ + 'sub' => $this->identifier, + 'name' => 'John Doe', + 'email' => '...', + ], + flags: JSON_PRETTY_PRINT + ) + ) + ) + ); + + $this->guard->refreshUser(); + + $userAttributes = $this->guard->user()->getAttributes(); + + expect($userAttributes) + ->toBeArray() + ->toMatchArray([ + 'sub' => $this->identifier, + 'name' => 'John Doe', + 'email' => '...', + ]); +}); diff --git a/tests/Unit/Http/Controller/Stateful/LogoutTest.php b/tests/Unit/Http/Controller/Stateful/LogoutTest.php deleted file mode 100644 index b18f365d..00000000 --- a/tests/Unit/Http/Controller/Stateful/LogoutTest.php +++ /dev/null @@ -1,57 +0,0 @@ -group('stateful', 'controller', 'controller.stateful', 'controller.stateful.logout'); - -beforeEach(function (): void { - $this->secret = uniqid(); - - config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.clientSecret' => $this->secret, - 'auth0.cookieSecret' => uniqid(), - 'auth0.routes.home' => '/' . uniqid(), - ]); - - $this->laravel = app('auth0'); - $this->guard = auth('testGuard'); - $this->sdk = $this->laravel->getSdk(); - - $this->validSession = [ - 'auth0_session_user' => ['sub' => 'hello|world'], - 'auth0_session_idToken' => uniqid(), - 'auth0_session_accessToken' => uniqid(), - 'auth0_session_accessTokenScope' => [uniqid()], - 'auth0_session_accessTokenExpiration' => time() + 60, - ]; - - Route::get('/logout', Logout::class); -}); - -it('redirects to the home route if an incompatible guard is active', function (): void { - config($config = [ - 'auth.defaults.guard' => 'web', - 'auth.guards.testGuard' => null - ]); - - $this->get('/logout') - ->assertRedirect(config('auth0.routes.home')); -}); - -it('redirects to the home route when a user is not already logged in', function (): void { - $this->get('/logout') - ->assertRedirect(config('auth0.routes.home')); -}); - -it('redirects to the Auth0 logout endpoint', function (): void { - $this->withSession($this->validSession) - ->get('/logout') - ->assertRedirectContains('/v2/logout'); -}); diff --git a/tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php b/tests/Unit/Middleware/AuthenticateMiddlewareTest.php similarity index 76% rename from tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php rename to tests/Unit/Middleware/AuthenticateMiddlewareTest.php index fba4e642..36b7a21e 100644 --- a/tests/Unit/Http/Middleware/Stateful/AuthenticateTest.php +++ b/tests/Unit/Middleware/AuthenticateMiddlewareTest.php @@ -2,8 +2,9 @@ declare(strict_types=1); -use Auth0\Laravel\Contract\Model\Stateful\User; +use Auth0\Laravel\Users\UserContract; use Auth0\SDK\Configuration\SdkConfiguration; +use Auth0\SDK\Token\Generator; use Illuminate\Http\Response; use Illuminate\Support\Facades\Route; @@ -13,21 +14,22 @@ $this->secret = uniqid(); config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.clientSecret' => $this->secret, - 'auth0.cookieSecret' => uniqid(), + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), ]); $this->laravel = app('auth0'); - $this->guard = auth('testGuard'); + $this->guard = auth('legacyGuard'); $this->sdk = $this->laravel->getSdk(); $this->validSession = [ 'auth0_session_user' => ['sub' => 'hello|world'], - 'auth0_session_idToken' => uniqid(), - 'auth0_session_accessToken' => uniqid(), + 'auth0_session_idToken' => (string) Generator::create((createRsaKeys())->private), + 'auth0_session_accessToken' => (string) Generator::create((createRsaKeys())->private), 'auth0_session_accessTokenScope' => [uniqid(), 'read:admin'], 'auth0_session_accessTokenExpiration' => time() + 60, ]; @@ -42,7 +44,7 @@ config($config = [ 'auth.defaults.guard' => 'web', - 'auth.guards.testGuard' => null + 'auth.guards.legacyGuard' => null ]); $this->get($route) @@ -59,12 +61,8 @@ return $route; }); - config($config = [ - 'auth0.routes.login' => '/' . uniqid() - ]); - $this->get($route) - ->assertRedirect($config['auth0.routes.login']); + ->assertRedirect('/login'); expect(redirect()->getIntendedUrl()) ->toEqual('http://localhost/' . $route); @@ -86,7 +84,7 @@ ->assertSee($route); expect($this->guard) - ->user()->toBeInstanceOf(User::class); + ->user()->toBeInstanceOf(UserContract::class); }); it('assigns a user when using a configured scope matches', function (): void { @@ -102,7 +100,7 @@ ->assertSee($route); expect($this->guard) - ->user()->toBeInstanceOf(User::class); + ->user()->toBeInstanceOf(UserContract::class); }); it('does not assign a user when a configured scope is not matched', function (): void { diff --git a/tests/Unit/Http/Middleware/Stateful/AuthenticateOptionalTest.php b/tests/Unit/Middleware/AuthenticateOptionalMiddlewareTest.php similarity index 77% rename from tests/Unit/Http/Middleware/Stateful/AuthenticateOptionalTest.php rename to tests/Unit/Middleware/AuthenticateOptionalMiddlewareTest.php index 494d4096..5f7bbbe6 100644 --- a/tests/Unit/Http/Middleware/Stateful/AuthenticateOptionalTest.php +++ b/tests/Unit/Middleware/AuthenticateOptionalMiddlewareTest.php @@ -2,8 +2,9 @@ declare(strict_types=1); -use Auth0\Laravel\Contract\Model\Stateful\User; +use Auth0\Laravel\Users\UserContract; use Auth0\SDK\Configuration\SdkConfiguration; +use Auth0\SDK\Token\Generator; use Illuminate\Http\Response; use Illuminate\Support\Facades\Route; @@ -13,21 +14,22 @@ $this->secret = uniqid(); config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.clientSecret' => $this->secret, - 'auth0.cookieSecret' => uniqid(), + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), ]); $this->laravel = app('auth0'); - $this->guard = auth('testGuard'); + $this->guard = auth('legacyGuard'); $this->sdk = $this->laravel->getSdk(); $this->validSession = [ 'auth0_session_user' => ['sub' => 'hello|world'], - 'auth0_session_idToken' => uniqid(), - 'auth0_session_accessToken' => uniqid(), + 'auth0_session_idToken' => (string) Generator::create((createRsaKeys())->private), + 'auth0_session_accessToken' => (string) Generator::create((createRsaKeys())->private), 'auth0_session_accessTokenScope' => [uniqid(), 'read:admin'], 'auth0_session_accessTokenExpiration' => time() + 60, ]; @@ -42,7 +44,7 @@ config($config = [ 'auth.defaults.guard' => 'web', - 'auth.guards.testGuard' => null + 'auth.guards.legacyGuard' => null ]); $this->get($route) @@ -80,7 +82,7 @@ ->assertSee($route); expect($this->guard) - ->user()->toBeInstanceOf(User::class); + ->user()->toBeInstanceOf(UserContract::class); }); it('assigns a user when using a configured scope matches', function (): void { @@ -96,7 +98,7 @@ ->assertSee($route); expect($this->guard) - ->user()->toBeInstanceOf(User::class); + ->user()->toBeInstanceOf(UserContract::class); }); it('does not assign a user when a configured scope is not matched', function (): void { diff --git a/tests/Unit/Middleware/AuthenticatorMiddlewareTest.php b/tests/Unit/Middleware/AuthenticatorMiddlewareTest.php new file mode 100644 index 00000000..769b2c22 --- /dev/null +++ b/tests/Unit/Middleware/AuthenticatorMiddlewareTest.php @@ -0,0 +1,39 @@ +group('Middleware/AuthenticatorMiddleware'); + +beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_NONE, + ]); +}); + +it('installs the Auth0 Authenticator', function (): void { + config(['auth.defaults.guard' => 'web']); + app(ServiceProvider::class, ['app' => app()])->registerMiddleware(app('router')); + + Route::middleware('web')->get('/test', function (): JsonResponse { + if (auth()->guard()->name !== 'auth0-session') { + abort(Response::HTTP_INTERNAL_SERVER_ERROR); + } + + return response()->json([ + 'guard' => auth()->guard()->name, + 'middleware' => app('router')->getMiddlewareGroups() + ]); + }); + + $this->get('/test') + ->assertOK(); +}); diff --git a/tests/Unit/Http/Middleware/Stateless/AuthorizeTest.php b/tests/Unit/Middleware/AuthorizeMiddlewareTest.php similarity index 75% rename from tests/Unit/Http/Middleware/Stateless/AuthorizeTest.php rename to tests/Unit/Middleware/AuthorizeMiddlewareTest.php index e59131f2..90ff54a6 100644 --- a/tests/Unit/Http/Middleware/Stateless/AuthorizeTest.php +++ b/tests/Unit/Middleware/AuthorizeMiddlewareTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use Auth0\Laravel\Contract\Model\Stateless\User; +use Auth0\Laravel\Users\UserContract; use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\SDK\Token; use Auth0\SDK\Token\Generator; @@ -15,17 +15,18 @@ $this->secret = uniqid(); config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_API, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.audience' => [uniqid()], - 'auth0.clientSecret' => $this->secret, - 'auth0.cookieSecret' => uniqid(), - 'auth0.tokenAlgorithm' => Token::ALGO_HS256, + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.audience' => [uniqid()], + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), + 'auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256, ]); $this->laravel = app('auth0'); - $this->guard = auth('testGuard'); + $this->guard = auth('legacyGuard'); $this->sdk = $this->laravel->getSdk(); }); @@ -38,7 +39,7 @@ config([ 'auth.defaults.guard' => 'web', - 'auth.guards.testGuard' => null + 'auth.guards.legacyGuard' => null ]); $this->getJson($route, ['Authorization' => 'Bearer ' . uniqid()]) @@ -71,14 +72,14 @@ }); $token = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => 'https://' . config('auth0.domain') . '/', + "iss" => 'https://' . config('auth0.guards.default.domain') . '/', "sub" => "auth0|123456", "aud" => [ "https://example.com/health-api", "https://my-domain.auth0.com/userinfo", - config('auth0.clientId') + config('auth0.guards.default.clientId') ], - "azp" => config('auth0.clientId'), + "azp" => config('auth0.guards.default.clientId'), "exp" => time() + 60, "iat" => time(), "scope" => "openid profile read:patients read:admin" @@ -89,7 +90,7 @@ ->assertJson(['status' => $route]); expect($this->guard) - ->user()->toBeInstanceOf(User::class); + ->user()->toBeInstanceOf(UserContract::class); }); it('assigns a user when using a configured scope matches', function (): void { @@ -100,14 +101,14 @@ }); $token = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => 'https://' . config('auth0.domain') . '/', + "iss" => 'https://' . config('auth0.guards.default.domain') . '/', "sub" => "auth0|123456", "aud" => [ "https://example.com/health-api", "https://my-domain.auth0.com/userinfo", - config('auth0.clientId') + config('auth0.guards.default.clientId') ], - "azp" => config('auth0.clientId'), + "azp" => config('auth0.guards.default.clientId'), "exp" => time() + 60, "iat" => time(), "scope" => "openid profile read:patients read:admin" @@ -118,7 +119,7 @@ ->assertJson(['status' => $route]); expect($this->guard) - ->user()->toBeInstanceOf(User::class); + ->user()->toBeInstanceOf(UserContract::class); }); it('returns a 403 and does not assign a user when a configured scope is not matched', function (): void { @@ -129,14 +130,14 @@ }); $token = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => 'https://' . config('auth0.domain') . '/', + "iss" => 'https://' . config('auth0.guards.default.domain') . '/', "sub" => "auth0|123456", "aud" => [ "https://example.com/health-api", "https://my-domain.auth0.com/userinfo", - config('auth0.clientId') + config('auth0.guards.default.clientId') ], - "azp" => config('auth0.clientId'), + "azp" => config('auth0.guards.default.clientId'), "exp" => time() + 60, "iat" => time(), "scope" => "openid profile read:patients read:admin" diff --git a/tests/Unit/Http/Middleware/Stateless/AuthorizeOptionalTest.php b/tests/Unit/Middleware/AuthorizeOptionalMiddlewareTest.php similarity index 75% rename from tests/Unit/Http/Middleware/Stateless/AuthorizeOptionalTest.php rename to tests/Unit/Middleware/AuthorizeOptionalMiddlewareTest.php index aded9fa6..fa1327f7 100644 --- a/tests/Unit/Http/Middleware/Stateless/AuthorizeOptionalTest.php +++ b/tests/Unit/Middleware/AuthorizeOptionalMiddlewareTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use Auth0\Laravel\Contract\Model\Stateless\User; +use Auth0\Laravel\Users\UserContract; use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\SDK\Token; use Auth0\SDK\Token\Generator; @@ -15,17 +15,18 @@ $this->secret = uniqid(); config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_API, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.audience' => [uniqid()], - 'auth0.clientSecret' => $this->secret, - 'auth0.cookieSecret' => uniqid(), - 'auth0.tokenAlgorithm' => Token::ALGO_HS256, + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.audience' => [uniqid()], + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), + 'auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256, ]); $this->laravel = app('auth0'); - $this->guard = auth('testGuard'); + $this->guard = auth('legacyGuard'); $this->sdk = $this->laravel->getSdk(); }); @@ -38,7 +39,7 @@ config([ 'auth.defaults.guard' => 'web', - 'auth.guards.testGuard' => null + 'auth.guards.legacyGuard' => null ]); $this->getJson($route, ['Authorization' => 'Bearer ' . uniqid()]) @@ -72,14 +73,14 @@ }); $token = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => 'https://' . config('auth0.domain') . '/', + "iss" => 'https://' . config('auth0.guards.default.domain') . '/', "sub" => "auth0|123456", "aud" => [ "https://example.com/health-api", "https://my-domain.auth0.com/userinfo", - config('auth0.clientId') + config('auth0.guards.default.clientId') ], - "azp" => config('auth0.clientId'), + "azp" => config('auth0.guards.default.clientId'), "exp" => time() + 60, "iat" => time(), "scope" => "openid profile read:patients read:admin" @@ -90,7 +91,7 @@ ->assertJson(['status' => $route]); expect($this->guard) - ->user()->toBeInstanceOf(User::class); + ->user()->toBeInstanceOf(UserContract::class); }); it('assigns a user when using a configured scope matches', function (): void { @@ -101,14 +102,14 @@ }); $token = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => 'https://' . config('auth0.domain') . '/', + "iss" => 'https://' . config('auth0.guards.default.domain') . '/', "sub" => "auth0|123456", "aud" => [ "https://example.com/health-api", "https://my-domain.auth0.com/userinfo", - config('auth0.clientId') + config('auth0.guards.default.clientId') ], - "azp" => config('auth0.clientId'), + "azp" => config('auth0.guards.default.clientId'), "exp" => time() + 60, "iat" => time(), "scope" => "openid profile read:patients read:admin" @@ -119,7 +120,7 @@ ->assertJson(['status' => $route]); expect($this->guard) - ->user()->toBeInstanceOf(User::class); + ->user()->toBeInstanceOf(UserContract::class); }); it('does not assign a user when a configured scope is not matched', function (): void { @@ -130,14 +131,14 @@ }); $token = Generator::create($this->secret, Token::ALGO_HS256, [ - "iss" => 'https://' . config('auth0.domain') . '/', + "iss" => 'https://' . config('auth0.guards.default.domain') . '/', "sub" => "auth0|123456", "aud" => [ "https://example.com/health-api", "https://my-domain.auth0.com/userinfo", - config('auth0.clientId') + config('auth0.guards.default.clientId') ], - "azp" => config('auth0.clientId'), + "azp" => config('auth0.guards.default.clientId'), "exp" => time() + 60, "iat" => time(), "scope" => "openid profile read:patients read:admin" diff --git a/tests/Unit/Middleware/AuthorizerMiddlewareTest.php b/tests/Unit/Middleware/AuthorizerMiddlewareTest.php new file mode 100644 index 00000000..793fed12 --- /dev/null +++ b/tests/Unit/Middleware/AuthorizerMiddlewareTest.php @@ -0,0 +1,39 @@ +group('Middleware/AuthenticatorMiddleware'); + +beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_NONE, + ]); +}); + +it('installs the Auth0 Authenticator', function (): void { + config(['auth.defaults.guard' => 'web']); + app(ServiceProvider::class, ['app' => app()])->registerMiddleware(app('router')); + + Route::middleware('api')->get('/test', function (): JsonResponse { + if (auth()->guard()->name !== 'auth0-api') { + abort(Response::HTTP_INTERNAL_SERVER_ERROR); + } + + return response()->json([ + 'guard' => auth()->guard()->name, + 'middleware' => app('router')->getMiddlewareGroups() + ]); + }); + + $this->get('/test') + ->assertOK(); +}); diff --git a/tests/Unit/Http/Middleware/GuardTest.php b/tests/Unit/Middleware/GuardMiddlewareTest.php similarity index 83% rename from tests/Unit/Http/Middleware/GuardTest.php rename to tests/Unit/Middleware/GuardMiddlewareTest.php index a3ee7f36..170c5c2a 100644 --- a/tests/Unit/Http/Middleware/GuardTest.php +++ b/tests/Unit/Middleware/GuardMiddlewareTest.php @@ -12,7 +12,6 @@ }); it('assigns the guard for route handling', function (): void { - $routeNonexistentGuard = '/' . uniqid(); $routeMiddlewareAssignedGuard = '/' . uniqid(); $routeMiddlewareUnassignedGuard = '/' . uniqid(); $routeUnspecifiedGuard = '/' . uniqid(); @@ -26,11 +25,7 @@ return get_class(auth()->guard()); }); - Route::middleware('guard:nonexistent')->get($routeNonexistentGuard, function (): string { - return get_class(auth()->guard()); - }); - - Route::middleware('guard:testGuard')->get($routeMiddlewareAssignedGuard, function (): string { + Route::middleware('guard:legacyGuard')->get($routeMiddlewareAssignedGuard, function (): string { return get_class(auth()->guard()); }); @@ -42,9 +37,6 @@ ->assertStatus(Response::HTTP_OK) ->assertSee($defaultGuardClass); - $this->get($routeNonexistentGuard) - ->assertStatus(Response::HTTP_INTERNAL_SERVER_ERROR); - $this->get($routeMiddlewareAssignedGuard) ->assertStatus(Response::HTTP_OK) ->assertSee($sdkGuardClass); @@ -71,7 +63,7 @@ config(['auth.defaults.guard' => 'web']); - Route::middleware('guard:testGuard')->group(function () use ($routeUnspecifiedGuard, $routeMiddlewareUnassignedGuard) { + Route::middleware('guard:legacyGuard')->group(function () use ($routeUnspecifiedGuard, $routeMiddlewareUnassignedGuard) { Route::get($routeUnspecifiedGuard, function (): string { return get_class(auth()->guard()); }); diff --git a/tests/Unit/ServiceProviderTest.php b/tests/Unit/ServiceProviderTest.php index 08507343..3ed809be 100644 --- a/tests/Unit/ServiceProviderTest.php +++ b/tests/Unit/ServiceProviderTest.php @@ -2,55 +2,114 @@ declare(strict_types=1); -use Auth0\Laravel\Auth\Guard; -use Auth0\Laravel\Auth\User\Provider; -use Auth0\Laravel\Auth\User\Repository; use Auth0\Laravel\Auth0; -use Auth0\Laravel\Http\Controller\Stateful\{Callback, Login, Logout}; -use Auth0\Laravel\Http\Middleware\Stateful\{Authenticate, AuthenticateOptional}; -use Auth0\Laravel\Http\Middleware\Stateless\{Authorize, AuthorizeOptional}; -use Auth0\Laravel\Http\Middleware\Guard as ShouldUseMiddleware; -use Auth0\Laravel\Store\LaravelSession; - -uses()->group('service-provider'); +use Auth0\Laravel\Auth\Guard; +use Auth0\Laravel\Bridges\{CacheBridge, CacheItemBridge, SessionBridge}; +use Auth0\Laravel\Configuration; +use Auth0\Laravel\Controllers\{CallbackController, LoginController, LogoutController}; +use Auth0\Laravel\Entities\CredentialEntity; +use Auth0\Laravel\Guards\{AuthenticationGuard, AuthorizationGuard}; +use Auth0\Laravel\Middleware\{AuthenticateMiddleware, AuthenticateOptionalMiddleware, AuthenticatorMiddleware, AuthorizeMiddleware, AuthorizeOptionalMiddleware, AuthorizerMiddleware, GuardMiddleware}; +use Auth0\Laravel\Service; +use Auth0\Laravel\ServiceProvider; +use Auth0\Laravel\UserProvider; +use Auth0\Laravel\UserRepository; +use Auth0\Laravel\Users\ImposterUser; +use Auth0\SDK\Token\Generator; +use Illuminate\Contracts\Auth\Authenticatable; +use Illuminate\Http\Response; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Route; + +uses()->group('ServiceProvider'); + +function setupGuardImpersonation( + array $profile = [], + array $scope = [], + array $permissions = [], +): Authenticatable { + Auth::shouldUse('legacyGuard'); + + $imposter = new ImposterUser(array_merge([ + 'sub' => uniqid(), + 'name' => uniqid(), + 'email' => uniqid() . '@example.com', + ], $profile)); + + Auth::guard()->setImpersonating(CredentialEntity::create( + user: $imposter, + idToken: (string) Generator::create((createRsaKeys())->private), + accessToken: (string) Generator::create((createRsaKeys())->private), + accessTokenScope: $scope, + accessTokenDecoded: [ + 'permissions' => $permissions, + ], + )); + + return $imposter; +} + +function resetGuard( + ?Authenticatable $imposter = null, +): void { + Auth::shouldUse('web'); + + if (null !== $imposter) { + Auth::setUser($imposter); + } + + config([ + 'auth.defaults.guard' => 'web', + 'auth.guards.legacyGuard' => null, + ]); +} it('provides the expected classes', function (): void { - $service = app(\Auth0\Laravel\ServiceProvider::class, ['app' => $this->app]); + $service = app(ServiceProvider::class, ['app' => $this->app]); expect($service->provides()) ->toBe([ Auth0::class, - Authenticate::class, - AuthenticateOptional::class, - Authorize::class, - AuthorizeOptional::class, - Callback::class, + AuthenticateMiddleware::class, + AuthenticateOptionalMiddleware::class, + AuthenticationGuard::class, + AuthenticatorMiddleware::class, + AuthorizationGuard::class, + AuthorizeMiddleware::class, + AuthorizeOptionalMiddleware::class, + AuthorizerMiddleware::class, + CacheBridge::class, + CacheItemBridge::class, + CallbackController::class, + Configuration::class, Guard::class, - LaravelSession::class, - Login::class, - Logout::class, - Provider::class, - Repository::class, - ShouldUseMiddleware::class + GuardMiddleware::class, + LoginController::class, + LogoutController::class, + Service::class, + SessionBridge::class, + UserProvider::class, + UserRepository::class, ]); }); -it('creates a Auth0 singleton', function (): void { +it('creates a Service singleton with `auth0` alias', function (): void { $singleton1 = $this->app->make('auth0'); - $singleton2 = $this->app->make(Auth0::class); + $singleton2 = $this->app->make(Service::class); expect($singleton1) - ->toBeInstanceOf(Auth0::class); + ->toBeInstanceOf(Service::class); expect($singleton2) - ->toBeInstanceOf(Auth0::class); + ->toBeInstanceOf(Service::class); expect($singleton1) ->toBe($singleton2); }); it('does NOT create a Guard singleton', function (): void { - $singleton1 = $this->app->make('auth0.guard'); + $singleton1 = auth()->guard('legacyGuard'); $singleton2 = $this->app->make(Guard::class); expect($singleton1) @@ -63,128 +122,431 @@ ->not()->toBe($singleton2); }); -it('creates a Repository singleton', function (): void { +it('creates a UserRepository singleton', function (): void { $singleton1 = $this->app->make('auth0.repository'); - $singleton2 = $this->app->make(Repository::class); + $singleton2 = $this->app->make(UserRepository::class); expect($singleton1) - ->toBeInstanceOf(Repository::class); + ->toBeInstanceOf(UserRepository::class); expect($singleton2) - ->toBeInstanceOf(Repository::class); + ->toBeInstanceOf(UserRepository::class); expect($singleton1) ->toBe($singleton2); }); -it('creates a Provider singleton', function (): void { - $singleton1 = $this->app->make('auth0.provider'); - $singleton2 = $this->app->make(Provider::class); +it('does NOT a Provider singleton', function (): void { + $singleton1 = Auth::createUserProvider('auth0-provider'); + $singleton2 = $this->app->make(UserProvider::class); expect($singleton1) - ->toBeInstanceOf(Provider::class); + ->toBeInstanceOf(UserProvider::class); expect($singleton2) - ->toBeInstanceOf(Provider::class); + ->toBeInstanceOf(UserProvider::class); expect($singleton1) - ->toBe($singleton2); + ->not()->toBe($singleton2); }); -it('creates a Authenticate singleton', function (): void { - $singleton1 = $this->app->make(Authenticate::class); - $singleton2 = $this->app->make(Authenticate::class); +it('creates a AuthenticateMiddleware singleton', function (): void { + $singleton1 = $this->app->make(AuthenticateMiddleware::class); + $singleton2 = $this->app->make(AuthenticateMiddleware::class); expect($singleton1) - ->toBeInstanceOf(Authenticate::class); + ->toBeInstanceOf(AuthenticateMiddleware::class); expect($singleton2) - ->toBeInstanceOf(Authenticate::class); + ->toBeInstanceOf(AuthenticateMiddleware::class); expect($singleton1) ->toBe($singleton2); }); -it('creates a AuthenticateOptional singleton', function (): void { - $singleton1 = $this->app->make(AuthenticateOptional::class); - $singleton2 = $this->app->make(AuthenticateOptional::class); +it('creates a AuthenticateOptionalMiddleware singleton', function (): void { + $singleton1 = $this->app->make(AuthenticateOptionalMiddleware::class); + $singleton2 = $this->app->make(AuthenticateOptionalMiddleware::class); expect($singleton1) - ->toBeInstanceOf(AuthenticateOptional::class); + ->toBeInstanceOf(AuthenticateOptionalMiddleware::class); expect($singleton2) - ->toBeInstanceOf(AuthenticateOptional::class); + ->toBeInstanceOf(AuthenticateOptionalMiddleware::class); expect($singleton1) ->toBe($singleton2); }); -it('creates a Authorize singleton', function (): void { - $singleton1 = $this->app->make(Authorize::class); - $singleton2 = $this->app->make(Authorize::class); +it('creates a AuthorizeMiddleware singleton', function (): void { + $singleton1 = $this->app->make(AuthorizeMiddleware::class); + $singleton2 = $this->app->make(AuthorizeMiddleware::class); expect($singleton1) - ->toBeInstanceOf(Authorize::class); + ->toBeInstanceOf(AuthorizeMiddleware::class); expect($singleton2) - ->toBeInstanceOf(Authorize::class); + ->toBeInstanceOf(AuthorizeMiddleware::class); expect($singleton1) ->toBe($singleton2); }); -it('creates a AuthorizeOptional singleton', function (): void { - $singleton1 = $this->app->make(AuthorizeOptional::class); - $singleton2 = $this->app->make(AuthorizeOptional::class); +it('creates a AuthorizeOptionalMiddleware singleton', function (): void { + $singleton1 = $this->app->make(AuthorizeOptionalMiddleware::class); + $singleton2 = $this->app->make(AuthorizeOptionalMiddleware::class); expect($singleton1) - ->toBeInstanceOf(AuthorizeOptional::class); + ->toBeInstanceOf(AuthorizeOptionalMiddleware::class); expect($singleton2) - ->toBeInstanceOf(AuthorizeOptional::class); + ->toBeInstanceOf(AuthorizeOptionalMiddleware::class); expect($singleton1) ->toBe($singleton2); }); -it('creates a Login singleton', function (): void { - $singleton1 = $this->app->make(Login::class); - $singleton2 = $this->app->make(Login::class); +it('creates a LoginController singleton', function (): void { + $singleton1 = $this->app->make(LoginController::class); + $singleton2 = $this->app->make(LoginController::class); expect($singleton1) - ->toBeInstanceOf(Login::class); + ->toBeInstanceOf(LoginController::class); expect($singleton2) - ->toBeInstanceOf(Login::class); + ->toBeInstanceOf(LoginController::class); expect($singleton1) ->toBe($singleton2); }); -it('creates a Logout singleton', function (): void { - $singleton1 = $this->app->make(Logout::class); - $singleton2 = $this->app->make(Logout::class); +it('creates a LogoutController singleton', function (): void { + $singleton1 = $this->app->make(LogoutController::class); + $singleton2 = $this->app->make(LogoutController::class); expect($singleton1) - ->toBeInstanceOf(Logout::class); + ->toBeInstanceOf(LogoutController::class); expect($singleton2) - ->toBeInstanceOf(Logout::class); + ->toBeInstanceOf(LogoutController::class); expect($singleton1) ->toBe($singleton2); }); -it('creates a Callback singleton', function (): void { - $singleton1 = $this->app->make(Callback::class); - $singleton2 = $this->app->make(Callback::class); +it('creates a CallbackController singleton', function (): void { + $singleton1 = $this->app->make(CallbackController::class); + $singleton2 = $this->app->make(CallbackController::class); expect($singleton1) - ->toBeInstanceOf(Callback::class); + ->toBeInstanceOf(CallbackController::class); expect($singleton2) - ->toBeInstanceOf(Callback::class); + ->toBeInstanceOf(CallbackController::class); expect($singleton1) ->toBe($singleton2); }); + +test('Gate::check(`scope`) returns true when a match hits', function (): void { + setupGuardImpersonation( + scope: [uniqid(), 'testScope', uniqid()], + ); + + expect(Gate::check('scope', 'testScope')) + ->toBeTrue(); +}); + +test('Gate::check(`scope`) returns false when a match misses', function (): void { + setupGuardImpersonation( + scope: [uniqid()], + ); + + expect(Gate::check('scope', 'testScope')) + ->toBeFalse(); +}); + +test('Gate::check(`scope`) returns false when an incompatible Guard is used', function (): void { + $imposter = setupGuardImpersonation( + scope: [uniqid(), 'testScope', uniqid()], + ); + + resetGuard($imposter); + + expect(Gate::check('scope', 'testScope')) + ->toBeFalse(); +}); + +test('Gate::check(`permission`) returns true when a match hits', function (): void { + setupGuardImpersonation( + permissions: [uniqid(), 'testPermission', uniqid()], + ); + + expect(Gate::check('permission', 'testPermission')) + ->toBeTrue(); +}); + +test('Gate::check(`permission`) returns false when a match misses', function (): void { + setupGuardImpersonation( + permissions: [uniqid()], + ); + + expect(Gate::check('permission', 'testPermission')) + ->toBeFalse(); +}); + +test('Gate::check(`permission`) returns false when an incompatible Guard is used', function (): void { + $imposter = setupGuardImpersonation( + permissions: [uniqid(), 'testPermission', uniqid()], + ); + + resetGuard($imposter); + + expect(Gate::check('permission', 'testPermission')) + ->toBeFalse(); +}); + +test('policies `can(scope)` middleware returns true when a match hits', function (): void { + Route::get('/test', function () { + return response()->json(['status' => 'OK']); + })->can('scope:testScope'); + + setupGuardImpersonation( + scope: [uniqid(), 'testScope', uniqid()], + ); + + $this->getJson('/test') + ->assertOK(); +}); + +test('policies `can(scope)` middleware returns false when a match misses', function (): void { + Route::get('/test', function () { + })->can('scope:testScope'); + + setupGuardImpersonation( + scope: [uniqid()], + ); + + $this->getJson('/test') + ->assertStatus(Response::HTTP_FORBIDDEN); +}); + +test('policies `can(scope)` middleware returns false when an incompatible Guard is used', function (): void { + Route::get('/test', function () { + return response()->json(['status' => 'OK']); + })->can('scope:testScope'); + + $imposter = setupGuardImpersonation( + scope: [uniqid(), 'testScope', uniqid()], + ); + + resetGuard($imposter); + + $this->getJson('/test') + ->assertStatus(Response::HTTP_FORBIDDEN); +}); + +test('policies `can(permission)` middleware returns true when a match hits', function (): void { + Route::get('/test', function () { + return response()->json(['status' => 'OK']); + })->can('testing:123'); + + setupGuardImpersonation( + permissions: [uniqid(), 'testing:123', uniqid()], + ); + + $this->getJson('/test') + ->assertOK(); +}); + +test('policies `can(permission)` middleware returns false when a match misses', function (): void { + Route::get('/test', function () { + return response()->json(['status' => 'OK']); + })->can('testing:123'); + + setupGuardImpersonation( + permissions: [uniqid(), 'testing:456', uniqid()], + ); + + $this->getJson('/test') + ->assertStatus(Response::HTTP_FORBIDDEN); +}); + +test('policies `can(permission)` middleware returns false when an incompatible Guard is used', function (): void { + Route::get('/test', function () { + return response()->json(['status' => 'OK']); + })->can('testing:123'); + + $imposter = setupGuardImpersonation( + permissions: [uniqid(), 'testing:123', uniqid()], + ); + + resetGuard($imposter); + + $this->getJson('/test') + ->assertStatus(Response::HTTP_FORBIDDEN); +}); + +test('auth0.registerGuards === true registers guards', function (): void { + config(['auth0.registerGuards' => true]); + + $service = app(ServiceProvider::class, ['app' => $this->app]); + /** + * @var ServiceProvider $service + */ + $service->register(); + + expect(config('auth.guards.auth0-session')) + ->toBeArray() + ->toHaveKey('driver', 'auth0.authenticator') + ->toHaveKey('configuration', 'web') + ->toHaveKey('provider', 'auth0-provider'); + + expect(config('auth.guards.auth0-api')) + ->toBeArray() + ->toHaveKey('driver', 'auth0.authorizer') + ->toHaveKey('configuration', 'api') + ->toHaveKey('provider', 'auth0-provider'); + + expect(config('auth.providers.auth0-provider')) + ->toBeArray() + ->toHaveKey('driver', 'auth0.provider') + ->toHaveKey('repository', 'auth0.repository'); +}); + +test('auth0.registerGuards === true registers guards, but does not overwrite an existing auth.guards.auth0-session entry', function (): void { + config([ + 'auth0.registerGuards' => true, + 'auth.guards.auth0-session' => [ + 'driver' => 'session', + 'provider' => 'users', + ] + ]); + + $service = app(ServiceProvider::class, ['app' => $this->app]); + /** + * @var ServiceProvider $service + */ + $service->register(); + + expect(config('auth.guards.auth0-session')) + ->toBeArray() + ->toHaveKey('driver', 'session') + ->toHaveKey('provider', 'users') + ->not()->toHaveKey('configuration'); + + expect(config('auth.guards.auth0-api')) + ->toBeArray() + ->toHaveKey('driver', 'auth0.authorizer') + ->toHaveKey('configuration', 'api') + ->toHaveKey('provider', 'auth0-provider'); + + expect(config('auth.providers.auth0-provider')) + ->toBeArray() + ->toHaveKey('driver', 'auth0.provider') + ->toHaveKey('repository', 'auth0.repository'); +}); + +test('auth0.registerGuards === true registers guards, but does not overwrite an existing auth.guards.auth0-api entry', function (): void { + config([ + 'auth0.registerGuards' => true, + 'auth.guards.auth0-api' => [ + 'driver' => 'api', + 'provider' => 'users', + ] + ]); + + $service = app(ServiceProvider::class, ['app' => $this->app]); + /** + * @var ServiceProvider $service + */ + $service->register(); + + expect(config('auth.guards.auth0-session')) + ->toBeArray() + ->toHaveKey('driver', 'auth0.authenticator') + ->toHaveKey('configuration', 'web') + ->toHaveKey('provider', 'auth0-provider'); + + expect(config('auth.guards.auth0-api')) + ->toBeArray() + ->toHaveKey('driver', 'api') + ->toHaveKey('provider', 'users') + ->not()->toHaveKey('configuration'); + + expect(config('auth.providers.auth0-provider')) + ->toBeArray() + ->toHaveKey('driver', 'auth0.provider') + ->toHaveKey('repository', 'auth0.repository'); +}); + +test('auth0.registerGuards === true registers guards, but does not overwrite an existing auth.providers.auth0-provider entry', function (): void { + config([ + 'auth0.registerGuards' => true, + 'auth.providers.auth0-provider' => [ + 'driver' => 'database', + 'repository' => 'users', + ] + ]); + + $service = app(ServiceProvider::class, ['app' => $this->app]); + /** + * @var ServiceProvider $service + */ + $service->register(); + + expect(config('auth.guards.auth0-session')) + ->toBeArray() + ->toHaveKey('driver', 'auth0.authenticator') + ->toHaveKey('configuration', 'web') + ->toHaveKey('provider', 'auth0-provider'); + + expect(config('auth.guards.auth0-api')) + ->toBeArray() + ->toHaveKey('driver', 'auth0.authorizer') + ->toHaveKey('configuration', 'api') + ->toHaveKey('provider', 'auth0-provider'); + + expect(config('auth.providers.auth0-provider')) + ->toBeArray() + ->toHaveKey('driver', 'database') + ->toHaveKey('repository', 'users'); +}); + +test('auth0.registerMiddleware === true registers middleware', function (): void { + config(['auth0.registerMiddleware' => true]); + + $service = app(ServiceProvider::class, ['app' => $this->app]); + /** + * @var ServiceProvider $service + */ + $service->registerMiddleware(app('router')); + /** + * @var \Illuminate\Foundation\Http\Kernel $kernel + */ + $middleware = app('router')->getMiddlewareGroups(); + + expect($middleware) + ->toBeArray() + ->toHaveKeys(['web', 'api']); + + expect($middleware['web']) + ->toContain(AuthenticatorMiddleware::class); + + expect($middleware['api']) + ->toContain(AuthorizerMiddleware::class); +}); + +test('auth0.registerAuthenticationRoutes === true registers routes', function (): void { + config(['auth0.registerAuthenticationRoutes' => true]); + + $service = app(ServiceProvider::class, ['app' => $this->app]); + /** + * @var ServiceProvider $service + */ + $service->registerRoutes(); + $routes = (array) Route::getRoutes()->get('GET'); + + expect($routes) + ->toHaveKeys(['login', 'logout', 'callback']); +}); diff --git a/tests/Unit/Auth0Test.php b/tests/Unit/ServiceTest.php similarity index 62% rename from tests/Unit/Auth0Test.php rename to tests/Unit/ServiceTest.php index c01cf55b..9a5d0b1e 100644 --- a/tests/Unit/Auth0Test.php +++ b/tests/Unit/ServiceTest.php @@ -2,32 +2,34 @@ declare(strict_types=1); -use Auth0\Laravel\Auth0; -use Auth0\Laravel\Cache\LaravelCachePool; -use Auth0\Laravel\Store\LaravelSession; +use Auth0\Laravel\Service; +use Auth0\Laravel\Bridges\{CacheBridge, CacheBridgeContract, SessionBridgeContract}; use Auth0\SDK\Contract\Auth0Interface as SdkContract; use Auth0\SDK\Auth0 as SDKAuth0; use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\SDK\Contract\API\ManagementInterface; use Auth0\SDK\Store\MemoryStore; +use Auth0\SDK\Token\Generator; +use Illuminate\Support\Facades\Route; use Psr\Cache\CacheItemPoolInterface; +use PsrMock\Psr17\ResponseFactory; -uses()->group('auth0'); +uses()->group('Service'); beforeEach(function (): void { $this->secret = uniqid(); config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_REGULAR, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.clientSecret' => $this->secret, - 'auth0.cookieSecret' => uniqid(), - 'auth0.routes.home' => '/' . uniqid(), + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), ]); $this->laravel = app('auth0'); - $this->guard = auth('testGuard'); + $this->guard = auth('legacyGuard'); $this->sdk = $this->laravel->getSdk(); $this->config = $this->sdk->configuration(); $this->session = $this->config->getSessionStorage(); @@ -64,8 +66,8 @@ ->toBeNull(); $this->session->set('user', ['sub' => 'hello|world']); - $this->session->set('idToken', uniqid()); - $this->session->set('accessToken', uniqid()); + $this->session->set('idToken', (string) Generator::create((createRsaKeys())->private)); + $this->session->set('accessToken', (string) Generator::create((createRsaKeys())->private)); $this->session->set('accessTokenScope', [uniqid()]); $this->session->set('accessTokenExpiration', time() - 1000); @@ -106,7 +108,7 @@ }); test('bootStrategy() rejects non-string values', function (): void { - $method = new ReflectionMethod(Auth0::class, 'bootStrategy'); + $method = new ReflectionMethod(Service::class, 'bootStrategy'); $method->setAccessible(true); expect($method->invoke($this->laravel, ['strategy' => 123])) @@ -114,19 +116,19 @@ }); test('bootSessionStorage() behaves as expected', function (): void { - $method = new ReflectionMethod(Auth0::class, 'bootSessionStorage'); + $method = new ReflectionMethod(Service::class, 'bootSessionStorage'); $method->setAccessible(true); expect($method->invoke($this->laravel, [])) - ->sessionStorage->toBeInstanceOf(LaravelSession::class); + ->sessionStorage->toBeInstanceOf(SessionBridgeContract::class); expect($method->invoke($this->laravel, ['sessionStorage' => null])) - ->sessionStorage->toBeInstanceOf(LaravelSession::class); + ->sessionStorage->toBeInstanceOf(SessionBridgeContract::class); expect($method->invoke($this->laravel, ['sessionStorage' => false])) ->sessionStorage->toBeNull(); - expect($method->invoke($this->laravel, ['sessionStorage' => LaravelCachePool::class])) + expect($method->invoke($this->laravel, ['sessionStorage' => CacheBridge::class])) ->sessionStorage->toBeNull(); expect($method->invoke($this->laravel, ['sessionStorage' => MemoryStore::class])) @@ -139,19 +141,19 @@ }); test('bootTransientStorage() behaves as expected', function (): void { - $method = new ReflectionMethod(Auth0::class, 'bootTransientStorage'); + $method = new ReflectionMethod(Service::class, 'bootTransientStorage'); $method->setAccessible(true); expect($method->invoke($this->laravel, [])) - ->transientStorage->toBeInstanceOf(LaravelSession::class); + ->transientStorage->toBeInstanceOf(SessionBridgeContract::class); expect($method->invoke($this->laravel, ['transientStorage' => null])) - ->transientStorage->toBeInstanceOf(LaravelSession::class); + ->transientStorage->toBeInstanceOf(SessionBridgeContract::class); expect($method->invoke($this->laravel, ['transientStorage' => false])) ->transientStorage->toBeNull(); - expect($method->invoke($this->laravel, ['transientStorage' => LaravelCachePool::class])) + expect($method->invoke($this->laravel, ['transientStorage' => CacheBridge::class])) ->transientStorage->toBeNull(); expect($method->invoke($this->laravel, ['transientStorage' => MemoryStore::class])) @@ -164,17 +166,17 @@ }); test('bootTokenCache() behaves as expected', function (): void { - $method = new ReflectionMethod(Auth0::class, 'bootTokenCache'); + $method = new ReflectionMethod(Service::class, 'bootTokenCache'); $method->setAccessible(true); expect($method->invoke($this->laravel, [])) - ->tokenCache->toBeInstanceOf(LaravelCachePool::class); + ->tokenCache->toBeInstanceOf(CacheBridgeContract::class); expect($method->invoke($this->laravel, ['tokenCache' => null])) - ->tokenCache->toBeInstanceOf(LaravelCachePool::class); + ->tokenCache->toBeInstanceOf(CacheBridgeContract::class); - expect($method->invoke($this->laravel, ['tokenCache' => LaravelCachePool::class])) - ->tokenCache->toBeInstanceOf(LaravelCachePool::class); + expect($method->invoke($this->laravel, ['tokenCache' => CacheBridge::class])) + ->tokenCache->toBeInstanceOf(CacheBridgeContract::class); expect($method->invoke($this->laravel, ['tokenCache' => false])) ->tokenCache->toBeNull(); @@ -186,25 +188,54 @@ ->tokenCache->toBeInstanceOf(CacheItemPoolInterface::class); }); -test('bootManagementTokenCache() behaves as expected', function (): void { - $method = new ReflectionMethod(Auth0::class, 'bootManagementTokenCache'); - $method->setAccessible(true); +// test('bootManagementTokenCache() behaves as expected', function (): void { +// $method = new ReflectionMethod(Service::class, 'bootManagementTokenCache'); +// $method->setAccessible(true); - expect($method->invoke($this->laravel, [])) - ->managementTokenCache->toBeInstanceOf(LaravelCachePool::class); +// expect($method->invoke($this->laravel, [])) +// ->managementTokenCache->toBeInstanceOf(CacheBridgeContract::class); + +// expect($method->invoke($this->laravel, ['managementTokenCache' => null])) +// ->managementTokenCache->toBeInstanceOf(CacheBridgeContract::class); + +// expect($method->invoke($this->laravel, ['managementTokenCache' => CacheBridgeContract::class])) +// ->managementTokenCache->toBeInstanceOf(CacheBridgeContract::class); + +// expect($method->invoke($this->laravel, ['managementTokenCache' => false])) +// ->managementTokenCache->toBeNull(); + +// expect($method->invoke($this->laravel, ['managementTokenCache' => MemoryStore::class])) +// ->managementTokenCache->toBeNull(); + +// expect($method->invoke($this->laravel, ['managementTokenCache' => 'cache.psr6'])) +// ->managementTokenCache->toBeInstanceOf(CacheItemPoolInterface::class); +// }); - expect($method->invoke($this->laravel, ['managementTokenCache' => null])) - ->managementTokenCache->toBeInstanceOf(LaravelCachePool::class); +test('json() behaves as expected', function (): void { + $factory = new ResponseFactory; - expect($method->invoke($this->laravel, ['managementTokenCache' => LaravelCachePool::class])) - ->managementTokenCache->toBeInstanceOf(LaravelCachePool::class); + $response = $factory->createResponse(200); + $response->getBody()->write('{"foo":"bar"}'); - expect($method->invoke($this->laravel, ['managementTokenCache' => false])) - ->managementTokenCache->toBeNull(); + expect(Service::json($response)) + ->toBe(['foo' => 'bar']); + + $response = $factory->createResponse(500); + $response->getBody()->write('{"foo":"bar"}'); + + expect(Service::json($response)) + ->toBeNull(); + + $response = $factory->createResponse(200); + $response->getBody()->write(json_encode(true)); + + expect(Service::json($response)) + ->toBeNull(); +}); - expect($method->invoke($this->laravel, ['managementTokenCache' => MemoryStore::class])) - ->managementTokenCache->toBeNull(); +test('routes() behaves as expected', function (): void { + Service::routes(); - expect($method->invoke($this->laravel, ['managementTokenCache' => 'cache.psr6'])) - ->managementTokenCache->toBeInstanceOf(CacheItemPoolInterface::class); + expect((array) Route::getRoutes()->get('GET')) + ->toHaveKeys(['login', 'logout', 'callback']); }); diff --git a/tests/Unit/Traits/ActingAsAuth0UserTest.php b/tests/Unit/Traits/ActingAsAuth0UserTest.php index 5b5f7a7b..78e0b27d 100644 --- a/tests/Unit/Traits/ActingAsAuth0UserTest.php +++ b/tests/Unit/Traits/ActingAsAuth0UserTest.php @@ -2,41 +2,34 @@ declare(strict_types=1); -use Auth0\Laravel\Model\Imposter; +use Auth0\Laravel\Auth\Guard; use Auth0\Laravel\Traits\ActingAsAuth0User; +use Auth0\Laravel\Users\UserContract; use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\SDK\Token; use Illuminate\Http\Response; use Illuminate\Support\Facades\Route; -uses()->group('trait', 'impersonation'); +uses()->group('trait', 'impersonation', 'acting-as-auth0-user'); uses(ActingAsAuth0User::class); beforeEach(function (): void { $this->secret = uniqid(); - - config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_API, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.audience' => [uniqid()], - 'auth0.clientSecret' => $this->secret, - 'auth0.cookieSecret' => uniqid(), - 'auth0.tokenAlgorithm' => Token::ALGO_HS256, - ]); - - $this->laravel = app('auth0'); - $this->guard = auth('testGuard'); - $this->sdk = $this->laravel->getSdk(); - $this->user = ['sub' => uniqid(), 'scope' => 'openid profile email read:messages']; }); it('impersonates with other guards', function (): void { config([ + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), + 'auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256, 'auth.defaults.guard' => 'web', - 'auth.guards.testGuard' => null + 'auth.guards.legacyGuard' => null ]); $route = '/' . uniqid(); @@ -45,15 +38,28 @@ return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); }); - $this->actingAsAuth0User($this->user, null) + $this->actingAsAuth0User(attributes: $this->user, source: Guard::SOURCE_SESSION) ->getJson($route) ->assertStatus(Response::HTTP_OK); - expect($this->guard) - ->user()->toBeNull(); + expect(auth()->guard()->user())->not()->toBeNull(); }); it('impersonates a user against auth0.authenticate', function (): void { + config([ + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), + 'auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256, + ]); + + $this->laravel = app('auth0'); + $this->guard = auth('legacyGuard'); + $this->sdk = $this->laravel->getSdk(); + $route = '/' . uniqid(); Route::middleware('auth0.authenticate')->get($route, function () use ($route) { @@ -63,17 +69,31 @@ ]); }); - $this->actingAsAuth0User($this->user, null) + $this->actingAsAuth0User(attributes: $this->user, source: Guard::SOURCE_SESSION) ->getJson($route) ->assertStatus(Response::HTTP_OK) ->assertJson(['status' => $route]) ->assertJsonFragment(['sub' => $this->user['sub']]); expect($this->guard) - ->user()->toBeInstanceOf(Imposter::class); + ->user()->toBeInstanceOf(UserContract::class); }); it('impersonates a user against auth0.authenticate.optional', function (): void { + config([ + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), + 'auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256, + ]); + + $this->laravel = app('auth0'); + $this->guard = auth('legacyGuard'); + $this->sdk = $this->laravel->getSdk(); + $route = '/' . uniqid(); Route::middleware('auth0.authenticate.optional')->get($route, function () use ($route) { @@ -83,17 +103,31 @@ ]); }); - $this->actingAsAuth0User($this->user, null) + $this->actingAsAuth0User(attributes: $this->user, source: Guard::SOURCE_SESSION) ->getJson($route) ->assertStatus(Response::HTTP_OK) ->assertJson(['status' => $route]) ->assertJsonFragment(['sub' => $this->user['sub']]); expect($this->guard) - ->user()->toBeInstanceOf(Imposter::class); + ->user()->toBeInstanceOf(UserContract::class); }); it('impersonates a user against auth0.authenticate using a scope', function (): void { + config([ + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), + 'auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256, + ]); + + $this->laravel = app('auth0'); + $this->guard = auth('legacyGuard'); + $this->sdk = $this->laravel->getSdk(); + $route = '/' . uniqid(); Route::middleware('auth0.authenticate:read:messages')->get($route, function () use ($route) { @@ -103,17 +137,31 @@ ]); }); - $this->actingAsAuth0User($this->user, null) + $this->actingAsAuth0User(attributes: $this->user, source: Guard::SOURCE_SESSION) ->getJson($route) ->assertStatus(Response::HTTP_OK) ->assertJson(['status' => $route]) ->assertJsonFragment(['sub' => $this->user['sub']]); expect($this->guard) - ->user()->toBeInstanceOf(Imposter::class); + ->user()->toBeInstanceOf(UserContract::class); }); it('impersonates a user against auth0.authorize', function (): void { + config([ + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.audience' => [uniqid()], + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256, + ]); + + $this->laravel = app('auth0'); + $this->guard = auth('legacyGuard'); + $this->sdk = $this->laravel->getSdk(); + $route = '/' . uniqid(); Route::middleware('auth0.authorize')->get($route, function () use ($route) { @@ -123,17 +171,31 @@ ]); }); - $this->actingAsAuth0User($this->user, null) + $this->actingAsAuth0User(attributes: $this->user, source: Guard::SOURCE_TOKEN) ->getJson($route) ->assertStatus(Response::HTTP_OK) ->assertJson(['status' => $route]) ->assertJsonFragment(['sub' => $this->user['sub']]); expect($this->guard) - ->user()->toBeInstanceOf(Imposter::class); + ->user()->toBeInstanceOf(UserContract::class); }); it('impersonates a user against auth0.authorize.optional', function (): void { + config([ + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.audience' => [uniqid()], + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256, + ]); + + $this->laravel = app('auth0'); + $this->guard = auth('legacyGuard'); + $this->sdk = $this->laravel->getSdk(); + $route = '/' . uniqid(); Route::middleware('auth0.authorize.optional')->get($route, function () use ($route) { @@ -143,17 +205,31 @@ ]); }); - $this->actingAsAuth0User($this->user, null) + $this->actingAsAuth0User(attributes: $this->user, source: Guard::SOURCE_TOKEN) ->getJson($route) ->assertStatus(Response::HTTP_OK) ->assertJson(['status' => $route]) ->assertJsonFragment(['sub' => $this->user['sub']]); expect($this->guard) - ->user()->toBeInstanceOf(Imposter::class); + ->user()->toBeInstanceOf(UserContract::class); }); it('impersonates a user against auth0.authorize using a scope', function (): void { + config([ + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.audience' => [uniqid()], + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256, + ]); + + $this->laravel = app('auth0'); + $this->guard = auth('legacyGuard'); + $this->sdk = $this->laravel->getSdk(); + $route = '/' . uniqid(); Route::middleware('auth0.authorize:read:messages')->get($route, function () use ($route) { @@ -163,12 +239,12 @@ ]); }); - $this->actingAsAuth0User($this->user, null) + $this->actingAsAuth0User(attributes: $this->user, source: Guard::SOURCE_TOKEN) ->getJson($route) ->assertStatus(Response::HTTP_OK) ->assertJson(['status' => $route]) ->assertJsonFragment(['sub' => $this->user['sub']]); expect($this->guard) - ->user()->toBeInstanceOf(Imposter::class); + ->user()->toBeInstanceOf(UserContract::class); }); diff --git a/tests/Unit/Traits/ImpersonateTest.php b/tests/Unit/Traits/ImpersonateTest.php index 29c85213..830d94be 100644 --- a/tests/Unit/Traits/ImpersonateTest.php +++ b/tests/Unit/Traits/ImpersonateTest.php @@ -3,13 +3,16 @@ declare(strict_types=1); use Auth0\Laravel\Auth\Guard; -use Auth0\Laravel\Entities\Credential; -use Auth0\Laravel\Model\Stateless\User; +use Auth0\Laravel\Guards\AuthenticationGuard; +use Auth0\Laravel\Guards\AuthorizationGuard; +use Auth0\Laravel\Entities\CredentialEntity; use Auth0\Laravel\Traits\Impersonate; +use Auth0\Laravel\Users\ImposterUser; use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\SDK\Token; use Illuminate\Http\Response; use Illuminate\Support\Facades\Route; +use PsrMock\Psr18\Client as MockHttpClient; uses()->group('trait', 'impersonate'); @@ -19,32 +22,25 @@ $this->secret = uniqid(); config([ - 'auth0.strategy' => SdkConfiguration::STRATEGY_API, - 'auth0.domain' => uniqid() . '.auth0.com', - 'auth0.clientId' => uniqid(), - 'auth0.audience' => [uniqid()], - 'auth0.clientSecret' => $this->secret, - 'auth0.cookieSecret' => uniqid(), - 'auth0.tokenAlgorithm' => Token::ALGO_HS256, + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_API, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.audience' => [uniqid()], + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), + 'auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256, ]); $this->laravel = app('auth0'); - $this->guard = auth('testGuard'); + $this->guard = auth('legacyGuard'); $this->sdk = $this->laravel->getSdk(); - - $this->impersonating = Credential::create( - user: new User(['sub' => uniqid()]), - idToken: uniqid(), - accessToken: uniqid(), - accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], - accessTokenExpiration: time() + 3600 - ); }); it('impersonates with other guards', function (): void { config([ 'auth.defaults.guard' => 'web', - 'auth.guards.testGuard' => null + 'auth.guards.legacyGuard' => null ]); $route = '/' . uniqid(); @@ -53,7 +49,15 @@ return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); }); - $this->impersonate($this->impersonating) + $imposter = CredentialEntity::create( + user: new ImposterUser(['sub' => uniqid()]), + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600 + ); + + $this->impersonate($imposter) ->getJson($route) ->assertStatus(Response::HTTP_OK); @@ -68,15 +72,23 @@ return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); }); - $this->impersonate($this->impersonating, Guard::SOURCE_SESSION) + $imposter = CredentialEntity::create( + user: new ImposterUser(['sub' => uniqid()]), + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600 + ); + + $this->impersonate($imposter, Guard::SOURCE_SESSION) ->getJson($route) ->assertStatus(Response::HTTP_OK) ->assertJson(['status' => $route]) - ->assertJson(['user' => json_encode($this->impersonating->getUser())]); + ->assertJson(['user' => json_encode($imposter->getUser())]); expect($this->guard) - ->user()->toBeInstanceOf(User::class) - ->toBe($this->impersonating->getUser()); + ->user()->toBeInstanceOf(ImposterUser::class) + ->toBe($imposter->getUser()); }); it('impersonates a user against auth0.authenticate.optional', function (): void { @@ -86,15 +98,23 @@ return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); }); - $this->impersonate($this->impersonating, Guard::SOURCE_SESSION) + $imposter = CredentialEntity::create( + user: new ImposterUser(['sub' => uniqid()]), + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600 + ); + + $this->impersonate($imposter, Guard::SOURCE_SESSION) ->getJson($route) ->assertStatus(Response::HTTP_OK) ->assertJson(['status' => $route]) - ->assertJson(['user' => json_encode($this->impersonating->getUser())]); + ->assertJson(['user' => json_encode($imposter->getUser())]); expect($this->guard) - ->user()->toBeInstanceOf(User::class) - ->toBe($this->impersonating->getUser()); + ->user()->toBeInstanceOf(ImposterUser::class) + ->toBe($imposter->getUser()); }); it('impersonates a user against auth0.authenticate using a scope', function (): void { @@ -104,15 +124,23 @@ return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); }); - $this->impersonate($this->impersonating, Guard::SOURCE_SESSION) + $imposter = CredentialEntity::create( + user: new ImposterUser(['sub' => uniqid()]), + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600 + ); + + $this->impersonate($imposter, Guard::SOURCE_SESSION) ->getJson($route) ->assertStatus(Response::HTTP_OK) ->assertJson(['status' => $route]) - ->assertJson(['user' => json_encode($this->impersonating->getUser())]); + ->assertJson(['user' => json_encode($imposter->getUser())]); expect($this->guard) - ->user()->toBeInstanceOf(User::class) - ->toBe($this->impersonating->getUser()); + ->user()->toBeInstanceOf(ImposterUser::class) + ->toBe($imposter->getUser()); }); it('impersonates a user against auth0.authorize', function (): void { @@ -122,15 +150,23 @@ return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); }); - $this->impersonate($this->impersonating, Guard::SOURCE_TOKEN) + $imposter = CredentialEntity::create( + user: new ImposterUser(['sub' => uniqid()]), + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600 + ); + + $this->impersonate($imposter, Guard::SOURCE_TOKEN) ->getJson($route) ->assertStatus(Response::HTTP_OK) ->assertJson(['status' => $route]) - ->assertJson(['user' => json_encode($this->impersonating->getUser())]); + ->assertJson(['user' => json_encode($imposter->getUser())]); expect($this->guard) - ->user()->toBeInstanceOf(User::class) - ->toBe($this->impersonating->getUser()); + ->user()->toBeInstanceOf(ImposterUser::class) + ->toBe($imposter->getUser()); }); it('impersonates a user against auth0.authorize.optional', function (): void { @@ -140,31 +176,268 @@ return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); }); - $this->impersonate($this->impersonating, Guard::SOURCE_TOKEN) + $imposter = CredentialEntity::create( + user: new ImposterUser(['sub' => uniqid()]), + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600 + ); + + $this->impersonate($imposter, Guard::SOURCE_TOKEN) ->getJson($route) ->assertStatus(Response::HTTP_OK) ->assertJson(['status' => $route]) - ->assertJson(['user' => json_encode($this->impersonating->getUser())]); + ->assertJson(['user' => json_encode($imposter->getUser())]); expect($this->guard) - ->user()->toBeInstanceOf(User::class) - ->toBe($this->impersonating->getUser()); + ->user()->toBeInstanceOf(ImposterUser::class) + ->toBe($imposter->getUser()); }); it('impersonates a user against auth0.authorize using a scope', function (): void { $route = '/' . uniqid(); + $imposter = CredentialEntity::create( + user: new ImposterUser(['sub' => uniqid()]), + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600 + ); + Route::middleware('auth0.authorize:read:messages')->get($route, function () use ($route): string { return json_encode(['user' => json_encode(auth()->user()), 'status' => $route]); }); - $this->impersonate($this->impersonating, Guard::SOURCE_TOKEN) + $this->impersonate($imposter, Guard::SOURCE_TOKEN) ->getJson($route) ->assertStatus(Response::HTTP_OK) ->assertJson(['status' => $route]) - ->assertJson(['user' => json_encode($this->impersonating->getUser())]); + ->assertJson(['user' => json_encode($imposter->getUser())]); expect($this->guard) - ->user()->toBeInstanceOf(User::class) - ->toBe($this->impersonating->getUser()); + ->user()->toBeInstanceOf(ImposterUser::class) + ->toBe($imposter->getUser()); +}); + +it('AuthenticationGuard returns the impersonated user', function (): void { + config([ + 'auth.defaults.guard' => 'auth0-session', + ]); + + $route = '/' . uniqid(); + + Route::get($route, function () use ($route): string { + return json_encode(['route' => get_class(auth()->guard()), 'user' => json_encode(auth()->user()), 'status' => $route]); + }); + + $imposter = new ImposterUser(['sub' => uniqid()]); + + $credential = CredentialEntity::create( + user: $imposter, + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600, + refreshToken: uniqid(), + ); + + $response = $this->impersonate($credential) + ->getJson($route) + ->assertStatus(Response::HTTP_OK); + + expect($response->json()) + ->route->toBe(AuthenticationGuard::class) + ->user->json()->sub->toBe($imposter->getAuthIdentifier()); + + expect(auth('legacyGuard')) + ->user()->toBeNull(); + + expect(auth('auth0-api')) + ->user()->toBeNull(); + + expect(auth('auth0-session')) + ->isImpersonating()->toBeTrue() + ->user()->toEqual($imposter) + ->find()->toEqual($credential) + ->findSession()->toEqual($credential) + ->getCredential()->toEqual($credential); + + $client = new MockHttpClient(requestLimit: 0); + $this->sdk->configuration()->setHttpClient($client); + + expect(auth('auth0-session')) + ->refreshUser(); + + auth('auth0-session')->setUser(new ImposterUser(['sub' => uniqid()])); + + expect(auth('auth0-session')) + ->isImpersonating()->toBeFalse() + ->user()->not()->toEqual($imposter) + ->find()->not()->toEqual($credential) + ->findSession()->not()->toEqual($credential) + ->getCredential()->not()->toEqual($credential); +}); + +it('AuthorizationGuard returns the impersonated user', function (): void { + config([ + 'auth.defaults.guard' => 'auth0-api', + ]); + + $route = '/' . uniqid(); + + Route::get($route, function () use ($route): string { + return json_encode(['route' => get_class(auth()->guard()), 'user' => json_encode(auth()->user()), 'status' => $route]); + }); + + $imposter = new ImposterUser(['sub' => uniqid()]); + + $credential = CredentialEntity::create( + user: $imposter, + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600, + refreshToken: uniqid(), + ); + + $response = $this->impersonate($credential) + ->getJson($route) + ->assertStatus(Response::HTTP_OK); + + expect($response->json()) + ->route->toBe(AuthorizationGuard::class) + ->user->json()->sub->toBe($imposter->getAuthIdentifier()); + + expect(auth('legacyGuard')) + ->user()->toBeNull(); + + expect(auth('auth0-session')) + ->user()->toBeNull(); + + expect(auth('auth0-api')) + ->isImpersonating()->toBeTrue() + ->getImposterSource()->toBe(Guard::SOURCE_TOKEN) + ->user()->toEqual($imposter) + ->find()->toEqual($credential) + ->findToken()->toEqual($credential) + ->getCredential()->toEqual($credential); + + $client = new MockHttpClient(requestLimit: 0); + $this->sdk->configuration()->setHttpClient($client); + + expect(auth('auth0-api')) + ->refreshUser(); + + auth('auth0-api')->setUser(new ImposterUser(['sub' => uniqid()])); + + expect(auth('auth0-api')) + ->isImpersonating()->toBeFalse() + ->user()->not()->toEqual($imposter) + ->find()->not()->toEqual($credential) + ->findToken()->not()->toEqual($credential) + ->getCredential()->not()->toEqual($credential); +}); + +it('Guard returns the impersonated user', function (): void { + config([ + 'auth.defaults.guard' => 'legacyGuard', + ]); + + $route = '/' . uniqid(); + + Route::get($route, function () use ($route): string { + return json_encode(['route' => get_class(auth()->guard()), 'user' => json_encode(auth()->user()), 'status' => $route]); + }); + + $imposter = new ImposterUser(['sub' => uniqid()]); + + $credential = CredentialEntity::create( + user: $imposter, + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600, + refreshToken: uniqid(), + ); + + $response = $this->impersonate(credential: $credential, source: Guard::SOURCE_SESSION) + ->getJson($route) + ->assertStatus(Response::HTTP_OK); + + expect($response->json()) + ->route->toBe(Guard::class) + ->user->json()->sub->toBe($imposter->getAuthIdentifier()); + + expect(auth('auth0-api')) + ->user()->toBeNull(); + + expect(auth('auth0-session')) + ->user()->toBeNull(); + + expect(auth('legacyGuard')) + ->isImpersonating()->toBeTrue() + ->getImposterSource()->toBe(Guard::SOURCE_SESSION) + ->user()->toEqual($imposter) + ->find()->toEqual($credential) + ->getCredential()->toEqual($credential); + + $client = new MockHttpClient(requestLimit: 0); + $this->sdk->configuration()->setHttpClient($client); + + auth('legacyGuard')->refreshUser(); + auth('legacyGuard')->setUser(new ImposterUser(['sub' => uniqid()])); + + expect(auth('legacyGuard')) + ->isImpersonating()->toBeFalse() + ->user()->not()->toEqual($imposter) + ->find()->not()->toEqual($credential) + ->getCredential()->not()->toEqual($credential); +}); + +it('Guard clears the impersonated user during logout()', function (): void { + config([ + 'auth.defaults.guard' => 'legacyGuard', + ]); + + $route = '/' . uniqid(); + + Route::get($route, function () use ($route): string { + return json_encode(['route' => get_class(auth()->guard()), 'user' => json_encode(auth()->user()), 'status' => $route]); + }); + + $imposter = new ImposterUser(['sub' => uniqid()]); + + $credential = CredentialEntity::create( + user: $imposter, + idToken: mockIdToken(algorithm: Token::ALGO_HS256), + accessToken: mockAccessToken(algorithm: Token::ALGO_HS256), + accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], + accessTokenExpiration: time() + 3600, + refreshToken: uniqid(), + ); + + $response = $this->impersonate(credential: $credential, source: Guard::SOURCE_TOKEN) + ->getJson($route) + ->assertStatus(Response::HTTP_OK); + + expect($response->json()) + ->route->toBe(Guard::class) + ->user->json()->sub->toBe($imposter->getAuthIdentifier()); + + expect(auth('legacyGuard')) + ->isImpersonating()->toBeTrue() + ->getImposterSource()->toBe(Guard::SOURCE_TOKEN) + ->user()->toEqual($imposter) + ->find()->toEqual($credential) + ->getCredential()->toEqual($credential); + + auth('legacyGuard')->logout(); + + expect(auth('legacyGuard')) + ->isImpersonating()->toBeFalse() + ->user()->toBeNull() + ->find()->toBeNull() + ->getCredential()->toBeNull(); }); diff --git a/tests/Unit/UserProviderTest.php b/tests/Unit/UserProviderTest.php new file mode 100644 index 00000000..9b0d909c --- /dev/null +++ b/tests/Unit/UserProviderTest.php @@ -0,0 +1,159 @@ +group('UserProvider'); + +beforeEach(function (): void { + $this->secret = uniqid(); + + config([ + 'auth0.AUTH0_CONFIG_VERSION' => 2, + 'auth0.guards.default.strategy' => SdkConfiguration::STRATEGY_REGULAR, + 'auth0.guards.default.domain' => uniqid() . '.auth0.com', + 'auth0.guards.default.clientId' => uniqid(), + 'auth0.guards.default.clientSecret' => $this->secret, + 'auth0.guards.default.cookieSecret' => uniqid(), + ]); + + $this->laravel = app('auth0'); + $this->guard = auth('legacyGuard'); + $this->sdk = $this->laravel->getSdk(); +}); + +test('retrieveByToken() returns null when an incompatible guard token is used', function (): void { + config([ + 'auth.defaults.guard' => 'web', + 'auth.guards.legacyGuard' => null + ]); + + $route = '/' . uniqid(); + Route::get($route, function () { + $provider = Auth::createUserProvider('auth0-provider'); + $credential = $provider->retrieveByToken('token', ''); + + if (null === $credential) { + return response()->json(['status' => 'OK']); + } + + abort(Response::HTTP_UNAUTHORIZED, 'Unauthorized'); + }); + + $this->getJson($route) + ->assertOK(); +}); + +test('retrieveByToken() returns null when an invalid token is provided', function (): void { + config(['auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256]); + + $token = Generator::create($this->secret, Token::ALGO_HS256, [ + "iss" => 'https://0.0.0.123/' . config('auth0.guards.default.domain') . '/', + 'sub' => 'hello|world', + 'aud' => config('auth0.guards.default.clientId'), + 'iat' => time(), + 'exp' => time() + 60, + 'azp' => config('auth0.guards.default.clientId'), + 'scope' => 'openid profile email' + ], []); + + $route = '/' . uniqid(); + Route::get($route, function () use ($token) { + $provider = Auth::createUserProvider('auth0-provider'); + $credential = $provider->retrieveByToken('token', $token); + + if (null === $credential) { + return response()->json(['status' => 'OK']); + } + + abort(Response::HTTP_UNAUTHORIZED, 'Unauthorized'); + }); + + + $this->getJson($route) + ->assertOK(); +}); + +test('retrieveByToken() returns a user when a valid token is provided', function (): void { + config(['auth0.guards.default.tokenAlgorithm' => Token::ALGO_HS256]); + + $token = Generator::create($this->secret, Token::ALGO_HS256, [ + "iss" => 'https://' . config('auth0.guards.default.domain') . '/', + 'sub' => 'hello|world', + 'aud' => config('auth0.guards.default.clientId'), + 'iat' => time(), + 'exp' => time() + 60, + 'azp' => config('auth0.guards.default.clientId'), + 'scope' => 'openid profile email' + ], []); + + $route = '/' . uniqid(); + Route::get($route, function () use ($token) { + $provider = Auth::createUserProvider('auth0-provider'); + $credential = $provider->retrieveByToken('token', (string) $token); + + if (null !== $credential) { + return response()->json(['status' => 'OK']); + } + + abort(Response::HTTP_UNAUTHORIZED, 'Unauthorized'); + }); + + $this->getJson($route) + ->assertOK(); +}); + +test('validateCredentials() always returns false', function (): void { + $provider = Auth::createUserProvider('auth0-provider'); + $user = new StatefulUser(); + + expect($provider->validateCredentials($user, [])) + ->toBeFalse(); +}); + +test('getRepository() throws an error when an non-existent repository provider is set', function (): void { + $provider = new UserProvider(['model' => 'MISSING']); + $provider->getRepository(); +})->throws(BindingResolutionException::class); + +test('getRepository() throws an error when an invalid repository provider is set', function (): void { + $provider = new UserProvider(['model' => ['ARRAY']]); + $provider->getRepository(); +})->throws(BindingResolutionException::class); + +test('setRepository() sets the repository model', function (): void { + $provider = new UserProvider(['model' => uniqid()]); + $repository = new UserRepository(); + $provider->setRepository($repository::class); + + expect($provider->getRepository()) + ->toBeInstanceOf($repository::class); +}); + +test('setRepository() with the same repository identifier uses the cached repository instance', function (): void { + $provider = new UserProvider(['model' => 'MISSING']); + $repository = new UserRepository(); + + $provider->setRepository($repository::class); + + expect($provider->getRepository()) + ->toBeInstanceOf($repository::class); + + $provider->setRepository($repository::class); + + expect($provider->getRepository()) + ->toBeInstanceOf($repository::class); +}); diff --git a/tests/Unit/Auth/User/RepositoryTest.php b/tests/Unit/UserRepositoryTest.php similarity index 75% rename from tests/Unit/Auth/User/RepositoryTest.php rename to tests/Unit/UserRepositoryTest.php index 6c2911a8..2c06e9af 100644 --- a/tests/Unit/Auth/User/RepositoryTest.php +++ b/tests/Unit/UserRepositoryTest.php @@ -2,10 +2,10 @@ declare(strict_types=1); -use Auth0\Laravel\Contract\Model\Stateful\User as StatefulUser; -use Auth0\Laravel\Contract\Model\Stateless\User as StatelessUser; +use Auth0\Laravel\Users\StatefulUser; +use Auth0\Laravel\Users\StatelessUser; -uses()->group('auth', 'auth.user', 'auth.user.repository'); +uses()->group('UserRepository'); it('returns a stateful user model from session queries', function (): void { $repository = $this->app['auth0.repository']; diff --git a/tests/Unit/Model/UserTest.php b/tests/Unit/Users/UserTest.php similarity index 79% rename from tests/Unit/Model/UserTest.php rename to tests/Unit/Users/UserTest.php index 77f6a353..ec63a897 100644 --- a/tests/Unit/Model/UserTest.php +++ b/tests/Unit/Users/UserTest.php @@ -2,19 +2,19 @@ declare(strict_types=1); -use Auth0\Laravel\Model\Stateless\User; +use Auth0\Laravel\Users\ImposterUser; uses()->group('stateful', 'model', 'model.user'); it('fills attributes provided to the constructor', function (): void { - $user = new User(['testing' => 'testing']); + $user = new ImposterUser(['testing' => 'testing']); expect($user->testing) ->toBe('testing'); }); it('fills attributes', function (): void { - $user = new User(); + $user = new ImposterUser(); $user->fill(['testing' => 'testing']); expect($user->testing) @@ -22,7 +22,7 @@ }); it('sets attributes with magic', function (): void { - $user = new User(); + $user = new ImposterUser(); $user->testing = 'testing'; expect($user->testing) @@ -30,7 +30,7 @@ }); it('sets attributes', function (): void { - $user = new User(); + $user = new ImposterUser(); $user->setAttribute('testing', 'testing'); expect($user->getAttribute('testing')) @@ -38,7 +38,7 @@ }); it('gets attributes array', function (): void { - $user = new User([ + $user = new ImposterUser([ 'testing' => 'testing', 'testing2' => 'testing2', ]); @@ -50,49 +50,49 @@ }); it('supports getting the identifier', function (): void { - $user = new User(['sub' => 'testing']); + $user = new ImposterUser(['sub' => 'testing']); expect($user->getAuthIdentifier()) ->toBe('testing'); }); it('supports getting the identifier name', function (): void { - $user = new User(['sub' => 'testing']); + $user = new ImposterUser(['sub' => 'testing']); expect($user->getAuthIdentifierName()) ->toBe('id'); }); it('supports getting the password', function (): void { - $user = new User(); + $user = new ImposterUser(); expect($user->getAuthPassword()) ->toBe(''); }); it('supports getting the remember token', function (): void { - $user = new User(); + $user = new ImposterUser(); expect($user->getRememberToken()) ->toBe(''); }); it('supports getting the remember token name', function (): void { - $user = new User(); + $user = new ImposterUser(); expect($user->getRememberTokenName()) ->toBe(''); }); it('supports setting the remember token', function (): void { - $user = new User(); + $user = new ImposterUser(); expect($user->setRememberToken('testing')) ->toBeNull(); }); it('supports JSON serialization', function (): void { - $user = new User(['testing' => 'testing']); + $user = new ImposterUser(['testing' => 'testing']); expect($user->jsonSerialize()) ->toBeArray() diff --git a/tests/constants.php b/tests/constants.php deleted file mode 100644 index 174d7fd7..00000000 --- a/tests/constants.php +++ /dev/null @@ -1,3 +0,0 @@ - Date: Thu, 18 May 2023 01:06:29 -0500 Subject: [PATCH 335/525] Rename README.md --- deprecated/{DEPRECATED.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename deprecated/{DEPRECATED.md => README.md} (100%) diff --git a/deprecated/DEPRECATED.md b/deprecated/README.md similarity index 100% rename from deprecated/DEPRECATED.md rename to deprecated/README.md From 4a34c27bfca0177efd072f32292783f3565106f7 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 18 May 2023 01:06:31 -0500 Subject: [PATCH 336/525] Update UserAbstract.php --- src/Users/UserAbstract.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Users/UserAbstract.php b/src/Users/UserAbstract.php index cde1d86a..d07055b8 100644 --- a/src/Users/UserAbstract.php +++ b/src/Users/UserAbstract.php @@ -67,6 +67,8 @@ final public function jsonSerialize(): mixed /** * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + * + * @param mixed $value */ final public function setRememberToken(mixed $value): void { From 56ea0a0df5b60a03c5c32ab5711c3225009f8c6e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 18 May 2023 01:10:03 -0500 Subject: [PATCH 337/525] Update CHANGELOG.md --- CHANGELOG.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4a10ca7..73a90a5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,9 @@ | `auth0.authenticator` | `Auth0\Laravel\Auth\Guards\AuthenticationGuard` | Session-based authentication. | | `auth0.authorizer` | `Auth0\Laravel\Auth\Guards\AuthorizationGuard` | Token-based authorization. | -- These guards are compatible with Laravel's Authentication API and support the native `auth` middleware. +- These guards are compatible with Laravel's Authentication API and support the standard `auth` middleware. -- These guards are compatible with Laravel's Authorization API and support the native `can` middleware, and the `Guard` facade, and work with the Policies API. +- These guards are compatible with Laravel's Authorization API and support the standard `can` middleware, and the `Guard` facade, and work with the Policies API. - 3 new pre-built Guards are available: `scope` and `permission`, as well as a dynamic `*:*`. This enables you to verify whether the user's access token has a particular scope or (if RBAC is enabled on the Auth0 API) a particular permission. For example `Gate::check('scope', 'email')` or `Route::get(/*...*/)->can('read:messages')`. @@ -23,15 +23,15 @@ - The SDK now automatically registers the Authentication routes. Manual route setup in `routes/web.php` is no longer necessary. -- 2 new routing Middleware have been added: `Auth0\Laravel\Http\Middleware\Authenticator` and `Auth0\Laravel\Http\Middleware\Authorizer`. These are automatically registered with your Laravel application, and ensure the Auth0 Guards are used for authentication and authorization, respectively. This replaces the need for the `guard` middleware or otherwise manual Guard assignment in your routes. +- 2 new routing Middleware have been added: `Auth0\Laravel\Http\Middleware\AuthenticatorMiddleware` and `Auth0\Laravel\Http\Middleware\AuthorizerMiddleware`. These are automatically registered with your Laravel application, and ensure the Auth0 Guards are used for authentication for `web` routes and authorization for `api` routes, respectively. This replaces the need for the `guard` middleware or otherwise manual Guard assignment in your routes. ### Improved -- We've introduced **a new configuration syntax**. This new syntax is more flexible and allows for more complex configuration scenarios. It also allows more efficient configuration of multiple guards. Developers using the previous syntax will have their existing configurations applied to all guards uniformly, to avoid a breaking change. +- We've introduced **a new configuration syntax**. This new syntax is more flexible and allows for more complex configuration scenarios, and introduces support for multiple guard instances. Developers using the previous syntax will have their existing configurations applied to all guards uniformly. - The SDK can now **configure itself using a `.auth0.json` file in the project root directory**. This file can be generated [using the Auth0 CLI](./docs/JSON%20Configuration.md), and provides a significantly simpler configuration experience for developers. -- The previous `auth0.guard` Guard (`Auth0\Laravel\Auth\Guard`) has been **refactored** as a lightweight wrapper around the new `SessionGuard` and `TokenGuard` guards. +- The previous `auth0.guard` Guard (`Auth0\Laravel\Auth\Guard`) has been **refactored** as a lightweight wrapper around the new `AuthenticationGuard` and `AuthorizationGuard` guards. ## [7.7.0](https://github.com/auth0/laravel-auth0/tree/7.7.0) (2023-04-26) From 39e30184803153d3443af3ed88693af26d9a9eb6 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 18 May 2023 01:10:20 -0500 Subject: [PATCH 338/525] Update ServiceAbstract.php --- src/ServiceAbstract.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceAbstract.php b/src/ServiceAbstract.php index fea06280..e94dfdeb 100644 --- a/src/ServiceAbstract.php +++ b/src/ServiceAbstract.php @@ -22,7 +22,7 @@ abstract class ServiceAbstract extends InstanceEntityAbstract * * @var string */ - public const VERSION = '7.7.0'; + public const VERSION = '7.8.0'; /** * Decode a PSR-7 HTTP Response Message containing a JSON content body to a PHP array. Returns null if the response was not successful, or the response body was not JSON. From ce5994fce4f0ea0e058d031fbfe06187a13598e3 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 18 May 2023 01:10:33 -0500 Subject: [PATCH 339/525] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73a90a5c..2cfbcbf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [Unreleased] +## [7.8.0] ### Added From 507f5a7336a4df8c51ee0fab3517f1996c5aa62b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 18 May 2023 02:35:38 -0500 Subject: [PATCH 340/525] Update EXAMPLES.md --- EXAMPLES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index b497cf26..a6661d6d 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -37,7 +37,7 @@ Route::get('/api/private-scoped', function () { 'authorized' => Auth::check(), 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, ], 200, [], JSON_PRETTY_PRINT); -})->middleware(['auth0.authorize:read:messages']); +})->can('read:messages'); ``` ## Events @@ -66,7 +66,7 @@ use Illuminate\Support\Facades\Route; uses(Impersonate::class); it('impersonates a user for the request', function (): void { - Route::middleware('auth0.authorize')->get('/example', function () use ($route): string { + Route::get('/example', function () use ($route): string { return response()->json('Hello World'); }); From 1af131f234d455da50d324513894212139838a5e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 19 May 2023 13:15:40 -0500 Subject: [PATCH 341/525] Fix: Exception when parsing `.env` with comments (#395) --- src/Configuration.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Configuration.php b/src/Configuration.php index 9814a4f2..6f37ab7c 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -294,6 +294,8 @@ public static function get( /** * @codeCoverageIgnore + * + * @psalm-suppress DocblockTypeContradiction */ public static function getEnvironment(): array { @@ -323,7 +325,22 @@ public static function getEnvironment(): array } foreach ($contents as $content) { + if (1 !== mb_substr_count($content, '=')) { + continue; + } + [$k,$v] = explode('=', $content); + + // @phpstan-ignore-next-line + if (! is_string($k)) { + continue; + } + + // @phpstan-ignore-next-line + if (! is_string($v)) { + continue; + } + $v = trim($v); if ('' === $v) { From 80dd404231c611c55ece6174156b5b6c2b54d0db Mon Sep 17 00:00:00 2001 From: Einar Hansen <49709354+einar-hansen@users.noreply.github.com> Date: Fri, 19 May 2023 20:17:07 +0200 Subject: [PATCH 342/525] Update namespaces and aliases for classes in the configuration documentation (#396) --- docs/Configuration.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index c6730512..ae888199 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -76,12 +76,12 @@ To register the guards manually, update your `config/auth.php` file as follows: ```php 'guards' => [ 'auth0-session' => [ - 'driver' => 'auth0.authentication', + 'driver' => 'auth0.authenticator', 'provider' => 'auth0-provider', 'configuration' => 'web', ], 'auth0-api' => [ - 'driver' => 'auth0.authorization', + 'driver' => 'auth0.authorizer', 'provider' => 'auth0-provider', 'configuration' => 'api', ], @@ -89,8 +89,8 @@ To register the guards manually, update your `config/auth.php` file as follows: 'providers' => [ 'auth0-provider' => [ - 'driver' => 'auth0', - 'repository' => \Auth0\Laravel\Auth\User\Repository::class, + 'driver' => 'auth0.provider', + 'repository' => \Auth0\Laravel\UserRepository::class, ], ], ``` @@ -105,13 +105,13 @@ To register the middleware manually, update your `app/Http/Kernel.php` file as f protected $middlewareGroups = [ 'web' => [ // ... - \Auth0\Laravel\Middleware\Authenticate::class, + \Auth0\Laravel\Middleware\AuthenticatorMiddleware::class::class, // ... ], 'api' => [ // ... - \Auth0\Laravel\Middleware\Authorization::class, + \Auth0\Laravel\Middleware\AuthorizerMiddleware::class, // ... ], ]; @@ -150,11 +150,11 @@ Auth0::routes(); Or, if you prefer complete control over the routing process: ```php -use Auth0\Laravel\Controllers\{Login, Logout, Callback}; +use Auth0\Laravel\Controllers\{LoginController, LogoutController, CallbackController}; Route::group(['middleware' => ['guard:auth0-session'], static function (): void { - Route::get('/login', Login::class)->name('login'); - Route::get('/logout', Logout::class)->name('logout'); - Route::get('/callback', Callback::class)->name('callback'); + Route::get('/login', LoginController::class)->name('login'); + Route::get('/logout', LogoutController::class)->name('logout'); + Route::get('/callback', CallbackController::class)->name('callback'); }); ``` From cb38ba9882915eeb5f41079250cebf6df33e7ab5 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 19 May 2023 20:16:37 -0500 Subject: [PATCH 343/525] Update Configuration.md --- docs/Configuration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index ae888199..d3a46f5d 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -90,7 +90,7 @@ To register the guards manually, update your `config/auth.php` file as follows: 'providers' => [ 'auth0-provider' => [ 'driver' => 'auth0.provider', - 'repository' => \Auth0\Laravel\UserRepository::class, + 'repository' => 'auth0.repository', ], ], ``` @@ -105,7 +105,7 @@ To register the middleware manually, update your `app/Http/Kernel.php` file as f protected $middlewareGroups = [ 'web' => [ // ... - \Auth0\Laravel\Middleware\AuthenticatorMiddleware::class::class, + \Auth0\Laravel\Middleware\AuthenticatorMiddleware::class, // ... ], From 517e2974d44425a0ccd804e8688c0414fafbbcde Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 19 May 2023 20:16:49 -0500 Subject: [PATCH 344/525] Update Configuration.md --- docs/Configuration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index d3a46f5d..31eb0d8a 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -133,8 +133,8 @@ Auth::shouldUse('auth0-api'); By default, the SDK will register the following routes for authentication: -| Method | URI | Name | Controller | Purpose | -| ------ | ----------- | ---------- | ------------------------------------------------- | ---------------------------------- | +| Method | URI | Name | Controller | Purpose | +| ------ | ----------- | ---------- | ---------------------------------------------- | ---------------------------------- | | `GET` | `/login` | `login` | `Auth0\Laravel\Controllers\LoginController` | Initiates the authentication flow. | | `GET` | `/logout` | `logout` | `Auth0\Laravel\Controllers\LogoutController` | Logs the user out. | | `GET` | `/callback` | `callback` | `Auth0\Laravel\Controllers\CallbackController` | Handles the callback from Auth0. | From 419e66646964ab132ad5f9b9cd7549517f17f50f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 19 May 2023 20:30:44 -0500 Subject: [PATCH 345/525] Update CHANGELOG.md --- CHANGELOG.md | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cfbcbf3..1bced494 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Unreleased] + +### Fixed + +- Parsing `.env` files could throw an exception when handling non-key-value pair strings. ([\#395](https://github.com/auth0/laravel-auth0/pull/395)) + ## [7.8.0] ### Added @@ -29,7 +35,7 @@ - We've introduced **a new configuration syntax**. This new syntax is more flexible and allows for more complex configuration scenarios, and introduces support for multiple guard instances. Developers using the previous syntax will have their existing configurations applied to all guards uniformly. -- The SDK can now **configure itself using a `.auth0.json` file in the project root directory**. This file can be generated [using the Auth0 CLI](./docs/JSON%20Configuration.md), and provides a significantly simpler configuration experience for developers. +- The SDK can now **configure itself using a `.auth0.json` file in the project root directory**. This file can be generated [using the Auth0 CLI](./docs/Configuration.md), and provides a significantly simpler configuration experience for developers. - The previous `auth0.guard` Guard (`Auth0\Laravel\Auth\Guard`) has been **refactored** as a lightweight wrapper around the new `AuthenticationGuard` and `AuthorizationGuard` guards. @@ -55,7 +61,7 @@ ### Improved -- `Auth0\Laravel\Http\Middleware\Stateful\Authenticate` now remembers the intended route (using `redirect()->setIntendedUrl()`) before kicking off authentication flow redirect. Users will be returned to the memorized intended route after completing their authentication flow. ([\#364](https://github.com/auth0/laravel-auth0/pull/364)) +- `Auth0\Laravel\Http\Middleware\Stateful\Authenticate` now remembers the intended route (using `redirect()->setIntendedUrl()`) before kicking off the authentication flow redirect. Users will be returned to the memorized intended route after completing their authentication flow. ([\#364](https://github.com/auth0/laravel-auth0/pull/364)) ### Fixed @@ -81,26 +87,26 @@ This release includes support for Laravel 10, and major improvements to the inte - Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) - New `Auth0\Laravel\Traits\Imposter` trait to allow for easier testing. [Example usage](./tests/Unit/Traits/ImpersonateTest.php) -- New Exception types have been added for more precise error catching. +- New Exception types have been added for more precise error-catching. ### Improved -The following changes have no effect on the external API of this package, but may affect internal usage. +The following changes have no effect on the external API of this package but may affect internal usage. - `Guard` will now more reliably detect changes in the underlying Auth0-PHP SDK session state. - `Guard` will now more reliably sync changes back to the underlying Auth0-PHP SDK session state. -- `StateInstance` concept has been replaced by new `Credentials` entity. +- `StateInstance` concept has been replaced by a new `Credentials` entity. - `Guard` updated to use new `Credentials` entity as primary internal storage for user data. -- `Auth0\Laravel\Traits\ActingAsAuth0User` was updated to use new`Credentials` entity. -- The HTTP middleware have been refactored to more clearly differentiate between token and session based identities. -- The `authenticate`, `authenticate.optional` and `authorize.optional` HTTP middleware now support scope filtering, as `authorize` already did. +- `Auth0\Laravel\Traits\ActingAsAuth0User` was updated to use new `Credentials` entity. +- The HTTP middleware has been refactored to more clearly differentiate between token and session-based identities. +- The `authenticate`, `authenticate.optional` and `authorize.optional` HTTP middleware now supports scope filtering, as `authorize` already did. - Upgraded test suite to use PEST 2.0 framework. - Updated test coverage to 100%. ### Fixed -- A 'Session store not set on request' error could occur when downstream applications implemented unit testing that use the Guard. This should be resolved now. +- A 'Session store not set on request' error could occur when downstream applications implemented unit testing that uses the Guard. This should be resolved now. - `Guard` would not always honor the `provider` configuration value in `config/auth.php`. - `Guard` is no longer defined as a Singleton to better support applications that need multi-guard configurations. @@ -108,13 +114,13 @@ The following changes have no effect on the external API of this package, but ma #### Changes to `user()` behavior -This release includes a significant behavior change around the `user()` method of the Guard. Previously, by simply invoking the method, the SDK would search for any available credential (access token, device session, etc.) and automatically assign the user within the Guard. The HTTP middleware have been upgraded to handle the user assignment step, and `user()` now only returns the current state of user assignment without altering it. +This release includes a significant behavior change around the `user()` method of the Guard. Previously, by simply invoking the method, the SDK would search for any available credential (access token, device session, etc.) and automatically assign the user within the Guard. The HTTP middleware has been upgraded to handle the user assignment step, and `user()` now only returns the current state of the user assignment without altering it. A new property has been added to the `config/auth0.php` configuration file: `behavior`. This is an array. At this time, there is a single option: `legacyGuardUserMethod`, a bool. If this value is set to true, or if the key is missing, the previously expected behavior will be applied, and `user()` will behave as it did before this release. The property defaults to `false`. #### Changes to Guard and Provider driver aliases -We identified an issue with using identical alias naming for both the Guard and Provider singletons under Laravel 10, which has required us to rename these aliases. As previous guidance had been to instantiate these using their class names, this should not be a breaking change in most cases. However, if you had used `auth0` as the name for either the Guard or the Provider drivers, kindly note that these have changed. Please use `auth0.guard` for the Guard driver, and `auth0.provider` for the Provider driver. This is a regrettable change, but was necessary for adequate Laravel 10 support. +We identified an issue with using identical alias naming for both the Guard and Provider singletons under Laravel 10, which has required us to rename these aliases. As previous guidance had been to instantiate these using their class names, this should not be a breaking change in most cases. However, if you had used `auth0` as the name for either the Guard or the Provider drivers, kindly note that these have changed. Please use `auth0.guard` for the Guard driver and `auth0.provider`` for the Provider driver. This is a regrettable change but was necessary for adequate Laravel 10 support. ## [7.4.0](https://github.com/auth0/laravel-auth0/tree/7.4.0) (2022-12-12) @@ -146,7 +152,7 @@ We identified an issue with using identical alias naming for both the Guard and ### Fixed - `Auth0\Laravel\Auth0` no longer requires a session configuration for stateless strategies, restoring previous behavior. [\#317](https://github.com/auth0/laravel-auth0/pull/317) -- The SDK now requires `^3.0` of the `psr/cache` dependency, to accomodate breaking changes made in the upstream interface (typed parameters and return types) for PHP 8.0+. [\#316](https://github.com/auth0/laravel-auth0/pull/316) +- The SDK now requires `^3.0` of the `psr/cache` dependency, to accommodate breaking changes made in the upstream interface (typed parameters and return types) for PHP 8.0+. [\#316](https://github.com/auth0/laravel-auth0/pull/316) ## [7.2.0](https://github.com/auth0/laravel-auth0/tree/7.2.0) (2022-10-10) @@ -165,7 +171,7 @@ We identified an issue with using identical alias naming for both the Guard and ### Improved - Return interfaces instead of concrete classes [\#296](https://github.com/auth0/laravel-auth0/pull/296) -- change: Use class names for app() calls [\#291](https://github.com/auth0/laravel-auth0/pull/291) +- change: Use class names for `app()` calls [\#291](https://github.com/auth0/laravel-auth0/pull/291) ### Fixed From 49468095cb13a8308b5066164dd59ced44a7e3c0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 19 May 2023 20:31:03 -0500 Subject: [PATCH 346/525] Update ServiceAbstract.php --- src/ServiceAbstract.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceAbstract.php b/src/ServiceAbstract.php index e94dfdeb..88b93ce5 100644 --- a/src/ServiceAbstract.php +++ b/src/ServiceAbstract.php @@ -22,7 +22,7 @@ abstract class ServiceAbstract extends InstanceEntityAbstract * * @var string */ - public const VERSION = '7.8.0'; + public const VERSION = '7.8.1'; /** * Decode a PSR-7 HTTP Response Message containing a JSON content body to a PHP array. Returns null if the response was not successful, or the response body was not JSON. From 46bfd0a4dfbf3c797c16f49ca6ef96db65aed604 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 19 May 2023 20:31:15 -0500 Subject: [PATCH 347/525] Update Bug Report.yml --- .github/ISSUE_TEMPLATE/Bug Report.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index d5b9e6ca..038592dd 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -22,6 +22,7 @@ body: label: SDK Version description: What version of our Laravel plugin are you running? (`composer show | grep auth0/login`) options: + - SDK 7.8 - SDK 7.7 - SDK 7.6 - SDK 7.5 From 1af99f91a2894e6e21e391ed0447c2f3e1040240 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 19 May 2023 20:33:18 -0500 Subject: [PATCH 348/525] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bced494..48911e7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,12 @@ # Changelog -## [Unreleased] +## [7.8.1](https://github.com/auth0/laravel-auth0/tree/7.8.1) (2023-05-19) ### Fixed - Parsing `.env` files could throw an exception when handling non-key-value pair strings. ([\#395](https://github.com/auth0/laravel-auth0/pull/395)) -## [7.8.0] +## [7.8.0](https://github.com/auth0/laravel-auth0/tree/7.8.0) (2023-05-18) ### Added From d293adf15322bda9ee459ead5c1b45dc42d64668 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 19 May 2023 20:34:19 -0500 Subject: [PATCH 349/525] Update Configuration.md --- docs/Configuration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 31eb0d8a..4a8c5b56 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -1,6 +1,6 @@ # Configuration -This document is an addendum to the [README](../README.md) file, and covers advanced configuration techniques. Please review the installation guidance there before continuing. +This document is an addendum to the [README](../README.md) file and covers advanced configuration techniques. Please review the installation guidance there before continuing. This document covers 'version 2' of the SDK configuration format. You can determine which version you are using by looking for the `Configuration::VERSION_` const returned with the `config/auth0.php` array. @@ -8,7 +8,7 @@ This document covers 'version 2' of the SDK configuration format. You can determ The SDK can automatically configure itself using the JSON files exported using the [Auth0 CLI](https://auth0.com/docs/cli). -This is the preferred method of configuration due to the ease of use. +This is the preferred method of configuration due to its ease of use. The SDK will look for the following files in the root of your project, in the order listed: From 5c1c698e53b66522bc3dfd01da1622f5d2c02b84 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 19 May 2023 20:35:22 -0500 Subject: [PATCH 350/525] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48911e7b..7ffa934d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Fixed -- Parsing `.env` files could throw an exception when handling non-key-value pair strings. ([\#395](https://github.com/auth0/laravel-auth0/pull/395)) +- Resolved an issue where parsing `.env` files could sometimes throw an exception when handling non-key-value pair strings. ([\#395](https://github.com/auth0/laravel-auth0/pull/395)) ## [7.8.0](https://github.com/auth0/laravel-auth0/tree/7.8.0) (2023-05-18) From a99084b7698fb012b6fa2c91a2293acdad0cf9b8 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 01:14:21 -0500 Subject: [PATCH 351/525] Update Installation.md --- docs/Installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Installation.md b/docs/Installation.md index 68c81dab..2e9b592b 100644 --- a/docs/Installation.md +++ b/docs/Installation.md @@ -1,6 +1,6 @@ # Installation -This document is an addendum to the [README](../README.md) file, and covers advanced installation techniques. Please review the installation guidance there before continuing. +This document is an addendum to the [README](../README.md) file and covers advanced installation techniques. Please review the installation guidance there before continuing. ## Alternative Configuration Methods From de7a90f8d8622af3ddf943502037cee8ef3e7eaa Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 01:14:26 -0500 Subject: [PATCH 352/525] Update README.md --- README.md | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 72e4114c..6861ccb6 100644 --- a/README.md +++ b/README.md @@ -11,15 +11,27 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. ## Documentation -- Quickstarts - - [Authentication using Sessions](https://auth0.com/docs/quickstart/webapp/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) — An application that uses sessions and supports logging in, logging out, and querying user profiles. - - [Authorization using Tokens](https://auth0.com/docs/quickstart/backend/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) — A backend API service that authorizes requests using tokens from a frontend application. -- Documentation - - [Events](./docs/Events.md) — Hooking into [events](https://laravel.com/docs/10.x/events) raised by the SDK to customize behavior. - - [Management API](./docs/Management.md) — Making API calls to [Auth0 Management API endpoints](https://auth0.com/docs/api/management/v2). - - [User Models and Repositories](./docs/Users.md) — Extending the SDK to support database storage, [Eloquent](https://laravel.com/docs/10.x/eloquent), and other scenarios. - - [Examples](./EXAMPLES.md) — Solutions for other common scenarios and questions. -- [Documentation Hub](https://www.auth0.com/docs) — Learn more about integrating Auth0. +Laravel SDK Quickstart: + +- [Session-based Authentication](https://auth0.com/docs/quickstart/webapp/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) +- [Token-based Authorization](https://auth0.com/docs/quickstart/backend/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) + +Laravel SDK Documentation: + +- [Getting Started](./README.md#getting-started) — Installing and configuring the SDK. +- [Examples](./EXAMPLES.md) — Answers and solutions for common questions and scenarios. +- Additional Reference: + - [docs/Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. + - [docs/Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. + - [docs/Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2). + - [docs/Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent). + - [docs/Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. + +Auth0: + +- [Documentation](https://www.auth0.com/docs) +- [Management API Explorer](https://auth0.com/docs/api/management/v2) +- [Authentication API Explorer](https://auth0.com/docs/api/authentication) ## Getting Started @@ -112,7 +124,7 @@ See [docs/Configuration](./docs/Configuration.md) for guidance on disabling auto ### Access Control -The SDK automatically registers its authentication and authorization guards into the standard `web` and `api` middleware for your Laravel application, respectively. +The SDK automatically registers its authentication and authorization guards into the standard `web` and `api` middleware groups for your Laravel application, respectively. See [docs/Configuration](./docs/Configuration.md) for guidance on disabling this automatic registration, and manually registering the guards. @@ -126,7 +138,7 @@ Route::get('/private', function () { })->middleware('auth'); ``` -You can also require the requestor have specific [permissions](https://auth0.com/docs/manage-users/access-control/rbac) by combining this with Laravel's `can` middleware: +You can also require the requestor to have specific [permissions](https://auth0.com/docs/manage-users/access-control/rbac)](https://auth0.com/docs/manage-users/access-control/rbac) by combining this with Laravel's `can` middleware: ```php Route::get('/scope', function () { @@ -222,7 +234,7 @@ The SDK supports [Laravel's Authorization API](https://laravel.com/docs/authoriz | `permission` | `Gate::check('permission', 'read:messages');` | `Route::get(/*...*/)->can('permission', 'read:messages');` | Determine if the user's access token has a specified [permission](https://auth0.com/docs/manage-users/access-control/rbac). This requires RBAC be enabled on [your Auth0 API's settings](https://manage.auth0.com/#/apis). | | `*:*` | `Gate::check('read:messages');` | `Route::get(/*...*/)->can('read:messages');` | A convenience alias for `permission` (described above), you can supply any permission string in the colon-delimited `ability:context` syntax. | -Using these gates, you can easily authorize users or access tokens to perform actions in your application. Your application can use Laravel's [Policies API](https://laravel.com/docs/10.x/authorization#creating-policies) in combination with these gates to further simplify authorization. +Using these gates, you can easily authorize users or access tokens to perform actions in your application. Your application can use Laravel's [Policies API](https://laravel.com/docs/authorization#creating-policies) in combination with these gates to further simplify authorization. ## Support Policy From 50c53b767258f4db18c1b323d41858a937d88681 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 01:15:03 -0500 Subject: [PATCH 353/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6861ccb6..e9fa0407 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. ## Documentation -Laravel SDK Quickstart: +Laravel SDK Quickstarts: - [Session-based Authentication](https://auth0.com/docs/quickstart/webapp/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) - [Token-based Authorization](https://auth0.com/docs/quickstart/backend/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) From 528c702dda0f3b3691794ead4bca017f444e628d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 01:19:43 -0500 Subject: [PATCH 354/525] Update README.md --- README.md | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index e9fa0407..622ca724 100644 --- a/README.md +++ b/README.md @@ -7,31 +7,28 @@ Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. [![Coverage](https://img.shields.io/codecov/c/github/auth0/laravel-auth0/main)](https://codecov.io/gh/auth0/laravel-auth0) [![License](https://img.shields.io/packagist/l/auth0/login)](https://doge.mit-license.org/) -:books: [Documentation](#documentation) - :rocket: [Getting Started](#getting-started) - :speech_balloon: [Feedback](#feedback) +:books: [Documentation](#documentation) — :rocket: [Getting Started](#getting-started) — :speech_balloon: [Feedback](#feedback) ## Documentation -Laravel SDK Quickstarts: +Quickstart Guides: - [Session-based Authentication](https://auth0.com/docs/quickstart/webapp/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) - [Token-based Authorization](https://auth0.com/docs/quickstart/backend/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) -Laravel SDK Documentation: +Documentation: - [Getting Started](./README.md#getting-started) — Installing and configuring the SDK. - [Examples](./EXAMPLES.md) — Answers and solutions for common questions and scenarios. -- Additional Reference: - - [docs/Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. - - [docs/Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. - - [docs/Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2). - - [docs/Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent). - - [docs/Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. - -Auth0: - -- [Documentation](https://www.auth0.com/docs) -- [Management API Explorer](https://auth0.com/docs/api/management/v2) -- [Authentication API Explorer](https://auth0.com/docs/api/authentication) +- Reference: + - [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. + - [Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. + - [Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2). + - [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent). + - [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. +- [Auth0 Documentation](https://www.auth0.com/docs) +- [Auth0 Management API Explorer](https://auth0.com/docs/api/management/v2) +- [Auth0 Authentication API Explorer](https://auth0.com/docs/api/authentication) ## Getting Started @@ -46,6 +43,8 @@ You will need to use a [supported version](#support-policy) of PHP and Laravel: You'll also need an [Auth0 account](https://auth0.com/signup), as well as [Composer](https://getcomposer.org/) and the [Auth0 CLI](https://github.com/auth0/auth0-cli). +--- + ### SDK Installation Run the following command within your project directory to install the [Auth0 Laravel SDK](https://github.com/auth0/laravel-auth0): @@ -60,6 +59,8 @@ Then generate an SDK configuration file for your application: php artisan vendor:publish --tag auth0 ``` +--- + ### SDK Configuration > **Note** @@ -110,6 +111,8 @@ As these files contain credentials it's important to treat these as sensitive. Y echo ".auth0.*.json" >> .gitignore ``` +--- + ### Authentication The SDK automatically registers all the necessary facilities within the `web` middleware group for your users to authenticate with your application. These routes are: @@ -122,6 +125,8 @@ The SDK automatically registers all the necessary facilities within the `web` mi See [docs/Configuration](./docs/Configuration.md) for guidance on disabling automatic registration, and manually registering these facilities. +--- + ### Access Control The SDK automatically registers its authentication and authorization guards into the standard `web` and `api` middleware groups for your Laravel application, respectively. @@ -149,6 +154,8 @@ Route::get('/scope', function () { > **Note** > Permissions need RBAC to be enabled on [your Auth0 API's settings](https://manage.auth0.com/#/apis). +--- + ### User and Token Information When requests are made to your application, the SDK will automatically attempt to authenticate or authorize the requestor, depending on the type of route. Information about the requesting party is expressed through the `user()` method of Laravel's `Auth` Facade, or the `auth()` helper function. @@ -187,6 +194,8 @@ Route::get('/', function () { }); ``` +--- + ### Management API You can update user information using the [Auth0 Management API](https://github.com/auth0/laravel-auth0/blob/main/docs/Management.md). All Management endpoints are accessible through the SDK's `management()` method. @@ -224,6 +233,8 @@ Route::get('/colors', function () { A quick reference guide of all the SDK's Management API methods is [available here](https://github.com/auth0/laravel-auth0/blob/main/docs/Management.md). +--- + ## Gates and Policies The SDK supports [Laravel's Authorization API](https://laravel.com/docs/authorization#main-content) and provides several convenient pre-built [Gates](https://laravel.com/docs/authorization#gates) for common tasks. @@ -236,6 +247,8 @@ The SDK supports [Laravel's Authorization API](https://laravel.com/docs/authoriz Using these gates, you can easily authorize users or access tokens to perform actions in your application. Your application can use Laravel's [Policies API](https://laravel.com/docs/authorization#creating-policies) in combination with these gates to further simplify authorization. +--- + ## Support Policy Our support lifecycle mirrors the [Laravel release support](https://laravel.com/docs/releases#support-policy) and [PHP release support](https://www.php.net/supported-versions.php) schedules. @@ -250,6 +263,8 @@ Our support lifecycle mirrors the [Laravel release support](https://laravel.com/ We drop support for Laravel and PHP versions when they reach end-of-life and cease receiving security fixes from Laravel and the PHP Foundation, whichever comes first. Please ensure your environment remains up to date so you can continue receiving updates for Laravel, PHP, and this SDK. +--- + ## Octane Support Octane compatibility is currently considered experimental and unsupported. @@ -258,6 +273,8 @@ Although we are working toward ensuring the SDK is fully compatible with this fe Feedback and bug-fix contributions are greatly appreciated as we work toward full support. +--- + ## Feedback ### Contributing From 8e4b995487423d14422e16b6f180507fc650eb26 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 03:18:07 -0500 Subject: [PATCH 355/525] Create README2.md --- README2.md | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 README2.md diff --git a/README2.md b/README2.md new file mode 100644 index 00000000..d769b58a --- /dev/null +++ b/README2.md @@ -0,0 +1,165 @@ +![laravel-auth0](https://cdn.auth0.com/website/sdks/banners/laravel-auth0-banner.png) + +

+Build Status +Code Coverage +Total Downloads +License +

+ +## Requirements + +Your application must use a [supported Laravel version](https://laravelversions.com/en), and your environment must be running a [supported PHP version](https://www.php.net/supported-versions.php). We do not support versions of Laravel or PHP that are no longer supported by their maintainers. + +| SDK | Laravel | PHP | Supported Until | +| ---- | ------- | ---- | --------------- | +| 7.5+ | 10 | 8.2+ | Feb 2025 | +| | | 8.1+ | Nov 2024 | +| 7.0+ | 9 | 8.2+ | Feb 2024 | +| | | 8.1+ | Feb 2024 | +| | | 8.0+ | Nov 2023 | + +You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). + +For the simplest integration, we recommend installing the [Auth0 CLI](https://auth0.com/docs/cli). Our documentation assumes that you have installed the CLI and are using it to configure the SDK. + +### Installation + +
+Using a Quickstart + +We provide a bootstrapped Laravel application pre-configured with the SDK that you can use to get started quickly. + +```shell +composer create-project auth0-samples/laravel auth0-laravel-app +``` +
+ +
+Using Composer + +Use Composer to install the SDK in your application: + +```shell +composer require auth0/login:^7.8 --update-with-all-dependencies +``` + +Then generate an SDK configuration file for your application: + +```shell +php artisan vendor:publish --tag auth0 +``` +
+ +### Configuration + +
+Using the Auth0 CLI (Recommended) + +You will need to download the CLI and authenticate it with your Auth0 account. You can then use it to create the configuration files for your application. + +1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your application's root directory: + + > **Note** + > If you are using the Quickstart application, the CLI was bundled for you, and you can skip to the next step. + + ```shell + curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . + ``` + +2. Then authenticate with your Auth0 account: + + ```shell + ./auth0 login + ``` + +3. Create a new application with Auth0: + + ```shell + ./auth0 apps create \ + --name "My Laravel Application" \ + --type "regular" \ + --auth-method "post" \ + --callbacks "http://localhost:8000/callback" \ + --logout-urls "http://localhost:8000/" \ + --reveal-secrets \ + --no-input \ + --json > .auth0.app.json + ``` + +4. Create a new API with Auth0 + + ```shell + ./auth0 apis create \ + --name "My Laravel Application API" \ + --identifier "https://github.com/auth0/laravel-auth0" \ + --offline-access \ + --no-input \ + --json > .auth0.api.json + ``` + +5. The files created by these commands contain sensitive credentials. It is important you do not commit these to version control. + + If you're using Git, you should add them to your `.gitignore` file: + + ```bash + echo ".auth0.*.json" >> .gitignore + ``` +
+ +
+Using Environment Variables + +
+ +## Documentation + +The documentation is divided into several sections: + +- [Getting Started](./README.md#getting-started) — Installing and configuring the SDK. +- [Examples](./EXAMPLES.md) — Answers and solutions for common questions and scenarios. +- Reference: + - [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. + - [Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. + - [Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2). + - [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent). + - [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. +- [Auth0 Documentation](https://www.auth0.com/docs) +- [Auth0 Management API Explorer](https://auth0.com/docs/api/management/v2) +- [Auth0 Authentication API Explorer](https://auth0.com/docs/api/authentication) + +You can improve it by sending pull requests to [this repository](https://github.com/auth0/laravel-auth0). + +## Examples + +We have several examples on the website. Here is the first one to get you started: + +```php + +``` + +## Community + +The main purpose of this repository is to continue evolving React core, making it faster and easier to use. Development of React happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving React. + +## Contributing + +## Code of Conduct + +## Security + +## License + +This library is open-sourced software licensed under the [MIT license](./LICENSE.md). + +--- + +

+ + + + Auth0 Logo + +

+ +

Auth0 is an easy-to-implement, adaptable authentication and authorization platform.
To learn more, check out "Why Auth0?"

From 9d06ff0a41c7838e12368bde9384397e4423ce4b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 03:21:41 -0500 Subject: [PATCH 356/525] Update README2.md --- README2.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README2.md b/README2.md index d769b58a..bcf104f2 100644 --- a/README2.md +++ b/README2.md @@ -21,12 +21,12 @@ Your application must use a [supported Laravel version](https://laravelversions. You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). -For the simplest integration, we recommend installing the [Auth0 CLI](https://auth0.com/docs/cli). Our documentation assumes that you have installed the CLI and are using it to configure the SDK. +The [Auth0 CLI](https://auth0.com/docs/cli) is recommended for configuring the SDK, but not required. ### Installation
-Using a Quickstart +

Using a Quickstart

We provide a bootstrapped Laravel application pre-configured with the SDK that you can use to get started quickly. @@ -36,7 +36,7 @@ composer create-project auth0-samples/laravel auth0-laravel-app
-Using Composer +

Using Composer

Use Composer to install the SDK in your application: From 73381632f717a0bc527abb94c28d3f6adca4adc0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 03:24:42 -0500 Subject: [PATCH 357/525] Update README2.md --- README2.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README2.md b/README2.md index bcf104f2..20b853ac 100644 --- a/README2.md +++ b/README2.md @@ -26,9 +26,9 @@ The [Auth0 CLI](https://auth0.com/docs/cli) is recommended for configuring the S ### Installation
-

Using a Quickstart

+

Using a Quickstart

-We provide a bootstrapped Laravel application pre-configured with the SDK that you can use to get started quickly. +

We provide a bootstrapped Laravel application pre-configured with the SDK that you can use to get started quickly.

```shell composer create-project auth0-samples/laravel auth0-laravel-app @@ -36,9 +36,9 @@ composer create-project auth0-samples/laravel auth0-laravel-app
-

Using Composer

+

Using Composer

-Use Composer to install the SDK in your application: +

Run the following command in your project directory to install the SDK:

```shell composer require auth0/login:^7.8 --update-with-all-dependencies From c5c7a8373853d9dba8624be7310bd2368b261493 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 03:27:21 -0500 Subject: [PATCH 358/525] Update README2.md --- README2.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README2.md b/README2.md index 20b853ac..83bb6577 100644 --- a/README2.md +++ b/README2.md @@ -26,9 +26,10 @@ The [Auth0 CLI](https://auth0.com/docs/cli) is recommended for configuring the S ### Installation
-

Using a Quickstart

-

We provide a bootstrapped Laravel application pre-configured with the SDK that you can use to get started quickly.

+Using a Quickstart + +We provide a bootstrapped Laravel application pre-configured with the SDK that you can use to get started quickly. ```shell composer create-project auth0-samples/laravel auth0-laravel-app @@ -36,7 +37,7 @@ composer create-project auth0-samples/laravel auth0-laravel-app
-

Using Composer

+Using Composer

Run the following command in your project directory to install the SDK:

From 9b3aaf55189e7af1b50c533e3f9c5bf5fcfd9406 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 03:33:10 -0500 Subject: [PATCH 359/525] Update README2.md --- README2.md | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/README2.md b/README2.md index 83bb6577..91b6b5d9 100644 --- a/README2.md +++ b/README2.md @@ -29,27 +29,27 @@ The [Auth0 CLI](https://auth0.com/docs/cli) is recommended for configuring the S Using a Quickstart -We provide a bootstrapped Laravel application pre-configured with the SDK that you can use to get started quickly. +- Run the following command to create a bootstrapped Laravel application pre-configured with the SDK: -```shell -composer create-project auth0-samples/laravel auth0-laravel-app -``` + ```shell + composer create-project auth0-samples/laravel auth0-laravel-app + ```
Using Composer -

Run the following command in your project directory to install the SDK:

+1. Run the following command in your project directory to install the SDK: -```shell -composer require auth0/login:^7.8 --update-with-all-dependencies -``` + ```shell + composer require auth0/login:^7.8 --update-with-all-dependencies + ``` -Then generate an SDK configuration file for your application: +2. Generate an SDK configuration file for your application: -```shell -php artisan vendor:publish --tag auth0 -``` + ```shell + php artisan vendor:publish --tag auth0 + ```
### Configuration @@ -57,24 +57,22 @@ php artisan vendor:publish --tag auth0
Using the Auth0 CLI (Recommended) -You will need to download the CLI and authenticate it with your Auth0 account. You can then use it to create the configuration files for your application. - 1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your application's root directory: - > **Note** - > If you are using the Quickstart application, the CLI was bundled for you, and you can skip to the next step. - ```shell curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . ``` -2. Then authenticate with your Auth0 account: + > **Note** + > When using the Quickstart the CLI is bundled for you already. + +2. Authenticate with your Auth0 account: ```shell ./auth0 login ``` -3. Create a new application with Auth0: +3. Register a new application with Auth0: ```shell ./auth0 apps create \ @@ -88,7 +86,7 @@ You will need to download the CLI and authenticate it with your Auth0 account. Y --json > .auth0.app.json ``` -4. Create a new API with Auth0 +4. Register a new API with Auth0 ```shell ./auth0 apis create \ @@ -99,9 +97,7 @@ You will need to download the CLI and authenticate it with your Auth0 account. Y --json > .auth0.api.json ``` -5. The files created by these commands contain sensitive credentials. It is important you do not commit these to version control. - - If you're using Git, you should add them to your `.gitignore` file: +5. The files created by these commands contain sensitive credentials. Add them to your application's `.gitignore`. ```bash echo ".auth0.*.json" >> .gitignore From c365dbd8545f3bb0b53260c9e40f66c5b9f4a536 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 03:36:01 -0500 Subject: [PATCH 360/525] Update README2.md --- README2.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README2.md b/README2.md index 91b6b5d9..8ef6304b 100644 --- a/README2.md +++ b/README2.md @@ -57,15 +57,15 @@ The [Auth0 CLI](https://auth0.com/docs/cli) is recommended for configuring the S
Using the Auth0 CLI (Recommended) -1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your application's root directory: +1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your project directory: + + > **Note** + > If you are using the Quickstart, you can skip to the next step. ```shell curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . ``` - > **Note** - > When using the Quickstart the CLI is bundled for you already. - 2. Authenticate with your Auth0 account: ```shell @@ -97,7 +97,7 @@ The [Auth0 CLI](https://auth0.com/docs/cli) is recommended for configuring the S --json > .auth0.api.json ``` -5. The files created by these commands contain sensitive credentials. Add them to your application's `.gitignore`. +5. The files created by these commands contain sensitive credentials, and should never be committed to version control. Add them to your application's `.gitignore`: ```bash echo ".auth0.*.json" >> .gitignore From adce7ab0c2f29e51bfefa2b1cb3d2cc9882bc112 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 03:39:49 -0500 Subject: [PATCH 361/525] Update README2.md --- README2.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README2.md b/README2.md index 8ef6304b..29c52b1e 100644 --- a/README2.md +++ b/README2.md @@ -21,8 +21,6 @@ Your application must use a [supported Laravel version](https://laravelversions. You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). -The [Auth0 CLI](https://auth0.com/docs/cli) is recommended for configuring the SDK, but not required. - ### Installation
@@ -97,7 +95,7 @@ The [Auth0 CLI](https://auth0.com/docs/cli) is recommended for configuring the S --json > .auth0.api.json ``` -5. The files created by these commands contain sensitive credentials, and should never be committed to version control. Add them to your application's `.gitignore`: +5. Add the newly created files to `.gitignore`, as they contain sensitive credentials: ```bash echo ".auth0.*.json" >> .gitignore @@ -109,6 +107,8 @@ The [Auth0 CLI](https://auth0.com/docs/cli) is recommended for configuring the S
+### Authentication + ## Documentation The documentation is divided into several sections: From 5d1b6e9c7151a9a905e29409c46ea6c9995c3da6 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 03:40:55 -0500 Subject: [PATCH 362/525] Update README2.md --- README2.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README2.md b/README2.md index 29c52b1e..e58210e3 100644 --- a/README2.md +++ b/README2.md @@ -74,25 +74,25 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h ```shell ./auth0 apps create \ - --name "My Laravel Application" \ - --type "regular" \ - --auth-method "post" \ - --callbacks "http://localhost:8000/callback" \ - --logout-urls "http://localhost:8000/" \ - --reveal-secrets \ - --no-input \ - --json > .auth0.app.json + --name "My Laravel Application" \ + --type "regular" \ + --auth-method "post" \ + --callbacks "http://localhost:8000/callback" \ + --logout-urls "http://localhost:8000/" \ + --reveal-secrets \ + --no-input \ + --json > .auth0.app.json ``` 4. Register a new API with Auth0 ```shell ./auth0 apis create \ - --name "My Laravel Application API" \ - --identifier "https://github.com/auth0/laravel-auth0" \ - --offline-access \ - --no-input \ - --json > .auth0.api.json + --name "My Laravel Application API" \ + --identifier "https://github.com/auth0/laravel-auth0" \ + --offline-access \ + --no-input \ + --json > .auth0.api.json ``` 5. Add the newly created files to `.gitignore`, as they contain sensitive credentials: From 6977ea7c4e86a9d1867aad80f605d7053b1fbfb3 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 03:42:36 -0500 Subject: [PATCH 363/525] Update README2.md --- README2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README2.md b/README2.md index e58210e3..8a3566bc 100644 --- a/README2.md +++ b/README2.md @@ -58,7 +58,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h 1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your project directory: > **Note** - > If you are using the Quickstart, you can skip to the next step. + > If you are using the Quickstart, skip to the next step. ```shell curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . From d3821069e353064d2bec0a107f5bdf779e57c4ca Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 03:45:46 -0500 Subject: [PATCH 364/525] Update README2.md --- README2.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README2.md b/README2.md index 8a3566bc..abb3aa2c 100644 --- a/README2.md +++ b/README2.md @@ -21,13 +21,13 @@ Your application must use a [supported Laravel version](https://laravelversions. You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). -### Installation +## Installation
Using a Quickstart -- Run the following command to create a bootstrapped Laravel application pre-configured with the SDK: +- Run the following command to set up a bootstrapped default Laravel 9 application pre-configured with the SDK: ```shell composer create-project auth0-samples/laravel auth0-laravel-app @@ -50,7 +50,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h ```
-### Configuration +## Configuration
Using the Auth0 CLI (Recommended) @@ -107,7 +107,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h
-### Authentication +## Example ## Documentation From 430a86ebe860ce9d6c5bba275a9722f7c4a8c5c2 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 03:46:16 -0500 Subject: [PATCH 365/525] Update README2.md --- README2.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README2.md b/README2.md index abb3aa2c..0b853b71 100644 --- a/README2.md +++ b/README2.md @@ -100,6 +100,9 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h ```bash echo ".auth0.*.json" >> .gitignore ``` + +--- +
From 6e4a9630956e19c74bb5116f575d6fe954ec7997 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 22:50:26 -0500 Subject: [PATCH 366/525] Update README2.md --- README2.md | 209 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 196 insertions(+), 13 deletions(-) diff --git a/README2.md b/README2.md index 0b853b71..ffccc98b 100644 --- a/README2.md +++ b/README2.md @@ -9,7 +9,7 @@ ## Requirements -Your application must use a [supported Laravel version](https://laravelversions.com/en), and your environment must be running a [supported PHP version](https://www.php.net/supported-versions.php). We do not support versions of Laravel or PHP that are no longer supported by their maintainers. +Your application must use a [supported Laravel version](https://laravelversions.com/en), and your environment must run a [supported PHP version](https://www.php.net/supported-versions.php). We do not support versions of Laravel or PHP that are no longer supported by their maintainers. | SDK | Laravel | PHP | Supported Until | | ---- | ------- | ---- | --------------- | @@ -27,11 +27,14 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h Using a Quickstart -- Run the following command to set up a bootstrapped default Laravel 9 application pre-configured with the SDK: +- Run the following command to set up a bootstrapped default Laravel 9 application that's pre-configured with the SDK: ```shell composer create-project auth0-samples/laravel auth0-laravel-app ``` + +--- +
@@ -53,7 +56,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h ## Configuration
-Using the Auth0 CLI (Recommended) +Using JSON (Recommended) 1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your project directory: @@ -95,7 +98,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h --json > .auth0.api.json ``` -5. Add the newly created files to `.gitignore`, as they contain sensitive credentials: +5. Add the newly created JSON files to `.gitignore`, as they contain sensitive credentials: ```bash echo ".auth0.*.json" >> .gitignore @@ -108,9 +111,197 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h
Using Environment Variables +1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your project directory: + + > **Note** + > If you are using the Quickstart, skip to the next step. + + ```shell + curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . + ``` + +2. Authenticate with your Auth0 account: + + ```shell + ./auth0 login + ``` + +3. Register a new application with Auth0: + + ```shell + ./auth0 apps create \ + --name "My Laravel Application" \ + --type "regular" \ + --auth-method "post" \ + --callbacks "http://localhost:8000/callback" \ + --logout-urls "http://localhost:8000/" \ + --reveal-secrets \ + --no-input + ``` + + Make a note of the `client_id` and `client_secret` values in the output. + +4. Register a new API with Auth0 + + ```shell + ./auth0 apis create \ + --name "My Laravel Application API" \ + --identifier "https://github.com/auth0/laravel-auth0" \ + --offline-access \ + --no-input + ``` + +5. Open the `.env` file in your project directory. Add the following lines, replacing the values with the ones you noted in the previous steps: + + ```ini + # The Auth0 domain for your tenant (e.g. tenant.region.auth0.com): + AUTH0_DOMAIN=... + + # The application `client_id` you noted above: + AUTH0_CLIENT_ID=... + + # The application `client_secret` you noted above: + AUTH0_CLIENT_SECRET=... + + # The API `identifier` you used above: + AUTH0_AUDIENCE=... + ``` + +
+ +## Examples + +
+Authentication + +The SDK automatically registers all the necessary authentication services within the `web` middleware group for your application. Once you have [configured the SDK](#configuration) your users will be able to authenticate with your application using Auth0. + +The SDK automatically registers the following routes to facilitate authentication: + +| Route | Purpose | +| ----------- | ---------------------------------- | +| `/login` | Initiates the authentication flow. | +| `/logout` | Logs the user out. | +| `/callback` | Handles the callback from Auth0. | + +> **Note** +> See [the configuration guide](./docs/Configuration.md) for information on customizing this behavior. + +
+ +
+Access Control + +The SDK automatically registers its authentication and authorization guards within the `web` and `api` middleware groups for your Laravel application. + +To require a user to be authenticated to access a route, use Laravel's `auth` middleware: + +```php +Route::get('/private', function () { + return response('Welcome! You are logged in.'); +})->middleware('auth'); +``` + +You can also require that the user have specific permissions to access a route, using Laravel's `can` middleware: + +```php +Route::get('/scope', function () { + return response('You have the `read:messages` permissions, and can therefore access this resource.'); +})->middleware('auth')->can('read:messages'); +``` + +> **Note** +> Permissions require that [RBAC](https://auth0.com/docs/manage-users/access-control/rbac) be enabled within [your API settings](https://manage.auth0.com/#/apis). + +
+ +
+Users and Tokens + +Laravel's `Auth` Facade (or the `auth()` global helper) can be used to retrieve information about the authenticated user, or the access token used to authorize the request. + +For example, for routes using the `web` middleware group in `routes/web.php`: + +```php +Route::get('/', function () { + if (! auth()->check()) { + return response('You are not logged in.'); + } + + $user = auth()->user(); + $name = $user->name ?? 'User'; + $email = $user->email ?? ''; + + return response("Hello {$name}! Your email address is {$email}."); +}); +``` + +Alternatively, for routes using the `api` middleware group in `routes/api.php`: + +```php +Route::get('/', function () { + if (! auth()->check()) { + return response()->json([ + 'message' => 'You did not provide a token.', + ]); + } + + return response()->json([ + 'message' => 'Your token is valid; you are authorized.', + 'id' => auth()->id(), + 'token' => auth()?->user()?->getAttributes(), + ]); +}); +```
-## Example +
+Management API + +> **Note** +> Before your application can make calls to the Management API, you must either generate and provide [a management token](./docs/Configuration.md#management-token) or [enable your application to communicate with the Management API](./docs/Management.md#management-api-permissions). + +You can issue [Auth0 Management API](https://auth0.com/docs/api/management/v2) calls through the SDK's `management()` method. + +For example, you can update a user's metadata by calling the `management()->users()->update()` method: + +```php +use Auth0\Laravel\Facade\Auth0; + +Route::get('/colors', function () { + $colors = ['red', 'blue', 'green', 'black', 'white', 'yellow', 'purple', 'orange', 'pink', 'brown']; + + // Update the authenticated user with a randomly assigned favorite color. + Auth0::management()->users()->update( + id: auth()->id(), + body: [ + 'user_metadata' => [ + 'color' => $colors[random_int(0, count($colors) - 1)] + ] + ] + ); + + // Retrieve the user's updated profile. + $profile = Auth0::management()->users()->get(auth()->id()); + + // For interoperability, the SDK returns all API responses as + // PSR-7 Responses that contain the JSON response. + + // You can use the `json()` helper to unpack the PSR-7, and + // convert the API's JSON response to a native PHP array. + $profile = Auth0::json($profile); + + // Read the user's profile. + $color = $profile['user_metadata']['color'] ?? 'unknown'; + $name = auth()->user()->name; + + return response("Hello {$name}! Your favorite color is {$color}."); +})->middleware('auth'); +``` + +All the SDK's Management API methods are [documented here](./docs/Management.md). + +
## Documentation @@ -130,14 +321,6 @@ The documentation is divided into several sections: You can improve it by sending pull requests to [this repository](https://github.com/auth0/laravel-auth0). -## Examples - -We have several examples on the website. Here is the first one to get you started: - -```php - -``` - ## Community The main purpose of this repository is to continue evolving React core, making it faster and easier to use. Development of React happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving React. From 415c1a0e94217821d776a3c47b667a86ea1ac39e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 22:53:28 -0500 Subject: [PATCH 367/525] Update README2.md --- README2.md | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/README2.md b/README2.md index ffccc98b..7c419eef 100644 --- a/README2.md +++ b/README2.md @@ -27,7 +27,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h Using a Quickstart -- Run the following command to set up a bootstrapped default Laravel 9 application that's pre-configured with the SDK: +- Run the following command to set up a bootstrapped default Laravel 9 application that's pre-configured with the SDK: ```shell composer create-project auth0-samples/laravel auth0-laravel-app @@ -40,18 +40,19 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h
Using Composer -1. Run the following command in your project directory to install the SDK: +1. Run the following command in your project directory to install the SDK: ```shell composer require auth0/login:^7.8 --update-with-all-dependencies ``` -2. Generate an SDK configuration file for your application: +2. Generate an SDK configuration file for your application: - ```shell - php artisan vendor:publish --tag auth0 - ``` -
+ ```shell + php artisan vendor:publish --tag auth0 + ``` + +
## Configuration @@ -60,7 +61,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h 1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your project directory: - > **Note** + > **Note** > If you are using the Quickstart, skip to the next step. ```shell @@ -113,7 +114,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h 1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your project directory: - > **Note** + > **Note** > If you are using the Quickstart, skip to the next step. ```shell @@ -184,7 +185,7 @@ The SDK automatically registers the following routes to facilitate authenticatio | `/logout` | Logs the user out. | | `/callback` | Handles the callback from Auth0. | -> **Note** +> **Note** . > See [the configuration guide](./docs/Configuration.md) for information on customizing this behavior.
@@ -210,7 +211,7 @@ Route::get('/scope', function () { })->middleware('auth')->can('read:messages'); ``` -> **Note** +> **Note** > Permissions require that [RBAC](https://auth0.com/docs/manage-users/access-control/rbac) be enabled within [your API settings](https://manage.auth0.com/#/apis).
@@ -253,12 +254,13 @@ Route::get('/', function () { ]); }); ``` +
Management API -> **Note** +> **Note** > Before your application can make calls to the Management API, you must either generate and provide [a management token](./docs/Configuration.md#management-token) or [enable your application to communicate with the Management API](./docs/Management.md#management-api-permissions). You can issue [Auth0 Management API](https://auth0.com/docs/api/management/v2) calls through the SDK's `management()` method. From b3cc598e297d7b43aff4f9f158b43c7c887ca07f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 22:54:36 -0500 Subject: [PATCH 368/525] Update README2.md --- README2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README2.md b/README2.md index 7c419eef..837c5dbd 100644 --- a/README2.md +++ b/README2.md @@ -185,7 +185,7 @@ The SDK automatically registers the following routes to facilitate authenticatio | `/logout` | Logs the user out. | | `/callback` | Handles the callback from Auth0. | -> **Note** . +> **Note** > See [the configuration guide](./docs/Configuration.md) for information on customizing this behavior.
From e798fee6b3ad7820aa60db8fc228ddbdcc339f02 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:20:30 -0500 Subject: [PATCH 369/525] Update README2.md --- README2.md | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/README2.md b/README2.md index 837c5dbd..d65f2386 100644 --- a/README2.md +++ b/README2.md @@ -48,11 +48,11 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h 2. Generate an SDK configuration file for your application: - ```shell - php artisan vendor:publish --tag auth0 - ``` + ```shell + php artisan vendor:publish --tag auth0 + ``` -
+
## Configuration @@ -188,6 +188,8 @@ The SDK automatically registers the following routes to facilitate authenticatio > **Note** > See [the configuration guide](./docs/Configuration.md) for information on customizing this behavior. +--- +
@@ -214,6 +216,8 @@ Route::get('/scope', function () { > **Note** > Permissions require that [RBAC](https://auth0.com/docs/manage-users/access-control/rbac) be enabled within [your API settings](https://manage.auth0.com/#/apis). +--- +
@@ -255,16 +259,18 @@ Route::get('/', function () { }); ``` +--- +
Management API -> **Note** -> Before your application can make calls to the Management API, you must either generate and provide [a management token](./docs/Configuration.md#management-token) or [enable your application to communicate with the Management API](./docs/Management.md#management-api-permissions). - You can issue [Auth0 Management API](https://auth0.com/docs/api/management/v2) calls through the SDK's `management()` method. +> **Note** +> Before your application can make calls to the Management API, you must [enable your application to communicate with the Management API](./docs/Management.md#management-api-permissions) or configure the SDK with [a management token](./docs/Configuration.md#management-token). + For example, you can update a user's metadata by calling the `management()->users()->update()` method: ```php @@ -307,32 +313,39 @@ All the SDK's Management API methods are [documented here](./docs/Management.md) ## Documentation -The documentation is divided into several sections: - - [Getting Started](./README.md#getting-started) — Installing and configuring the SDK. -- [Examples](./EXAMPLES.md) — Answers and solutions for common questions and scenarios. +- [Examples](./EXAMPLES.md) — Solutions for common scenarios. - Reference: - [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. - [Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. - [Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2). - [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent). - [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. + - [Octane](./docs/Octane.md) — We do not support using the SDK with [Octane](https://laravel.com/docs/octane) at this time. - [Auth0 Documentation](https://www.auth0.com/docs) - [Auth0 Management API Explorer](https://auth0.com/docs/api/management/v2) - [Auth0 Authentication API Explorer](https://auth0.com/docs/api/authentication) -You can improve it by sending pull requests to [this repository](https://github.com/auth0/laravel-auth0). +Contributions to improve our documentation [are welcomed](https://github.com/auth0/laravel-auth0/pull). ## Community -The main purpose of this repository is to continue evolving React core, making it faster and easier to use. Development of React happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving React. +The [Auth0 Community](https://community.auth0.com) is where you can ask questions, get support, and share your projects. ## Contributing +We appreciate feedback and contributions to this library. Before you get started, please review Auth0's [General Contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md). Read [our contributing guide](./CONTRIBUTING.md) to learn about how to propose bug fixes and improvements, and how to build and test your changes to the library. + +To provide feedback or report a bug, [please raise an issue](https://github.com/auth0/laravel-auth0/issues). + ## Code of Conduct +Participants are expected to adhere to our [code of conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) when interacting with this project. + ## Security +If you believe you have found a security vulnerability, we encourage you to responsibly disclose this and not open a public issue. We will investigate all reports. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. + ## License This library is open-sourced software licensed under the [MIT license](./LICENSE.md). From 58368aa855231eebd2f8360efdc4c27c633a116d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:20:33 -0500 Subject: [PATCH 370/525] Create Octane.md --- docs/Octane.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 docs/Octane.md diff --git a/docs/Octane.md b/docs/Octane.md new file mode 100644 index 00000000..2e868031 --- /dev/null +++ b/docs/Octane.md @@ -0,0 +1,7 @@ +# Octane Support + +Octane compatibility with the SDK is currently considered experimental and is not supported. + +Although we are working toward ensuring the SDK has full compatibility in the future, we do not recommend using this with our SDK in production until we have full confidence and announced support. There is an opportunity for problems we have not fully identified or addressed yet. + +Feedback and bug-fix contributions are greatly appreciated as we work toward full support. From 8fa0a7bf821477a74401a6b868a650b091d8d7d9 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:20:57 -0500 Subject: [PATCH 371/525] Update Management.md --- docs/Management.md | 48 +++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/Management.md b/docs/Management.md index 5dc662b7..31584cd4 100644 --- a/docs/Management.md +++ b/docs/Management.md @@ -18,30 +18,30 @@ Auth0::management(); ## Available endpoints -- [Actions](#actions) -- [Attack Protection](#attack-protection) -- [Blacklists](#blacklists) -- [ClientGrants](#client-grants) -- [Clients](#clients) -- [Connections](#connections) -- [Device Credentials](#device-credentials) -- [Emails](#emails) -- [Email Templates](#email-templates) -- [Grants](#grants) -- [Guardian](#guardian) -- [Jobs](#jobs) -- [Logs](#logs) -- [Log Streams](#log-streams) -- [Organizations](#organizations) -- [Resource Servers](#resource-servers) -- [Roles](#roles) -- [Rules](#rules) -- [Stats](#stats) -- [Tenants](#tenants) -- [Tickets](#tickets) -- [User Blocks](#user-blocks) -- [Users](#users) -- [Users by Email](#users-by-email) +- [Actions](#actions) +- [Attack Protection](#attack-protection) +- [Blacklists](#blacklists) +- [ClientGrants](#client-grants) +- [Clients](#clients) +- [Connections](#connections) +- [Device Credentials](#device-credentials) +- [Emails](#emails) +- [Email Templates](#email-templates) +- [Grants](#grants) +- [Guardian](#guardian) +- [Jobs](#jobs) +- [Logs](#logs) +- [Log Streams](#log-streams) +- [Organizations](#organizations) +- [Resource Servers](#resource-servers) +- [Roles](#roles) +- [Rules](#rules) +- [Stats](#stats) +- [Tenants](#tenants) +- [Tickets](#tickets) +- [User Blocks](#user-blocks) +- [Users](#users) +- [Users by Email](#users-by-email) ### Actions From 351f6f388afa193b7ff750f587cb5ad963ac308e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:22:46 -0500 Subject: [PATCH 372/525] Update README2.md --- README2.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README2.md b/README2.md index d65f2386..c3f892a6 100644 --- a/README2.md +++ b/README2.md @@ -265,6 +265,7 @@ Route::get('/', function () {
Management API +  You can issue [Auth0 Management API](https://auth0.com/docs/api/management/v2) calls through the SDK's `management()` method. From 758b6aaf779adc88c808425ad03cca0d74c9ffdf Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:27:51 -0500 Subject: [PATCH 373/525] Update README2.md --- README2.md | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/README2.md b/README2.md index c3f892a6..97730f07 100644 --- a/README2.md +++ b/README2.md @@ -25,7 +25,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h
-Using a Quickstart +Using Quickstart (Fastest) - Run the following command to set up a bootstrapped default Laravel 9 application that's pre-configured with the SDK: @@ -38,7 +38,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h
-Using Composer +Using Composer 1. Run the following command in your project directory to install the SDK: @@ -57,7 +57,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h ## Configuration
-Using JSON (Recommended) +Using JSON (Fastest) 1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your project directory: @@ -110,7 +110,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h
-Using Environment Variables +Using Environment Variables 1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your project directory: @@ -170,10 +170,16 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h
+## Quickstart + +- [Session-based Authentication](https://auth0.com/docs/quickstart/webapp/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) +- [Token-based Authorization](https://auth0.com/docs/quickstart/backend/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) + ## Examples
-Authentication +Authentication +  The SDK automatically registers all the necessary authentication services within the `web` middleware group for your application. Once you have [configured the SDK](#configuration) your users will be able to authenticate with your application using Auth0. @@ -193,7 +199,8 @@ The SDK automatically registers the following routes to facilitate authenticatio
-Access Control +Access Control +  The SDK automatically registers its authentication and authorization guards within the `web` and `api` middleware groups for your Laravel application. @@ -221,7 +228,8 @@ Route::get('/scope', function () {
-Users and Tokens +Users and Tokens +  Laravel's `Auth` Facade (or the `auth()` global helper) can be used to retrieve information about the authenticated user, or the access token used to authorize the request. @@ -264,7 +272,7 @@ Route::get('/', function () {
-Management API +Management API   You can issue [Auth0 Management API](https://auth0.com/docs/api/management/v2) calls through the SDK's `management()` method. @@ -314,7 +322,6 @@ All the SDK's Management API methods are [documented here](./docs/Management.md) ## Documentation -- [Getting Started](./README.md#getting-started) — Installing and configuring the SDK. - [Examples](./EXAMPLES.md) — Solutions for common scenarios. - Reference: - [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. From 2a0e5ac870b725d33b7c61a8023a87b55671d771 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:38:13 -0500 Subject: [PATCH 374/525] Delete EXAMPLES.md --- EXAMPLES.md | 85 ----------------------------------------------------- 1 file changed, 85 deletions(-) delete mode 100644 EXAMPLES.md diff --git a/EXAMPLES.md b/EXAMPLES.md deleted file mode 100644 index a6661d6d..00000000 --- a/EXAMPLES.md +++ /dev/null @@ -1,85 +0,0 @@ -# Examples Cookbook - -This document provides example solutions for common integration questions. - -- [Users](#users) - - [Custom Models and Repositories](#custom-user-models-and-repositories) -- [Management API](#management-api) -- [Middleware](#middleware) - - [Scope Filtering](#scope-filtering) -- [Events](#events) -- [Testing](#testing) - - [Impersonation](#impersonation) - -> **Note** -> The [README](./README.md) also covers many integration questions. Please review that document if your question is not answered here. - -## Users - -### Custom User Models and Repositories - -[docs/User Models and Repositories](./docs/User%20Models%20and%20Repositories.md) covers extending the SDK to support database storage, [Eloquent](https://laravel.com/docs/10.x/eloquent), and other scenarios. - -## Management API - -[docs/Management API](./docs/Management%20API.md) covers making API calls to [Auth0 Management API endpoints](https://auth0.com/docs/api/management/v2). - -## Middleware - -### Scope Filtering - -Let's assume you have a route like the following, that is protected by the scope `read:messages`: - -```php -Route::get('/api/private-scoped', function () { - return response()->json([ - 'message' => 'Hello from a private endpoint!', - 'authorized' => Auth::check(), - 'user' => Auth::check() ? json_decode(json_encode((array) Auth::user(), JSON_THROW_ON_ERROR), true) : null, - ], 200, [], JSON_PRETTY_PRINT); -})->can('read:messages'); -``` - -## Events - -[docs/Events](./docs/Events.md) covers hooking into [events](https://laravel.com/docs/10.x/events) raised by the SDK to customize behavior. - -## Testing - -### Impersonation - -When writing unit tests for your application that include HTTP requests to routes protected by the SDK's middleware, you can use the "Imposter" trait to simplify fulfilling the request by mocking a user session. The following example is writen in [PEST syntax](https://pestphp.com), but the trait can be used in an identical manner with test-case classes in PHPUnit: - -> **Note** -> If you're using custom user repositories or models, you may need to adjust how `$imposter` is shaping the `user` property to match your integration. - -```php -json('Hello World'); - }); - - $imposter = Credential::create( - user: new User(['sub' => uniqid()]), - idToken: uniqid(), - accessToken: uniqid(), - accessTokenScope: ['openid', 'profile', 'email', 'read:messages'], - accessTokenExpiration: time() + 3600 - ); - - $this->impersonate($imposter) - ->getJson('./example') - ->assertStatus(Response::HTTP_OK); -}); -``` From 4a57085e66497f5571d31182d806a307f7538769 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:38:17 -0500 Subject: [PATCH 375/525] Update README2.md --- README2.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/README2.md b/README2.md index 97730f07..316dc2af 100644 --- a/README2.md +++ b/README2.md @@ -27,7 +27,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h Using Quickstart (Fastest) -- Run the following command to set up a bootstrapped default Laravel 9 application that's pre-configured with the SDK: +- Run the following command to create a new Laravel 9 project pre-configured with the SDK: ```shell composer create-project auth0-samples/laravel auth0-laravel-app @@ -168,9 +168,11 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h AUTH0_AUDIENCE=... ``` + Additional variables are available for configuration. More on those in the [configuration guide](./docs/Configuration.md). +
-## Quickstart +## Quickstarts - [Session-based Authentication](https://auth0.com/docs/quickstart/webapp/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) - [Token-based Authorization](https://auth0.com/docs/quickstart/backend/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) @@ -322,15 +324,16 @@ All the SDK's Management API methods are [documented here](./docs/Management.md) ## Documentation -- [Examples](./EXAMPLES.md) — Solutions for common scenarios. -- Reference: - - [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. - - [Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. - - [Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2). - - [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent). - - [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. - - [Octane](./docs/Octane.md) — We do not support using the SDK with [Octane](https://laravel.com/docs/octane) at this time. -- [Auth0 Documentation](https://www.auth0.com/docs) +- [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. +- [Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. +- [Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2). +- [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent). +- [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. +- [Octane](./docs/Octane.md) — We do not support using the SDK with [Octane](https://laravel.com/docs/octane) at this time. + +You may also find the following resources helpful: + +- [Auth0 Documentation Hub](https://www.auth0.com/docs) - [Auth0 Management API Explorer](https://auth0.com/docs/api/management/v2) - [Auth0 Authentication API Explorer](https://auth0.com/docs/api/authentication) From a48d2ee3c2037799c09b4c5e9e21b1a33e7f8caf Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:39:40 -0500 Subject: [PATCH 376/525] Update README2.md --- README2.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README2.md b/README2.md index 316dc2af..4fd1eda5 100644 --- a/README2.md +++ b/README2.md @@ -88,7 +88,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h --json > .auth0.app.json ``` -4. Register a new API with Auth0 +4. Register a new API with Auth0: ```shell ./auth0 apis create \ @@ -99,7 +99,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h --json > .auth0.api.json ``` -5. Add the newly created JSON files to `.gitignore`, as they contain sensitive credentials: +5. Add the new files to `.gitignore`: ```bash echo ".auth0.*.json" >> .gitignore @@ -142,7 +142,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h Make a note of the `client_id` and `client_secret` values in the output. -4. Register a new API with Auth0 +4. Register a new API with Auth0: ```shell ./auth0 apis create \ @@ -168,7 +168,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h AUTH0_AUDIENCE=... ``` - Additional variables are available for configuration. More on those in the [configuration guide](./docs/Configuration.md). + Additional variables are available. More on those in the [configuration guide](./docs/Configuration.md).
From deea0ec02139d572b3239749b58b1f5da7fbbbd1 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:42:37 -0500 Subject: [PATCH 377/525] Update Events.md --- docs/Events.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/Events.md b/docs/Events.md index 04618c7a..408f6cde 100644 --- a/docs/Events.md +++ b/docs/Events.md @@ -49,13 +49,13 @@ During login with `Auth0\Laravel\Controllers\LoginController` the following even During callback with `Auth0\Laravel\Controllers\CallbackController` the following events may be raised: -| Event | Description | -| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `Illuminate\Auth\Events\Attempting` | Raised when a user is returned to the application after authenticating with Auth0. This is raised before verification of the authentication process begins. | -| `Illuminate\Auth\Events\Failed` | Raised when authentication with Auth0 failed. The reason is provided with the event as an array. | -| `Auth0\Laravel\Events\AuthenticationFailed` | Raised when authentication with Auth0 failed. This provides an opportunity to intercept the exception thrown by the middleware, by using the event's `setThrowException()` method to `false`. You can also customize the type of exception thrown using `setException()`. | -| `Illuminate\Auth\Events\Illuminate\Auth\Events\Validated` | Raised when authentication was successful, but immediately before the user's session is established. | -| `Auth0\Laravel\Events\AuthenticationSucceeded` | Raised when authentication was successful. The model of the authenticated user is provided with the event. | +| Event | Description | +| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Illuminate\Auth\Events\Attempting` | Raised when a user is returned to the application after authenticating with Auth0. This is raised before verification of the authentication process begins. | +| `Illuminate\Auth\Events\Failed` | Raised when authentication with Auth0 failed. The reason is provided with the event as an array. | +| `Auth0\Laravel\Events\AuthenticationFailed` | Raised when authentication with Auth0 failed. This provides an opportunity to intercept the exception thrown by the middleware, by using the event's `setThrowException()` method to `false`. You can also customize the type of exception thrown using `setException()`. | +| `Illuminate\Auth\Events\Validated` | Raised when authentication was successful, but immediately before the user's session is established. | +| `Auth0\Laravel\Events\AuthenticationSucceeded` | Raised when authentication was successful. The model of the authenticated user is provided with the event. | ## Logout Controller Events From 77b5ef68868e560f9afa8a695ee06a3f9fa02399 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:42:40 -0500 Subject: [PATCH 378/525] Update Installation.md --- docs/Installation.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/Installation.md b/docs/Installation.md index 2e9b592b..59563284 100644 --- a/docs/Installation.md +++ b/docs/Installation.md @@ -1,6 +1,7 @@ # Installation -This document is an addendum to the [README](../README.md) file and covers advanced installation techniques. Please review the installation guidance there before continuing. +> **Note:** +> This is an addendum to the [README](../README.md) file. Please review that guidance there first. ## Alternative Configuration Methods From c7fc048c7ef6f40aa2634a89fbad84eb1e807fab Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:43:15 -0500 Subject: [PATCH 379/525] Delete README2.md --- README2.md | 374 ----------------------------------------------------- 1 file changed, 374 deletions(-) delete mode 100644 README2.md diff --git a/README2.md b/README2.md deleted file mode 100644 index 4fd1eda5..00000000 --- a/README2.md +++ /dev/null @@ -1,374 +0,0 @@ -![laravel-auth0](https://cdn.auth0.com/website/sdks/banners/laravel-auth0-banner.png) - -

-Build Status -Code Coverage -Total Downloads -License -

- -## Requirements - -Your application must use a [supported Laravel version](https://laravelversions.com/en), and your environment must run a [supported PHP version](https://www.php.net/supported-versions.php). We do not support versions of Laravel or PHP that are no longer supported by their maintainers. - -| SDK | Laravel | PHP | Supported Until | -| ---- | ------- | ---- | --------------- | -| 7.5+ | 10 | 8.2+ | Feb 2025 | -| | | 8.1+ | Nov 2024 | -| 7.0+ | 9 | 8.2+ | Feb 2024 | -| | | 8.1+ | Feb 2024 | -| | | 8.0+ | Nov 2023 | - -You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). - -## Installation - -
- -Using Quickstart (Fastest) - -- Run the following command to create a new Laravel 9 project pre-configured with the SDK: - - ```shell - composer create-project auth0-samples/laravel auth0-laravel-app - ``` - ---- - -
- -
-Using Composer - -1. Run the following command in your project directory to install the SDK: - - ```shell - composer require auth0/login:^7.8 --update-with-all-dependencies - ``` - -2. Generate an SDK configuration file for your application: - - ```shell - php artisan vendor:publish --tag auth0 - ``` - -
- -## Configuration - -
-Using JSON (Fastest) - -1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your project directory: - - > **Note** - > If you are using the Quickstart, skip to the next step. - - ```shell - curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . - ``` - -2. Authenticate with your Auth0 account: - - ```shell - ./auth0 login - ``` - -3. Register a new application with Auth0: - - ```shell - ./auth0 apps create \ - --name "My Laravel Application" \ - --type "regular" \ - --auth-method "post" \ - --callbacks "http://localhost:8000/callback" \ - --logout-urls "http://localhost:8000/" \ - --reveal-secrets \ - --no-input \ - --json > .auth0.app.json - ``` - -4. Register a new API with Auth0: - - ```shell - ./auth0 apis create \ - --name "My Laravel Application API" \ - --identifier "https://github.com/auth0/laravel-auth0" \ - --offline-access \ - --no-input \ - --json > .auth0.api.json - ``` - -5. Add the new files to `.gitignore`: - - ```bash - echo ".auth0.*.json" >> .gitignore - ``` - ---- - -
- -
-Using Environment Variables - -1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your project directory: - - > **Note** - > If you are using the Quickstart, skip to the next step. - - ```shell - curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . - ``` - -2. Authenticate with your Auth0 account: - - ```shell - ./auth0 login - ``` - -3. Register a new application with Auth0: - - ```shell - ./auth0 apps create \ - --name "My Laravel Application" \ - --type "regular" \ - --auth-method "post" \ - --callbacks "http://localhost:8000/callback" \ - --logout-urls "http://localhost:8000/" \ - --reveal-secrets \ - --no-input - ``` - - Make a note of the `client_id` and `client_secret` values in the output. - -4. Register a new API with Auth0: - - ```shell - ./auth0 apis create \ - --name "My Laravel Application API" \ - --identifier "https://github.com/auth0/laravel-auth0" \ - --offline-access \ - --no-input - ``` - -5. Open the `.env` file in your project directory. Add the following lines, replacing the values with the ones you noted in the previous steps: - - ```ini - # The Auth0 domain for your tenant (e.g. tenant.region.auth0.com): - AUTH0_DOMAIN=... - - # The application `client_id` you noted above: - AUTH0_CLIENT_ID=... - - # The application `client_secret` you noted above: - AUTH0_CLIENT_SECRET=... - - # The API `identifier` you used above: - AUTH0_AUDIENCE=... - ``` - - Additional variables are available. More on those in the [configuration guide](./docs/Configuration.md). - -
- -## Quickstarts - -- [Session-based Authentication](https://auth0.com/docs/quickstart/webapp/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) -- [Token-based Authorization](https://auth0.com/docs/quickstart/backend/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) - -## Examples - -
-Authentication -  - -The SDK automatically registers all the necessary authentication services within the `web` middleware group for your application. Once you have [configured the SDK](#configuration) your users will be able to authenticate with your application using Auth0. - -The SDK automatically registers the following routes to facilitate authentication: - -| Route | Purpose | -| ----------- | ---------------------------------- | -| `/login` | Initiates the authentication flow. | -| `/logout` | Logs the user out. | -| `/callback` | Handles the callback from Auth0. | - -> **Note** -> See [the configuration guide](./docs/Configuration.md) for information on customizing this behavior. - ---- - -
- -
-Access Control -  - -The SDK automatically registers its authentication and authorization guards within the `web` and `api` middleware groups for your Laravel application. - -To require a user to be authenticated to access a route, use Laravel's `auth` middleware: - -```php -Route::get('/private', function () { - return response('Welcome! You are logged in.'); -})->middleware('auth'); -``` - -You can also require that the user have specific permissions to access a route, using Laravel's `can` middleware: - -```php -Route::get('/scope', function () { - return response('You have the `read:messages` permissions, and can therefore access this resource.'); -})->middleware('auth')->can('read:messages'); -``` - -> **Note** -> Permissions require that [RBAC](https://auth0.com/docs/manage-users/access-control/rbac) be enabled within [your API settings](https://manage.auth0.com/#/apis). - ---- - -
- -
-Users and Tokens -  - -Laravel's `Auth` Facade (or the `auth()` global helper) can be used to retrieve information about the authenticated user, or the access token used to authorize the request. - -For example, for routes using the `web` middleware group in `routes/web.php`: - -```php -Route::get('/', function () { - if (! auth()->check()) { - return response('You are not logged in.'); - } - - $user = auth()->user(); - $name = $user->name ?? 'User'; - $email = $user->email ?? ''; - - return response("Hello {$name}! Your email address is {$email}."); -}); -``` - -Alternatively, for routes using the `api` middleware group in `routes/api.php`: - -```php -Route::get('/', function () { - if (! auth()->check()) { - return response()->json([ - 'message' => 'You did not provide a token.', - ]); - } - - return response()->json([ - 'message' => 'Your token is valid; you are authorized.', - 'id' => auth()->id(), - 'token' => auth()?->user()?->getAttributes(), - ]); -}); -``` - ---- - -
- -
-Management API -  - -You can issue [Auth0 Management API](https://auth0.com/docs/api/management/v2) calls through the SDK's `management()` method. - -> **Note** -> Before your application can make calls to the Management API, you must [enable your application to communicate with the Management API](./docs/Management.md#management-api-permissions) or configure the SDK with [a management token](./docs/Configuration.md#management-token). - -For example, you can update a user's metadata by calling the `management()->users()->update()` method: - -```php -use Auth0\Laravel\Facade\Auth0; - -Route::get('/colors', function () { - $colors = ['red', 'blue', 'green', 'black', 'white', 'yellow', 'purple', 'orange', 'pink', 'brown']; - - // Update the authenticated user with a randomly assigned favorite color. - Auth0::management()->users()->update( - id: auth()->id(), - body: [ - 'user_metadata' => [ - 'color' => $colors[random_int(0, count($colors) - 1)] - ] - ] - ); - - // Retrieve the user's updated profile. - $profile = Auth0::management()->users()->get(auth()->id()); - - // For interoperability, the SDK returns all API responses as - // PSR-7 Responses that contain the JSON response. - - // You can use the `json()` helper to unpack the PSR-7, and - // convert the API's JSON response to a native PHP array. - $profile = Auth0::json($profile); - - // Read the user's profile. - $color = $profile['user_metadata']['color'] ?? 'unknown'; - $name = auth()->user()->name; - - return response("Hello {$name}! Your favorite color is {$color}."); -})->middleware('auth'); -``` - -All the SDK's Management API methods are [documented here](./docs/Management.md). - -
- -## Documentation - -- [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. -- [Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. -- [Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2). -- [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent). -- [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. -- [Octane](./docs/Octane.md) — We do not support using the SDK with [Octane](https://laravel.com/docs/octane) at this time. - -You may also find the following resources helpful: - -- [Auth0 Documentation Hub](https://www.auth0.com/docs) -- [Auth0 Management API Explorer](https://auth0.com/docs/api/management/v2) -- [Auth0 Authentication API Explorer](https://auth0.com/docs/api/authentication) - -Contributions to improve our documentation [are welcomed](https://github.com/auth0/laravel-auth0/pull). - -## Community - -The [Auth0 Community](https://community.auth0.com) is where you can ask questions, get support, and share your projects. - -## Contributing - -We appreciate feedback and contributions to this library. Before you get started, please review Auth0's [General Contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md). Read [our contributing guide](./CONTRIBUTING.md) to learn about how to propose bug fixes and improvements, and how to build and test your changes to the library. - -To provide feedback or report a bug, [please raise an issue](https://github.com/auth0/laravel-auth0/issues). - -## Code of Conduct - -Participants are expected to adhere to our [code of conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) when interacting with this project. - -## Security - -If you believe you have found a security vulnerability, we encourage you to responsibly disclose this and not open a public issue. We will investigate all reports. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. - -## License - -This library is open-sourced software licensed under the [MIT license](./LICENSE.md). - ---- - -

- - - - Auth0 Logo - -

- -

Auth0 is an easy-to-implement, adaptable authentication and authorization platform.
To learn more, check out "Why Auth0?"

From 0e7dd669e543ee9f437f4c7dadf97e76f995700e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:43:16 -0500 Subject: [PATCH 380/525] Update README.md --- README.md | 373 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 220 insertions(+), 153 deletions(-) diff --git a/README.md b/README.md index 622ca724..4fd1eda5 100644 --- a/README.md +++ b/README.md @@ -1,121 +1,191 @@ ![laravel-auth0](https://cdn.auth0.com/website/sdks/banners/laravel-auth0-banner.png) -Laravel SDK for [Auth0](https://auth0.com) Authentication and Management APIs. +

+Build Status +Code Coverage +Total Downloads +License +

-[![Package](https://img.shields.io/packagist/dt/auth0/login)](https://packagist.org/packages/auth0/login) -![Build Status](https://img.shields.io/github/checks-status/auth0/laravel-auth0/main) -[![Coverage](https://img.shields.io/codecov/c/github/auth0/laravel-auth0/main)](https://codecov.io/gh/auth0/laravel-auth0) -[![License](https://img.shields.io/packagist/l/auth0/login)](https://doge.mit-license.org/) +## Requirements -:books: [Documentation](#documentation) — :rocket: [Getting Started](#getting-started) — :speech_balloon: [Feedback](#feedback) +Your application must use a [supported Laravel version](https://laravelversions.com/en), and your environment must run a [supported PHP version](https://www.php.net/supported-versions.php). We do not support versions of Laravel or PHP that are no longer supported by their maintainers. -## Documentation +| SDK | Laravel | PHP | Supported Until | +| ---- | ------- | ---- | --------------- | +| 7.5+ | 10 | 8.2+ | Feb 2025 | +| | | 8.1+ | Nov 2024 | +| 7.0+ | 9 | 8.2+ | Feb 2024 | +| | | 8.1+ | Feb 2024 | +| | | 8.0+ | Nov 2023 | -Quickstart Guides: +You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). -- [Session-based Authentication](https://auth0.com/docs/quickstart/webapp/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) -- [Token-based Authorization](https://auth0.com/docs/quickstart/backend/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) +## Installation -Documentation: - -- [Getting Started](./README.md#getting-started) — Installing and configuring the SDK. -- [Examples](./EXAMPLES.md) — Answers and solutions for common questions and scenarios. -- Reference: - - [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. - - [Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. - - [Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2). - - [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent). - - [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. -- [Auth0 Documentation](https://www.auth0.com/docs) -- [Auth0 Management API Explorer](https://auth0.com/docs/api/management/v2) -- [Auth0 Authentication API Explorer](https://auth0.com/docs/api/authentication) +
-## Getting Started +Using Quickstart (Fastest) -### Requirements +- Run the following command to create a new Laravel 9 project pre-configured with the SDK: -You will need to use a [supported version](#support-policy) of PHP and Laravel: + ```shell + composer create-project auth0-samples/laravel auth0-laravel-app + ``` -| Laravel | PHP | -| ------- | ---- | -| 10 | 8.1+ | -| 9 | 8.0+ | +--- -You'll also need an [Auth0 account](https://auth0.com/signup), as well as [Composer](https://getcomposer.org/) and the [Auth0 CLI](https://github.com/auth0/auth0-cli). +
---- +
+Using Composer -### SDK Installation +1. Run the following command in your project directory to install the SDK: -Run the following command within your project directory to install the [Auth0 Laravel SDK](https://github.com/auth0/laravel-auth0): + ```shell + composer require auth0/login:^7.8 --update-with-all-dependencies + ``` -```shell -composer require auth0/login:^7.8 --update-with-all-dependencies -``` +2. Generate an SDK configuration file for your application: -Then generate an SDK configuration file for your application: + ```shell + php artisan vendor:publish --tag auth0 + ``` -```shell -php artisan vendor:publish --tag auth0 -``` +
---- +## Configuration -### SDK Configuration +
+Using JSON (Fastest) -> **Note** -> If you prefer to use environment variables to configure the SDK, please see [docs/Installation](./docs/Installation.md) for guidance. +1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your project directory: -Run the following command from your project directory to download the [Auth0 CLI](https://github.com/auth0/auth0-cli): + > **Note** + > If you are using the Quickstart, skip to the next step. -```shell -curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . -``` + ```shell + curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . + ``` -Then authenticate the CLI with your Auth0 account: +2. Authenticate with your Auth0 account: -```shell -./auth0 login -``` + ```shell + ./auth0 login + ``` -Next, create a new application with Auth0: - -```shell -./auth0 apps create \ - --name "My Laravel Application" \ - --type "regular" \ - --auth-method "post" \ - --callbacks "http://localhost:8000/callback" \ - --logout-urls "http://localhost:8000/" \ - --reveal-secrets \ - --no-input \ - --json > .auth0.app.json -``` +3. Register a new application with Auth0: -You should also create a new API: + ```shell + ./auth0 apps create \ + --name "My Laravel Application" \ + --type "regular" \ + --auth-method "post" \ + --callbacks "http://localhost:8000/callback" \ + --logout-urls "http://localhost:8000/" \ + --reveal-secrets \ + --no-input \ + --json > .auth0.app.json + ``` -```shell -./auth0 apis create \ - --name "My Laravel Application API" \ - --identifier "https://github.com/auth0/laravel-auth0" \ - --offline-access \ - --no-input \ - --json > .auth0.api.json -``` +4. Register a new API with Auth0: -This produces two files in your project directory that configure the SDK. + ```shell + ./auth0 apis create \ + --name "My Laravel Application API" \ + --identifier "https://github.com/auth0/laravel-auth0" \ + --offline-access \ + --no-input \ + --json > .auth0.api.json + ``` -As these files contain credentials it's important to treat these as sensitive. You should ensure you do not commit these to version control. If you're using Git, you should add them to your `.gitignore` file: +5. Add the new files to `.gitignore`: -```bash -echo ".auth0.*.json" >> .gitignore -``` + ```bash + echo ".auth0.*.json" >> .gitignore + ``` --- -### Authentication +
+ +
+Using Environment Variables + +1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your project directory: + + > **Note** + > If you are using the Quickstart, skip to the next step. + + ```shell + curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . + ``` + +2. Authenticate with your Auth0 account: + + ```shell + ./auth0 login + ``` + +3. Register a new application with Auth0: + + ```shell + ./auth0 apps create \ + --name "My Laravel Application" \ + --type "regular" \ + --auth-method "post" \ + --callbacks "http://localhost:8000/callback" \ + --logout-urls "http://localhost:8000/" \ + --reveal-secrets \ + --no-input + ``` + + Make a note of the `client_id` and `client_secret` values in the output. + +4. Register a new API with Auth0: + + ```shell + ./auth0 apis create \ + --name "My Laravel Application API" \ + --identifier "https://github.com/auth0/laravel-auth0" \ + --offline-access \ + --no-input + ``` + +5. Open the `.env` file in your project directory. Add the following lines, replacing the values with the ones you noted in the previous steps: + + ```ini + # The Auth0 domain for your tenant (e.g. tenant.region.auth0.com): + AUTH0_DOMAIN=... + + # The application `client_id` you noted above: + AUTH0_CLIENT_ID=... + + # The application `client_secret` you noted above: + AUTH0_CLIENT_SECRET=... + + # The API `identifier` you used above: + AUTH0_AUDIENCE=... + ``` -The SDK automatically registers all the necessary facilities within the `web` middleware group for your users to authenticate with your application. These routes are: + Additional variables are available. More on those in the [configuration guide](./docs/Configuration.md). + +
+ +## Quickstarts + +- [Session-based Authentication](https://auth0.com/docs/quickstart/webapp/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) +- [Token-based Authorization](https://auth0.com/docs/quickstart/backend/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) + +## Examples + +
+Authentication +  + +The SDK automatically registers all the necessary authentication services within the `web` middleware group for your application. Once you have [configured the SDK](#configuration) your users will be able to authenticate with your application using Auth0. + +The SDK automatically registers the following routes to facilitate authentication: | Route | Purpose | | ----------- | ---------------------------------- | @@ -123,19 +193,20 @@ The SDK automatically registers all the necessary facilities within the `web` mi | `/logout` | Logs the user out. | | `/callback` | Handles the callback from Auth0. | -See [docs/Configuration](./docs/Configuration.md) for guidance on disabling automatic registration, and manually registering these facilities. +> **Note** +> See [the configuration guide](./docs/Configuration.md) for information on customizing this behavior. --- -### Access Control - -The SDK automatically registers its authentication and authorization guards into the standard `web` and `api` middleware groups for your Laravel application, respectively. +
-See [docs/Configuration](./docs/Configuration.md) for guidance on disabling this automatic registration, and manually registering the guards. +
+Access Control +  -You can use the Auth0 SDK's authentication guard to restrict access to your application's routes. +The SDK automatically registers its authentication and authorization guards within the `web` and `api` middleware groups for your Laravel application. -To require the requesting party to be authenticated (routes using the `web` middleware defined in `routes/web.php`) or authorized (routes using the `api` middleware defined in `routes/api.php`), you can use Laravel's `auth` middleware: +To require a user to be authenticated to access a route, use Laravel's `auth` middleware: ```php Route::get('/private', function () { @@ -143,7 +214,7 @@ Route::get('/private', function () { })->middleware('auth'); ``` -You can also require the requestor to have specific [permissions](https://auth0.com/docs/manage-users/access-control/rbac)](https://auth0.com/docs/manage-users/access-control/rbac) by combining this with Laravel's `can` middleware: +You can also require that the user have specific permissions to access a route, using Laravel's `can` middleware: ```php Route::get('/scope', function () { @@ -151,16 +222,20 @@ Route::get('/scope', function () { })->middleware('auth')->can('read:messages'); ``` -> **Note** -> Permissions need RBAC to be enabled on [your Auth0 API's settings](https://manage.auth0.com/#/apis). +> **Note** +> Permissions require that [RBAC](https://auth0.com/docs/manage-users/access-control/rbac) be enabled within [your API settings](https://manage.auth0.com/#/apis). --- -### User and Token Information +
-When requests are made to your application, the SDK will automatically attempt to authenticate or authorize the requestor, depending on the type of route. Information about the requesting party is expressed through the `user()` method of Laravel's `Auth` Facade, or the `auth()` helper function. +
+Users and Tokens +  -For routes using the `web` middleware defined in `routes/web.php`, the `user()` method will return profile information for the authenticated user. +Laravel's `Auth` Facade (or the `auth()` global helper) can be used to retrieve information about the authenticated user, or the access token used to authorize the request. + +For example, for routes using the `web` middleware group in `routes/web.php`: ```php Route::get('/', function () { @@ -173,16 +248,16 @@ Route::get('/', function () { $email = $user->email ?? ''; return response("Hello {$name}! Your email address is {$email}."); -});; +}); ``` -For routes using the `api` middleware defined in `routes/api.php`, the `user()` method will return details about the access token. +Alternatively, for routes using the `api` middleware group in `routes/api.php`: ```php Route::get('/', function () { if (! auth()->check()) { return response()->json([ - 'message' => 'You did not provide a valid token.', + 'message' => 'You did not provide a token.', ]); } @@ -196,23 +271,27 @@ Route::get('/', function () { --- -### Management API +
-You can update user information using the [Auth0 Management API](https://github.com/auth0/laravel-auth0/blob/main/docs/Management.md). All Management endpoints are accessible through the SDK's `management()` method. +
+Management API +  -**Before making Management API calls you must enable your application to communicate with the Management API.** This can be done from the [Auth0 Dashboard's API page](https://manage.auth0.com/#/apis/), choosing `Auth0 Management API`, and selecting the 'Machine to Machine Applications' tab. Authorize your Laravel application, and then click the down arrow to choose the scopes you wish to grant. +You can issue [Auth0 Management API](https://auth0.com/docs/api/management/v2) calls through the SDK's `management()` method. -For the following example, in which we will update a user's metadata and assign a random favorite color, you should grant the `read:users` and `update:users` scopes. A list of API endpoints and the required scopes can be found in [the Management API documentation](https://auth0.com/docs/api/management/v2). +> **Note** +> Before your application can make calls to the Management API, you must [enable your application to communicate with the Management API](./docs/Management.md#management-api-permissions) or configure the SDK with [a management token](./docs/Configuration.md#management-token). + +For example, you can update a user's metadata by calling the `management()->users()->update()` method: ```php use Auth0\Laravel\Facade\Auth0; Route::get('/colors', function () { - $endpoint = Auth0::management()->users(); - $colors = ['red', 'blue', 'green', 'black', 'white', 'yellow', 'purple', 'orange', 'pink', 'brown']; - $endpoint->update( + // Update the authenticated user with a randomly assigned favorite color. + Auth0::management()->users()->update( id: auth()->id(), body: [ 'user_metadata' => [ @@ -221,76 +300,66 @@ Route::get('/colors', function () { ] ); - $metadata = $endpoint->get(auth()->id()); - $metadata = Auth0::json($metadata); + // Retrieve the user's updated profile. + $profile = Auth0::management()->users()->get(auth()->id()); + + // For interoperability, the SDK returns all API responses as + // PSR-7 Responses that contain the JSON response. + + // You can use the `json()` helper to unpack the PSR-7, and + // convert the API's JSON response to a native PHP array. + $profile = Auth0::json($profile); - $color = $metadata['user_metadata']['color'] ?? 'unknown'; + // Read the user's profile. + $color = $profile['user_metadata']['color'] ?? 'unknown'; $name = auth()->user()->name; return response("Hello {$name}! Your favorite color is {$color}."); })->middleware('auth'); ``` -A quick reference guide of all the SDK's Management API methods is [available here](https://github.com/auth0/laravel-auth0/blob/main/docs/Management.md). +All the SDK's Management API methods are [documented here](./docs/Management.md). ---- - -## Gates and Policies - -The SDK supports [Laravel's Authorization API](https://laravel.com/docs/authorization#main-content) and provides several convenient pre-built [Gates](https://laravel.com/docs/authorization#gates) for common tasks. - -| Gate | Facade Usage | Middleware Usage | Purpose | -| ------------ | --------------------------------------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `scope` | `Gate::check('scope', 'email');` | `Route::get(/*...*/)->can('scope', 'email');` | Determine if the user's access token has a specified [scope](https://auth0.com/docs/get-started/apis/scopes). | -| `permission` | `Gate::check('permission', 'read:messages');` | `Route::get(/*...*/)->can('permission', 'read:messages');` | Determine if the user's access token has a specified [permission](https://auth0.com/docs/manage-users/access-control/rbac). This requires RBAC be enabled on [your Auth0 API's settings](https://manage.auth0.com/#/apis). | -| `*:*` | `Gate::check('read:messages');` | `Route::get(/*...*/)->can('read:messages');` | A convenience alias for `permission` (described above), you can supply any permission string in the colon-delimited `ability:context` syntax. | - -Using these gates, you can easily authorize users or access tokens to perform actions in your application. Your application can use Laravel's [Policies API](https://laravel.com/docs/authorization#creating-policies) in combination with these gates to further simplify authorization. - ---- - -## Support Policy +
-Our support lifecycle mirrors the [Laravel release support](https://laravel.com/docs/releases#support-policy) and [PHP release support](https://www.php.net/supported-versions.php) schedules. - -| SDK Version | Laravel Version | PHP Version | Support Ends | -| ----------- | --------------- | ----------- | ------------ | -| 7.5+ | 10 | 8.2 | Feb 2025 | -| | | 8.1 | Nov 2024 | -| 7.0+ | 9 | 8.2 | Feb 2024 | -| | | 8.1 | Feb 2024 | -| | | 8.0 | Nov 2023 | +## Documentation -We drop support for Laravel and PHP versions when they reach end-of-life and cease receiving security fixes from Laravel and the PHP Foundation, whichever comes first. Please ensure your environment remains up to date so you can continue receiving updates for Laravel, PHP, and this SDK. +- [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. +- [Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. +- [Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2). +- [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent). +- [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. +- [Octane](./docs/Octane.md) — We do not support using the SDK with [Octane](https://laravel.com/docs/octane) at this time. ---- +You may also find the following resources helpful: -## Octane Support +- [Auth0 Documentation Hub](https://www.auth0.com/docs) +- [Auth0 Management API Explorer](https://auth0.com/docs/api/management/v2) +- [Auth0 Authentication API Explorer](https://auth0.com/docs/api/authentication) -Octane compatibility is currently considered experimental and unsupported. +Contributions to improve our documentation [are welcomed](https://github.com/auth0/laravel-auth0/pull). -Although we are working toward ensuring the SDK is fully compatible with this feature, we do not recommend using this with our SDK in production until we have full confidence and announced support. Due to the caching behavior of Octane, there is an opportunity for problems we have not fully identified or resolved yet. +## Community -Feedback and bug-fix contributions are greatly appreciated as we work toward full support. +The [Auth0 Community](https://community.auth0.com) is where you can ask questions, get support, and share your projects. ---- +## Contributing -## Feedback +We appreciate feedback and contributions to this library. Before you get started, please review Auth0's [General Contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md). Read [our contributing guide](./CONTRIBUTING.md) to learn about how to propose bug fixes and improvements, and how to build and test your changes to the library. -### Contributing +To provide feedback or report a bug, [please raise an issue](https://github.com/auth0/laravel-auth0/issues). -We appreciate feedback and contribution to this repo! Before you get started, please see the following: +## Code of Conduct -- [Auth0's general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) -- [Auth0's code of conduct guidelines](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) +Participants are expected to adhere to our [code of conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) when interacting with this project. -### Raise an issue +## Security -To provide feedback or report a bug, [please raise an issue on our issue tracker](https://github.com/auth0/laravel-auth0/issues). +If you believe you have found a security vulnerability, we encourage you to responsibly disclose this and not open a public issue. We will investigate all reports. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. -### Vulnerability Reporting +## License -Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. +This library is open-sourced software licensed under the [MIT license](./LICENSE.md). --- @@ -303,5 +372,3 @@ Please do not report security vulnerabilities on the public GitHub issue tracker

Auth0 is an easy-to-implement, adaptable authentication and authorization platform.
To learn more, check out "Why Auth0?"

- -

This project is licensed under the MIT license. See the LICENSE file for more info.

From a6260f995b650b2999050727370517f25d9debc7 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:46:38 -0500 Subject: [PATCH 381/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4fd1eda5..9be28ed7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ![laravel-auth0](https://cdn.auth0.com/website/sdks/banners/laravel-auth0-banner.png)

-Build Status +Build Status Code Coverage Total Downloads License From 50f5a72cefca55177e49ce538a908e0b21c95f50 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:53:00 -0500 Subject: [PATCH 382/525] Create CONTRIBUTING.md --- .github/CONTRIBUTING.md | 91 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 .github/CONTRIBUTING.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000..969cb7c5 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,91 @@ +# Contribution Guide + +- [Getting Involved](#getting-involved) +- [Support Questions](#support-questions) +- [Code Contributions](#code-contributions) +- [Security Vulnerabilities](#security-vulnerabilities) +- [Coding Style](#coding-style) + - [PHPDoc](#phpdoc) +- [Code of Conduct](#code-of-conduct) + +## Getting Involved + +To encourage active collaboration, Auth0 strongly encourages pull requests, not just bug reports. Pull requests will only be reviewed when marked as "ready for review" (not in the "draft" state) and all tests for new features are passing. Lingering, non-active pull requests left in the "draft" state will eventually be closed. + +If you file a bug report, your issue should contain a title and a clear description of the issue. You should also include as much relevant information as possible and a code sample that demonstrates the issue. The goal of a bug report is to make it easy for yourself - and others - to replicate the bug and develop a fix. + +Remember, bug reports are created in the hope that others with the same problem will be able to collaborate with you on solving it. Do not expect that the bug report will automatically see any activity or that others will jump to fix it. Creating a bug report serves to help yourself and others start on the path of fixing the problem. If you want to chip in, you can help out by fixing any bugs listed in our issue trackers. + +## Support Questions + +Auth0's GitHub issue trackers are not intended to provide integration support. Instead, please refer your questions to the [Auth0 Community](https://community.auth0.com). + +## Code Contributions + +You may propose new features or improvements of existing SDK behavior by creating a feature request within the repository's issue tracker. If you are willing to implement at least some of the code that would be needed to complete the feature, please fork the repository and submit a pull request. + +All development should be done in individual forks using dedicated branches, and submitted against the `main` default branch. + +Pull request titles must follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) rules so our changelogs can be automatically generated. Commits messages are irrelevant as they will be squashed into the Pull request's title during merge. + +The following types are allowed: + +- _feat:_ A new feature +- _perf:_ A code change that improves performance +- _refactor:_ A code change that neither fixes a bug nor adds a feature +- _build:_ Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) +- _ci:_ Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs) +- _style:_ Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) +- _fix:_ A bug fix +- _security:_ A change that improves security +- _docs:_ Documentation only changes +- _test:_ Adding missing tests or correcting existing tests + +## Security Vulnerabilities + +If you discover a security vulnerability within this SDK, please review Auth0's [Responsible Disclosure Program](https://auth0.com/responsible-disclosure-policy) details the procedure for disclosing security issues. All security vulnerabilities will be promptly addressed. + +## Unit Testing and 100% Minimum Coverage + +We use [PEST](https://pestphp.com/) for testing. You can run `composer pest` to run the test suite. You can also run `composer pest:coverage` to generate a code coverage report. + +We require 100% code coverage for all new features. If you are adding a new feature, please add tests to cover all of the new code. If you are fixing a bug, please add a test that reproduces the bug and then shows that it has been fixed. + +Pull requests that do not meet the minimum coverage requirements will not be merged. + +## Static Analysis + +We use [PHPStan](https://phpstan.org) and [Psalm](https://psalm.dev/) for static analysis. You can run `composer psalm` to run the static analysis. + +## Coding Style + +We use [PHP CS Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) to ensure that the code style is consistent. You can run `composer phpcs` to check for any code style issues. `composer phpcs:fix` will attempt to automatically fix the issues, but be cautious as it may not always get it right. + +We also use [Rector](https://github.com/rectorphp/rector) to catch edge cases where more optimal refactoring can be made. You can run `composer rector` to check for any recommendations, and `composer rector:fix` will to accept the suggested changes. + +It's important to note that our GitHub CI will also run these checks for pull requests, but you should run these locally first to avoid any surprises when you push your code. If you disagree with one of these tools recommendations, please bring it up in the pull request so we can discuss it. We may decide to adjust the styling rules if we feel it's warranted, but we prefer to avoid it if possible. + +### PHPDoc + +Below is an example of a valid documentation block. Note that the @param attribute is followed by two spaces, the argument type, two more spaces, and finally the variable name: + +```php +/** + * Register a binding with the container. + * + * @param string|array $abstract + * @param \Closure|string|null $concrete + * @param bool $shared + * @return void + * + * @throws \Exception + */ +public function bind($abstract, $concrete = null, $shared = false) +{ + // +} +``` + +## Code of Conduct + +Before making any contributions to this repo, please review Auth0's [Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). By contributing, you agree to uphold this code. From 538ad9db7c77e046436131987eda4d106fb86aeb Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:53:03 -0500 Subject: [PATCH 383/525] Update README.md --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9be28ed7..48653b64 100644 --- a/README.md +++ b/README.md @@ -341,17 +341,19 @@ Contributions to improve our documentation [are welcomed](https://github.com/aut ## Community -The [Auth0 Community](https://community.auth0.com) is where you can ask questions, get support, and share your projects. +The [Auth0 Community](https://community.auth0.com) is where you can get support, ask questions, and share your projects. ## Contributing -We appreciate feedback and contributions to this library. Before you get started, please review Auth0's [General Contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md). Read [our contributing guide](./CONTRIBUTING.md) to learn about how to propose bug fixes and improvements, and how to build and test your changes to the library. +We appreciate feedback and contributions to this library. Before you get started, please review Auth0's [General Contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md). + +The [Contribution Guide](./github/CONTRIBUTING.md) contains information about our development process and expectations, insight into how to propose bug fixes and improvements, and instructions on how to build and test changes to the library. To provide feedback or report a bug, [please raise an issue](https://github.com/auth0/laravel-auth0/issues). ## Code of Conduct -Participants are expected to adhere to our [code of conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) when interacting with this project. +Participants are expected to adhere to Auth0's [Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) when interacting with this project. ## Security From 19eb71fd2c3f134b236f3d0d730e47658ce808c8 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:58:39 -0500 Subject: [PATCH 384/525] Update Configuration.md --- docs/Configuration.md | 68 +++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 4a8c5b56..681be973 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -25,43 +25,43 @@ Where `` is the value of Laravel's `APP_ENV` environment variable (if s The SDK supports the use of environment variables to configure the SDK. These can be defined in the `.env` file in the root of your project, or in your hosting environment. -| Variable | Description | -| --------------------- | --------------------------------------------------------------------------------------------------- | -| `AUTH0_STRATEGY` | String. The Auth0 strategy to use. | -| `AUTH0_DOMAIN` | String (FQDN.) The Auth0 domain for your tenant. | -| `AUTH0_CUSTOM_DOMAIN` | String (FQDN.) The Auth0 custom domain for your tenant, if set. | -| `AUTH0_CLIENT_ID` | String. The Client ID for your Auth0 application. | -| `AUTH0_CLIENT_SECRET` | String. The Client Secret for your Auth0 application. | -| `AUTH0_COOKIE_SECRET` | String. The optional secret used to encrypt the cookie used by the SDK. | -| `AUTH0_REDIRECT_URI` | String (URL.) The redirect URI for your application. | -| `AUTH0_AUDIENCE` | String (comma-delimited list.) The audiences for your application. | -| `AUTH0_SCOPE` | String (comma-delimited list.) The scopes for your application. Defaults to 'openid,profile,email'. | -| `AUTH0_ORGANIZATION` | String (comma-delimited list.) The organizations for your application. | +| Variable | Description | +| --------------------- | ---------------------------------------------------------------------------------------------------- | +| `AUTH0_STRATEGY` | `String` The Auth0 strategy to use. | +| `AUTH0_DOMAIN` | `String (FQDN)` The Auth0 domain for your tenant. | +| `AUTH0_CUSTOM_DOMAIN` | `String (FQDN)` The Auth0 custom domain for your tenant, if set. | +| `AUTH0_CLIENT_ID` | `String` The Client ID for your Auth0 application. | +| `AUTH0_CLIENT_SECRET` | `String` The Client Secret for your Auth0 application. | +| `AUTH0_COOKIE_SECRET` | `String` The optional secret used to encrypt the cookie used by the SDK. | +| `AUTH0_REDIRECT_URI` | `String` (URL) The redirect URI for your application. | +| `AUTH0_AUDIENCE` | `String (comma-delimited list)` The audiences for your application. | +| `AUTH0_SCOPE` | `String (comma-delimited list)` The scopes for your application. Defaults to 'openid,profile,email'. | +| `AUTH0_ORGANIZATION` | `String (comma-delimited list)` The organizations for your application. | The following environment variables are also supported, but should not be adjusted unless you know what you are doing: -| Variable | Description | -| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `AUTH0_USE_PKCE` | Boolean. Whether to use PKCE for the authorization flow. Defaults to `true`. | -| `AUTH0_RESPONSE_MODE` | String. The response mode to use for the authorization flow. Defaults to `query`. | -| `AUTH0_RESPONSE_TYPE` | String. The response type to use for the authorization flow. Defaults to `code`. | -| `AUTH0_TOKEN_ALGORITHM` | String. The algorithm to use for the ID token. Defaults to `RS256`. | -| `AUTH0_TOKEN_JWKS_URI` | String (URL.) The URI to use to retrieve the JWKS for the ID token. Defaults to `https:///.well-known/jwks.json`. | -| `AUTH0_TOKEN_MAX_AGE` | Integer. The maximum age of a token, in seconds. No default value is assigned. | -| `AUTH0_TOKEN_LEEWAY` | Integer. The leeway to use when validating a token, in seconds. Defaults to `60` (1 minute). | -| `AUTH0_TOKEN_CACHE` | String (class name.) A PSR-6 class to use for caching JWKS responses. | -| `AUTH0_TOKEN_CACHE_TTL` | Integer. The TTL to use for caching JWKS responses. Defaults to `60` (1 minute). | -| `AUTH0_HTTP_MAX_RETRIES` | Integer. The maximum number of times to retry a failed HTTP request. Defaults to `3`. | -| `AUTH0_HTTP_TELEMETRY` | Boolean. Whether to send telemetry data with HTTP requests to Auth0. Defaults to `true`. | -| `AUTH0_SESSION_STORAGE` | String (class name.) The `StoreInterface` class to use for storing session data. Defaults to using Laravel's native Sessions API. | -| `AUTH0_SESSION_STORAGE_ID` | String. The namespace to use for storing session data. Defaults to `auth0_session`. | -| `AUTH0_TRANSIENT_STORAGE` | String (class name.) The `StoreInterface` class to use for storing temporary session data. Defaults to using Laravel's native Sessions API. | -| `AUTH0_TRANSIENT_STORAGE_ID` | String. The namespace to use for storing temporary session data. Defaults to `auth0_transient`. | -| `AUTH0_MANAGEMENT_TOKEN` | String (class name.) The Management API token to use for the Management API client. (If one is not provided, the SDK will attempt to create one for you.) | -| `AUTH0_MANAGEMENT_TOKEN_CACHE` | Integer. A PSR-6 class to use for caching Management API tokens. | -| `AUTH0_CLIENT_ASSERTION_SIGNING_KEY` | String. The key to use for signing client assertions. | -| `AUTH0_CLIENT_ASSERTION_SIGNING_ALGORITHM` | String. The algorithm to use for signing client assertions. Defaults to `RS256`. | -| `AUTH0_PUSHED_AUTHORIZATION_REQUEST` | Boolean. Whether the SDK should use Pushed Authorization Requests during authentication. Note that your tenant must have this feature enabled. Defaults to `false`. | +| Variable | Description | +| ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `AUTH0_USE_PKCE` | Boolean. Whether to use PKCE for the authorization flow. Defaults to `true`. | +| `AUTH0_RESPONSE_MODE` | `String` The response mode to use for the authorization flow. Defaults to `query`. | +| `AUTH0_RESPONSE_TYPE` | `String` The response type to use for the authorization flow. Defaults to `code`. | +| `AUTH0_TOKEN_ALGORITHM` | `String` The algorithm to use for the ID token. Defaults to `RS256`. | +| `AUTH0_TOKEN_JWKS_URI` | `String (URL)` The URI to use to retrieve the JWKS for the ID token. Defaults to `https:///.well-known/jwks.json`. | +| `AUTH0_TOKEN_MAX_AGE` | `Integer` The maximum age of a token, in seconds. No default value is assigned. | +| `AUTH0_TOKEN_LEEWAY` | `Integer` The leeway to use when validating a token, in seconds. Defaults to `60` (1 minute). | +| `AUTH0_TOKEN_CACHE` | `String (class name)` A PSR-6 class to use for caching JWKS responses. | +| `AUTH0_TOKEN_CACHE_TTL` | `Integer` The TTL to use for caching JWKS responses. Defaults to `60` (1 minute). | +| `AUTH0_HTTP_MAX_RETRIES` | `Integer` The maximum number of times to retry a failed HTTP request. Defaults to `3`. | +| `AUTH0_HTTP_TELEMETRY` | `Boolean` Whether to send telemetry data with HTTP requests to Auth0. Defaults to `true`. | +| `AUTH0_SESSION_STORAGE` | `String (class name)` The `StoreInterface` class to use for storing session data. Defaults to using Laravel's native Sessions API. | +| `AUTH0_SESSION_STORAGE_ID` | `String` The namespace to use for storing session data. Defaults to `auth0_session`. | +| `AUTH0_TRANSIENT_STORAGE` | `String (class name)` The `StoreInterface` class to use for storing temporary session data. Defaults to using Laravel's native Sessions API. | +| `AUTH0_TRANSIENT_STORAGE_ID` | `String` The namespace to use for storing temporary session data. Defaults to `auth0_transient`. | +| `AUTH0_MANAGEMENT_TOKEN` | `String` The Management API token to use for the Management API client. If one is not provided, the SDK will attempt to create one for you. | +| `AUTH0_MANAGEMENT_TOKEN_CACHE` | `Integer` A PSR-6 class to use for caching Management API tokens. | +| `AUTH0_CLIENT_ASSERTION_SIGNING_KEY` | `String` The key to use for signing client assertions. | +| `AUTH0_CLIENT_ASSERTION_SIGNING_ALGORITHM` | `String` The algorithm to use for signing client assertions. Defaults to `RS256`. | +| `AUTH0_PUSHED_AUTHORIZATION_REQUEST` | `Boolean` Whether the SDK should use Pushed Authorization Requests during authentication. Note that your tenant must have this feature enabled. Defaults to `false`. | ## Overriding Automatic Behavior From 1c60af75ddf8e84f5428f643b4e6f294621ee27c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sat, 20 May 2023 23:58:43 -0500 Subject: [PATCH 385/525] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 48653b64..0febdfdc 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h AUTH0_AUDIENCE=... ``` - Additional variables are available. More on those in the [configuration guide](./docs/Configuration.md). + Additional variables are available. More on those in the [configuration guide](./docs/Configuration.md#environment-variables).

@@ -194,7 +194,7 @@ The SDK automatically registers the following routes to facilitate authenticatio | `/callback` | Handles the callback from Auth0. | > **Note** -> See [the configuration guide](./docs/Configuration.md) for information on customizing this behavior. +> See [the configuration guide](./docs/Configuration.md#authentication-routes) for information on customizing this behavior. --- From 123822e6d13cfa7aa145156ad1825ca07a2b3a1e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 21 May 2023 00:06:38 -0500 Subject: [PATCH 386/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0febdfdc..14b0eebf 100644 --- a/README.md +++ b/README.md @@ -347,7 +347,7 @@ The [Auth0 Community](https://community.auth0.com) is where you can get support, We appreciate feedback and contributions to this library. Before you get started, please review Auth0's [General Contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md). -The [Contribution Guide](./github/CONTRIBUTING.md) contains information about our development process and expectations, insight into how to propose bug fixes and improvements, and instructions on how to build and test changes to the library. +The [Contribution Guide](./.github/CONTRIBUTING.md) contains information about our development process and expectations, insight into how to propose bug fixes and improvements, and instructions on how to build and test changes to the library. To provide feedback or report a bug, [please raise an issue](https://github.com/auth0/laravel-auth0/issues). From 991d6cfb81586368ccd34834b37d8f1938fab92f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 21 May 2023 00:09:28 -0500 Subject: [PATCH 387/525] Update CONTRIBUTING.md --- .github/CONTRIBUTING.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 969cb7c5..fbb4e82e 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -55,18 +55,20 @@ Pull requests that do not meet the minimum coverage requirements will not be mer ## Static Analysis -We use [PHPStan](https://phpstan.org) and [Psalm](https://psalm.dev/) for static analysis. You can run `composer psalm` to run the static analysis. +We use [PHPStan](https://phpstan.org) and [Psalm](https://psalm.dev/) for static analysis. You can use `composer phpstan` and `composer psalm` to run them. ## Coding Style -We use [PHP CS Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) to ensure that the code style is consistent. You can run `composer phpcs` to check for any code style issues. `composer phpcs:fix` will attempt to automatically fix the issues, but be cautious as it may not always get it right. +We use [PHP CS Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) to ensure that code styling is consistent. You can run `composer phpcs` to check for any code style issues. `composer phpcs:fix` will attempt to automatically fix the issues, but be cautious as it may not always get it right. -We also use [Rector](https://github.com/rectorphp/rector) to catch edge cases where more optimal refactoring can be made. You can run `composer rector` to check for any recommendations, and `composer rector:fix` will to accept the suggested changes. +We also use [Rector](https://github.com/rectorphp/rector) to catch edge cases where more optimal refactoring can be made. You can run `composer rector` to check for any recommendations, and `composer rector:fix` to accept the suggestions. It's important to note that our GitHub CI will also run these checks for pull requests, but you should run these locally first to avoid any surprises when you push your code. If you disagree with one of these tools recommendations, please bring it up in the pull request so we can discuss it. We may decide to adjust the styling rules if we feel it's warranted, but we prefer to avoid it if possible. ### PHPDoc +All public methods and classes should be documented with PHPDoc blocks. + Below is an example of a valid documentation block. Note that the @param attribute is followed by two spaces, the argument type, two more spaces, and finally the variable name: ```php From b1d63e5c3b023303880d5602dc28ead973db33a1 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 21 May 2023 00:27:40 -0500 Subject: [PATCH 388/525] Update Users.md --- docs/Users.md | 51 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/docs/Users.md b/docs/Users.md index b276a9bc..c97a14d9 100644 --- a/docs/Users.md +++ b/docs/Users.md @@ -1,14 +1,19 @@ # Users +- [Retrieving User Information](#retrieving-user-information) +- [Updating User Information](#updating-user-information) +- [Custom User Repositories](#custom-user-repositories) +- [Custom User Models](#custom-user-models) + ## Retrieving User Information -To retrieve information about the currently authenticated user, use the `user()` method on the `Auth0` facade, or the `auth0()` helper. +To retrieve information about the currently authenticated user, use the `user()` method on the `Auth` facade or `auth()` helper. ```php auth()->user(); ``` -You can also retrieve information for any user using [the Management API](./Management.md). This also returns extended information about the user, including stored metadata. +You can also retrieve information on any user using [the Management API](./Management.md). This also returns extended information not usually contained in the authentication state such as user metadata. ```php use Auth0\Laravel\Facade\Auth0; @@ -45,16 +50,16 @@ Route::get('/update', function () { })->middleware('auth'); ``` -## Custom User Models and Repositories +## Custom User Repositories The Auth0 Laravel SDK uses the repository pattern to allow the abstraction of potential database operations. This pattern is useful for building completely custom integrations that fit your application's needs. ### Creating a User Repository -Creating a repository is simple: it must implement the `Auth0\Laravel\Auth\User\RepositoryContract` interface, and include two methods: +Creating a repository is simple: it must implement the `Auth0\Laravel\UserRepositoryContract` interface, and include two methods: -- `fromSession()` is used to retrieve a user from the application's session. -- `fromAccessToken` is used to retrieve a user from an access token. +- `fromSession()` to construct a model for an authenticated user. +- `fromAccessToken` to construct a model representing an access token request. The default implementation looks like this: @@ -92,10 +97,10 @@ declare(strict_types=1); namespace App\Repositories; use App\Models\User; -use Auth0\Laravel\Auth\User\RepositoryContract; +use Auth0\Laravel\UserRepositoryContract; use Illuminate\Contracts\Auth\Authenticatable; -final class UserRepository implements RepositoryContract +final class UserRepository implements UserRepositoryContract { public function fromAccessToken(array $user): ?Authenticatable { @@ -117,14 +122,31 @@ final class UserRepository implements RepositoryContract } ``` -### Creating a User Model +### Registering the Repository -The repository is responsible for retrieving and storing users, but it does not define the user model itself. The SDK provides an abstract user model class that can be extended for building your own implementations, `Auth0\Laravel\Entities\UserAbstract`. +The SDK uses it's own repository implementation by default, but you can override this with your own by updating your application's `config/auth.php` file. Simply point the value of the `repository` key to your repository class. -- User models must implement the `Illuminate\Contracts\Auth\Authenticatable` interface, which is required for Laravel's authentication system. -- User models must also implement the `Auth0\Laravel\Entities\UserContract` interface, which is required by the Laravel SDK. +```php +'providers' => [ + 'auth0-provider' => [ + 'driver' => 'auth0.provider', + 'repository' => \App\Repositories\UserRepository::class, + ], +], +``` + +## Custom User Models + +The repository is responsible for retrieving and storing users, but does not itself define the models representing those users. To customize these, the SDK provides an abstract class that can be extended, `Auth0\Laravel\Users\UserAbstract`. + +User models must implement the following interfaces: -Because the abstract model already fulfills the requirements of these interfaces, you can use it as-is if you do not need to add any additional functionality. Here's an example customer user model that extends the SDK's abstract user model class to support Eloquent: +- `Illuminate\Contracts\Auth\Authenticatable` required by Laravel's authentication APIs. +- `Auth0\Laravel\Users\UserContract` required by the SDK. + +The abstract model already fulfills the requirements of these interfaces, so you can use it as-is if you do not require any additional functionality. + +Here's an example customer user model that extends the SDK's abstract user model class to support Eloquent: ```php \App\Repositories\UserRepository::class, ], ], +``` From b0eb0c7114d2f36fb692d99f557cd7a4d8af83a9 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 21 May 2023 00:31:16 -0500 Subject: [PATCH 389/525] Update Users.md --- docs/Users.md | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/docs/Users.md b/docs/Users.md index c97a14d9..edfad40e 100644 --- a/docs/Users.md +++ b/docs/Users.md @@ -97,10 +97,10 @@ declare(strict_types=1); namespace App\Repositories; use App\Models\User; -use Auth0\Laravel\UserRepositoryContract; +use Auth0\Laravel\{UserRepositoryAbstract, UserRepositoryContract}; use Illuminate\Contracts\Auth\Authenticatable; -final class UserRepository implements UserRepositoryContract +final class UserRepository extends UserRepositoryAbstract implements UserRepositoryContract { public function fromAccessToken(array $user): ?Authenticatable { @@ -175,20 +175,3 @@ final class User extends UserAbstract implements UserContract ]; } ``` - -# - -Once you have created your repository and model, you can integrate them into your application by updating your `config/auth.php` file and pointing the `repository` key to your repository class. - -```php -/** - * Register the SDK's User Provider with your application. - * You should not remove any other entries from this array. - */ -'providers' => [ - 'auth0-provider' => [ - 'driver' => 'auth0.provider', - 'repository' => \App\Repositories\UserRepository::class, - ], -], -``` From a91e1507161b4ffe39cb7766ba21539c4cf99d0b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 21 May 2023 00:42:51 -0500 Subject: [PATCH 390/525] Update Configuration.md --- docs/Configuration.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 681be973..4ffe79ee 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -1,6 +1,7 @@ # Configuration -This document is an addendum to the [README](../README.md) file and covers advanced configuration techniques. Please review the installation guidance there before continuing. +> **Note:** +> This is an addendum to the [README](../README.md) file. Please review that guidance first. This document covers 'version 2' of the SDK configuration format. You can determine which version you are using by looking for the `Configuration::VERSION_` const returned with the `config/auth0.php` array. From 7046b89ac0bca38dad609c1d4b4d15dd7247d534 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 21 May 2023 00:42:54 -0500 Subject: [PATCH 391/525] Update Installation.md --- docs/Installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Installation.md b/docs/Installation.md index 59563284..e7d61889 100644 --- a/docs/Installation.md +++ b/docs/Installation.md @@ -1,7 +1,7 @@ # Installation > **Note:** -> This is an addendum to the [README](../README.md) file. Please review that guidance there first. +> This is an addendum to the [README](../README.md) file. Please review that guidance first. ## Alternative Configuration Methods From 65c7878b16472ac5c91e6686da8b8ad1e9e84f80 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 21 May 2023 00:51:33 -0500 Subject: [PATCH 392/525] Update Configuration.md --- docs/Configuration.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 4ffe79ee..af34589a 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -7,11 +7,9 @@ This document covers 'version 2' of the SDK configuration format. You can determ ## JSON Configuration (Preferred) -The SDK can automatically configure itself using the JSON files exported using the [Auth0 CLI](https://auth0.com/docs/cli). +The preferred method of SDK configuration is to use JSON exported from the [Auth0 CLI](https://auth0.com/docs/cli). This allows you to use the CLI to manage your Auth0 configuration, and then export the configuration to JSON for use by the SDK. -This is the preferred method of configuration due to its ease of use. - -The SDK will look for the following files in the root of your project, in the order listed: +The SDK will look for the following files in the project directory, in the order listed: - `auth0.json` - `auth0..json` @@ -24,17 +22,14 @@ Where `` is the value of Laravel's `APP_ENV` environment variable (if s ## Environment Variables -The SDK supports the use of environment variables to configure the SDK. These can be defined in the `.env` file in the root of your project, or in your hosting environment. +The SDK also supports configuration using environment variables. These can be defined in the host environment, or in a `.env` file in the project directory. | Variable | Description | | --------------------- | ---------------------------------------------------------------------------------------------------- | -| `AUTH0_STRATEGY` | `String` The Auth0 strategy to use. | | `AUTH0_DOMAIN` | `String (FQDN)` The Auth0 domain for your tenant. | | `AUTH0_CUSTOM_DOMAIN` | `String (FQDN)` The Auth0 custom domain for your tenant, if set. | | `AUTH0_CLIENT_ID` | `String` The Client ID for your Auth0 application. | | `AUTH0_CLIENT_SECRET` | `String` The Client Secret for your Auth0 application. | -| `AUTH0_COOKIE_SECRET` | `String` The optional secret used to encrypt the cookie used by the SDK. | -| `AUTH0_REDIRECT_URI` | `String` (URL) The redirect URI for your application. | | `AUTH0_AUDIENCE` | `String (comma-delimited list)` The audiences for your application. | | `AUTH0_SCOPE` | `String (comma-delimited list)` The scopes for your application. Defaults to 'openid,profile,email'. | | `AUTH0_ORGANIZATION` | `String (comma-delimited list)` The organizations for your application. | @@ -72,7 +67,7 @@ By default, the SDK will register the Authentication and Authorization guards wi You can disable this behavior by setting `registerGuards` to false in your `config/auth0.php` file. -To register the guards manually, update your `config/auth.php` file as follows: +To register the guards manually, update the arrays in your `config/auth.php` file to include the following additions: ```php 'guards' => [ @@ -98,9 +93,11 @@ To register the guards manually, update your `config/auth.php` file as follows: ### Middleware Registration -By default, the SDK will register the Authentication and Authorization guards within your application's `web` and `api` middleware groups. You can disable this behavior by setting `registerMiddleware` to false in your `config/auth0.php` file. +By default, the SDK will register the Authentication and Authorization guards within your application's `web` and `api` middleware groups. + +You can disable this behavior by setting `registerMiddleware` to false in your `config/auth0.php` file. -To register the middleware manually, update your `app/Http/Kernel.php` file as follows: +To register the middleware manually, update your `app/Http/Kernel.php` file and include the following additions: ```php protected $middlewareGroups = [ @@ -142,13 +139,7 @@ By default, the SDK will register the following routes for authentication: You can disable this behavior by setting `registerAuthenticationRoutes` to false in your `config/auth0.php` file. -If you've disabled the automatic registration of routes, you can register the routes manually by adding the following to your `routes/web.php` file: - -```php -Auth0::routes(); -``` - -Or, if you prefer complete control over the routing process: +If you've disabled the automatic registration of routes, you must register the routes manually for authentication to work. ```php use Auth0\Laravel\Controllers\{LoginController, LogoutController, CallbackController}; @@ -159,3 +150,12 @@ Route::group(['middleware' => ['guard:auth0-session'], static function (): void Route::get('/callback', CallbackController::class)->name('callback'); }); ``` + +Or you can call the SDK Facade's `routes()` method in your `routes/web.php` file: + +```php +Auth0::routes(); +``` + +- These must be registered within the `web` middleware group, as they rely on sessions. +- Requests must be routed through the SDK's Authenticator guard. From c24ced729135cb5954cda54a1169f4b01f447edb Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:43:10 -0400 Subject: [PATCH 393/525] Create CODE_OF_CONDUCT.md --- .github/CODE_OF_CONDUCT.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/CODE_OF_CONDUCT.md diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..d04a2291 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# Code of Conduct + +Before making any contributions to this repo, please review Auth0's [Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). By contributing, you agree to uphold this code. From da8e3d0e562b7e28dce63227e3d85505430b0db4 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:43:12 -0400 Subject: [PATCH 394/525] Update CONTRIBUTING.md --- .github/CONTRIBUTING.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index fbb4e82e..55056aa9 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -14,7 +14,7 @@ To encourage active collaboration, Auth0 strongly encourages pull requests, not If you file a bug report, your issue should contain a title and a clear description of the issue. You should also include as much relevant information as possible and a code sample that demonstrates the issue. The goal of a bug report is to make it easy for yourself - and others - to replicate the bug and develop a fix. -Remember, bug reports are created in the hope that others with the same problem will be able to collaborate with you on solving it. Do not expect that the bug report will automatically see any activity or that others will jump to fix it. Creating a bug report serves to help yourself and others start on the path of fixing the problem. If you want to chip in, you can help out by fixing any bugs listed in our issue trackers. +Remember, bug reports are created in the hope that others with the same problem will be able to collaborate with you on solving it. Do not expect that the bug report will automatically see any activity or that others will jump to fix it. Creating a bug report serves to help you and others start on the path of fixing the problem. If you want to chip in, you can help out by fixing any bugs listed in our issue trackers. ## Support Questions @@ -22,11 +22,11 @@ Auth0's GitHub issue trackers are not intended to provide integration support. I ## Code Contributions -You may propose new features or improvements of existing SDK behavior by creating a feature request within the repository's issue tracker. If you are willing to implement at least some of the code that would be needed to complete the feature, please fork the repository and submit a pull request. +You may propose new features or improvements to existing SDK behavior by creating a feature request within the repository's issue tracker. If you are willing to implement at least some of the code that would be needed to complete the feature, please fork the repository and submit a pull request. All development should be done in individual forks using dedicated branches, and submitted against the `main` default branch. -Pull request titles must follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) rules so our changelogs can be automatically generated. Commits messages are irrelevant as they will be squashed into the Pull request's title during merge. +Pull request titles must follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) rules so our changelogs can be automatically generated. Commits messages are irrelevant as they will be squashed into the Pull request's title during a merge. The following types are allowed: @@ -35,7 +35,7 @@ The following types are allowed: - _refactor:_ A code change that neither fixes a bug nor adds a feature - _build:_ Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) - _ci:_ Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs) -- _style:_ Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) +- _style:_ Changes that do not affect the meaning of the code (white space, formatting, missing semi-colons, etc) - _fix:_ A bug fix - _security:_ A change that improves security - _docs:_ Documentation only changes @@ -63,7 +63,7 @@ We use [PHP CS Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) to ensure th We also use [Rector](https://github.com/rectorphp/rector) to catch edge cases where more optimal refactoring can be made. You can run `composer rector` to check for any recommendations, and `composer rector:fix` to accept the suggestions. -It's important to note that our GitHub CI will also run these checks for pull requests, but you should run these locally first to avoid any surprises when you push your code. If you disagree with one of these tools recommendations, please bring it up in the pull request so we can discuss it. We may decide to adjust the styling rules if we feel it's warranted, but we prefer to avoid it if possible. +It's important to note that our GitHub CI will also run these checks for pull requests, but you should run these locally first to avoid any surprises when you push your code. If you disagree with one of these recommendations, please bring it up in the pull request so we can discuss it. We may decide to adjust the styling rules if we feel it's warranted, but we prefer to avoid it if possible. ### PHPDoc From 4556c292d358c4b571ec2761b4d85a0dd3c6e76d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:43:15 -0400 Subject: [PATCH 395/525] Delete dependabot.yml --- .github/dependabot.yml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index dfb465a1..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,7 +0,0 @@ -version: 2 -updates: - - package-ecosystem: composer - directory: "/" - schedule: - interval: daily - open-pull-requests-limit: 10 From 740b10c5bb18ec34c0da6cbfdda1cdbb44cfd373 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:43:17 -0400 Subject: [PATCH 396/525] Delete Bug Report.yml --- .github/ISSUE_TEMPLATE/Bug Report.yml | 68 --------------------------- 1 file changed, 68 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/Bug Report.yml diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml deleted file mode 100644 index 038592dd..00000000 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: Report a Bug -description: Found a bug or issue? Let us know with a bug report. -labels: [triage] -body: - - type: markdown - attributes: - value: Thanks for taking the time to help us improve this project! - - type: dropdown - id: laravel - attributes: - label: Laravel Version - description: What version of Laravel are you running? - options: - - Laravel 10.x - - Laravel 9.x - - Other (specify in 'additional context') - validations: - required: true - - type: dropdown - id: sdk - attributes: - label: SDK Version - description: What version of our Laravel plugin are you running? (`composer show | grep auth0/login`) - options: - - SDK 7.8 - - SDK 7.7 - - SDK 7.6 - - SDK 7.5 - - SDK 7.4 - - SDK 7.3 - - SDK 7.2 - - SDK 7.1 - - SDK 7.0 - - Other (specify in 'additional context') - validations: - required: true - - type: dropdown - id: php - attributes: - label: PHP Version - description: What version of PHP are you running? (`php -v`) - options: - - PHP 8.3 - - PHP 8.2 - - PHP 8.1 - - PHP 8.0 - - Other (specify in 'additional context') - validations: - required: true - - type: textarea - id: bug-description - attributes: - label: What happened? - description: Also tell us, what did you expect to happen? - validations: - required: true - - type: textarea - id: bug-reproduction - attributes: - label: How can we reproduce this issue? - description: Detail the steps taken to reproduce this error, and whether this can be reproduced consistently or if it is intermittent. - validations: - required: true - - type: textarea - id: context - attributes: - label: Additional context - description: Add any other context about the problem here. From 93b64f488efb902891a4c3cbfc7596169a4dda76 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:43:20 -0400 Subject: [PATCH 397/525] Create bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 86 +++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..6a769dbd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,86 @@ +name: Report a Bug +description: Encountering unexpected problems or unintended behavior? Let us know! + +body: + - type: markdown + attributes: + value: | + **Please do not report security vulnerabilities here**. The [Responsible Disclosure Program](https://auth0.com/responsible-disclosure-policy) details the procedure for disclosing security issues. + + - type: checkboxes + id: checklist + attributes: + label: Checklist + options: + - label: This can be reproduced using [the quickstart sample application](https://github.com/auth0-samples/laravel). + required: true + - label: I have looked at [the README](https://github.com/auth0/laravel-auth0/#readme) and have not found a solution. + required: true + - label: I have looked at [the `docs` directory](https://github.com/auth0/laravel-auth0/blob/main/docs) and have not found a solution. + required: true + - label: I have searched [previous issues](https://github.com/auth0/laravel-auth0/issues) and have not found a solution. + required: true + - label: I have searched [the Auth0 Community](https://community.auth0.com/tag/laravel) and have not found a solution. + required: true + - label: I agree to uphold [the Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). + required: true + + - type: dropdown + id: laravel + attributes: + label: Laravel Version + description: What version of Laravel are you using? (`composer show | grep laravel/framework`) + options: + - 10 + - 9 + - Other (specify below) + validations: + required: true + + - type: dropdown + id: sdk + attributes: + label: SDK Version + description: What version of our SDK are you using? (`composer show | grep auth0/login`) + options: + - 7.8 + - 7.7 + - 7.6 + - 7.5 + - 7.4 + - 7.3 + - 7.2 + - 7.1 + - 7.0 + - Other (specify below) + validations: + required: true + + - type: dropdown + id: php + attributes: + label: PHP Version + description: What version of PHP are you running? (`php -v`) + options: + - PHP 8.2 + - PHP 8.1 + - PHP 8.0 + - Other (specify below) + validations: + required: true + + - type: textarea + id: bug-description + attributes: + label: Description + description: Provide a description of the issue, including what you expected to happen. + validations: + required: true + + - type: textarea + id: bug-reproduction + attributes: + label: How can we reproduce this issue? + description: Detail the steps taken to reproduce this error. If possible, please provide a GitHub repository to demonstrate the issue. + validations: + required: true From b998c6233b0db1537ad2e2a8b0377bbc3d5ef80d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:43:22 -0400 Subject: [PATCH 398/525] Update config.yml --- .github/ISSUE_TEMPLATE/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index b921445c..18c8450a 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -4,7 +4,7 @@ contact_links: url: https://github.com/auth0/auth0-PHP/ about: For issues relating to the Auth0-PHP SDK, please report them in that repository. - name: Community Support - url: https://community.auth0.com/tags/c/sdks/5/laravel + url: https://community.auth0.com/tag/laravel about: Please ask general usage questions here. - name: Responsible Disclosure Program url: https://auth0.com/whitehat From 32d45b6bceca85facbffdf129ddbf78e6999d3a7 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:43:24 -0400 Subject: [PATCH 399/525] Delete Feature Request.yml --- .github/ISSUE_TEMPLATE/Feature Request.yml | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/Feature Request.yml diff --git a/.github/ISSUE_TEMPLATE/Feature Request.yml b/.github/ISSUE_TEMPLATE/Feature Request.yml deleted file mode 100644 index ecf3e049..00000000 --- a/.github/ISSUE_TEMPLATE/Feature Request.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Suggest a Feature -description: Suggest an idea or a feature for this project. -labels: [triage] -body: - - type: markdown - attributes: - value: Thanks for taking the time to help us improve this project! - - type: textarea - id: feature-description - attributes: - label: What should be added? - description: How do you think this feature will improve the developer experience? - validations: - required: true From d3b7f0d65fe8ed37a6b05340fc875e70f4a29e11 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:43:27 -0400 Subject: [PATCH 400/525] Create feature_request.yml --- .github/ISSUE_TEMPLATE/feature_request.yml | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..7bab51f8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,23 @@ +name: Suggest a Feature +description: Help us improve the SDK by suggest new features and improvements. + +body: + - type: markdown + attributes: + value: Thanks for taking the time to help us improve this SDK! + + - type: checkboxes + id: checklist + attributes: + label: Checklist + options: + - label: I agree to uphold [the Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). + required: true + + - type: textarea + id: feature-description + attributes: + label: Description + description: Please provide a summary of the change you'd like considered, including any relevant context. + validations: + required: true From b000d68ffb4286c91ec4f8c7cfab9ceab024cae4 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:43:30 -0400 Subject: [PATCH 401/525] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index fc9f6f7a..8837cb85 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,35 +1,28 @@ ### Changes ### References -Resolves # - ### Testing ### Contributor Checklist -- [ ] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) -- [ ] I have read the [Auth0 code of conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) +- [ ] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) +- [ ] I have read the [Auth0 code of conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) From 90581346088d904ba153cc9b606a829d78f53853 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:44:04 -0400 Subject: [PATCH 402/525] Create SECURITY.md --- .github/SECURITY.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/SECURITY.md diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 00000000..0738ecdf --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,11 @@ +# Security Policy + +**PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, [SEE BELOW](#reporting-a-vulnerability).** + +## Supported Versions + +Please see [our support policy](https://github.com/auth0/laravel-auth0#requirements) for information on supported versions for security releases. + +## Reporting a Vulnerability + +If you discover a security vulnerability within this SDK, please review Auth0's [Responsible Disclosure Program](https://auth0.com/responsible-disclosure-policy) details the procedure for disclosing security issues. All security vulnerabilities will be promptly addressed. From 8f324c021ad6dc01a8481d5d32a72e1222cd3d93 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:44:06 -0400 Subject: [PATCH 403/525] Delete stale.yml --- .github/stale.yml | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index bf9b1cf4..00000000 --- a/.github/stale.yml +++ /dev/null @@ -1,21 +0,0 @@ -# Configuration for probot-stale - https://github.com/probot/stale - -# Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 120 - -# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. -daysUntilClose: 21 - -# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) -onlyLabels: - - 'Waiting for Response' - -# Set to true to ignore issues with an assignee (defaults to false) -exemptAssignees: true - -# Label to use when marking as stale -staleLabel: closed:stale - -# Comment to post when marking as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you have not received a response for our team (apologies for the delay) and this is still a blocker, please reply with additional information or just a ping. Thank you for your contribution! 🙇‍♂️ From d553108dc9eb4257aef478d8bcf0369c73b297b3 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:44:10 -0400 Subject: [PATCH 404/525] Create SUPPORT.md --- .github/SUPPORT.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/SUPPORT.md diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md new file mode 100644 index 00000000..dbd8a8c8 --- /dev/null +++ b/.github/SUPPORT.md @@ -0,0 +1,3 @@ +# Support Questions + +Auth0's GitHub issue trackers are not intended to provide integration support. Instead, please refer your questions to the [Auth0 Community](https://community.auth0.com). From 333825548fc46f8e2d95e46ea3c7f22fb9b08b69 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:44:13 -0400 Subject: [PATCH 405/525] Update composer.json --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f3a3d71b..52b94f51 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,7 @@ "illuminate/contracts": "^9 || ^10", "illuminate/http": "^9 || ^10", "illuminate/support": "^9 || ^10", - "psr-discovery/all": "^1.0", + "psr-discovery/all": "^1", "psr/cache": "^2 || ^3" }, "require-dev": { @@ -56,7 +56,7 @@ "phpstan/phpstan-strict-rules": "^1", "psalm/plugin-laravel": "^2", "psr-mock/http": "^1", - "rector/rector": "*", + "rector/rector": "^0", "spatie/laravel-ray": "^1", "squizlabs/php_codesniffer": "^3", "symfony/cache": "^6", From 037579337162ffa9119ed9413674557baad85c62 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:44:16 -0400 Subject: [PATCH 406/525] Update SessionBridgeAbstract.php --- src/Bridges/SessionBridgeAbstract.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bridges/SessionBridgeAbstract.php b/src/Bridges/SessionBridgeAbstract.php index 7eed63c7..70f69d54 100644 --- a/src/Bridges/SessionBridgeAbstract.php +++ b/src/Bridges/SessionBridgeAbstract.php @@ -65,7 +65,7 @@ final public function getAll(): array $response = []; foreach (array_keys($pairs) as $key) { - if (mb_substr($key, 0, mb_strlen($prefix)) === $prefix) { + if (substr($key, 0, strlen($prefix)) === $prefix) { $response[$key] = $pairs[$key]; } } From ec13c68cc2aa057c7d5bb6a203fc226857126247 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:44:19 -0400 Subject: [PATCH 407/525] Update Configuration.php --- src/Configuration.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Configuration.php b/src/Configuration.php index 6f37ab7c..55113a56 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -325,7 +325,7 @@ public static function getEnvironment(): array } foreach ($contents as $content) { - if (1 !== mb_substr_count($content, '=')) { + if (1 !== substr_count($content, '=')) { continue; } @@ -515,7 +515,7 @@ public static function stringToBoolOrNull(bool | string | null $config, ?bool $d } if (is_string($config) && '' !== $config) { - $config = mb_strtolower(trim($config)); + $config = strtolower(trim($config)); if ('true' === $config) { return true; @@ -547,7 +547,7 @@ private static function getValue( $value = config($override . '.' . $setting); } } else { - $env = 'AUTH0_' . mb_strtoupper(Str::snake($setting)); + $env = 'AUTH0_' . strtoupper(Str::snake($setting)); $json = self::CONFIG_AUDIENCE === $setting ? 'identifier' : Str::snake($setting); $value = self::getEnvironment()[$env] ?? self::getJson()[$json] ?? $default; } From bf6055e1ceb7d5882d40355a0342bcb0888d4e9c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:44:22 -0400 Subject: [PATCH 408/525] Update ServiceProviderAbstract.php --- src/ServiceProviderAbstract.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceProviderAbstract.php b/src/ServiceProviderAbstract.php index fcf9884c..9947a573 100644 --- a/src/ServiceProviderAbstract.php +++ b/src/ServiceProviderAbstract.php @@ -69,7 +69,7 @@ final public function boot( } if (str_starts_with($ability, 'scope:')) { - if ($guard->hasScope(mb_substr($ability, 6))) { + if ($guard->hasScope(substr($ability, 6))) { return Response::allow(); } From ed82884940ce06c1d6924f0204ae7e619ee8c2f3 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:44:37 -0400 Subject: [PATCH 409/525] Update composer.json --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index 52b94f51..e89d6116 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,6 @@ "require": { "php": "^8.0", "ext-json": "*", - "ext-mbstring": "*", "auth0/auth0-php": "^8.6", "illuminate/contracts": "^9 || ^10", "illuminate/http": "^9 || ^10", From 3743200420b7b9afc601eb08839219a36ce9cc8f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:50:21 -0400 Subject: [PATCH 410/525] Update .php-cs-fixer.dist.php --- .php-cs-fixer.dist.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index b37fdaf6..6eca820a 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -82,7 +82,7 @@ 'lowercase_static_reference' => true, 'magic_constant_casing' => true, 'magic_method_casing' => true, - 'mb_str_functions' => true, + 'mb_str_functions' => false, 'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline', 'after_heredoc' => true], 'method_chaining_indentation' => true, 'modernize_strpos' => true, From 78ca97881c9cd33236fbfbef4cb461308aa36e9b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 29 May 2023 23:50:25 -0400 Subject: [PATCH 411/525] Update SessionBridgeAbstract.php --- src/Bridges/SessionBridgeAbstract.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bridges/SessionBridgeAbstract.php b/src/Bridges/SessionBridgeAbstract.php index 70f69d54..84572769 100644 --- a/src/Bridges/SessionBridgeAbstract.php +++ b/src/Bridges/SessionBridgeAbstract.php @@ -65,7 +65,7 @@ final public function getAll(): array $response = []; foreach (array_keys($pairs) as $key) { - if (substr($key, 0, strlen($prefix)) === $prefix) { + if (str_starts_with($key, $prefix)) { $response[$key] = $pairs[$key]; } } From 09696b58162880d3db28e8b18836f871efb9fa68 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 12 Jun 2023 15:15:47 -0500 Subject: [PATCH 412/525] Update sec_semgrep.yml --- .github/workflows/sec_semgrep.yml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/sec_semgrep.yml b/.github/workflows/sec_semgrep.yml index e9be6baf..ca1ee291 100644 --- a/.github/workflows/sec_semgrep.yml +++ b/.github/workflows/sec_semgrep.yml @@ -5,6 +5,9 @@ on: branches: - main + schedule: + - cron: '30 0 1,15 * *' + jobs: semgrep: runs-on: ubuntu-latest @@ -14,16 +17,7 @@ jobs: steps: - uses: actions/checkout@v3 - with: - persist-credentials: false - - run: semgrep scan --sarif --output=semgrep.sarif + - run: semgrep ci env: - SEMGREP_RULES: >- - p/phpcs-security-audit - p/security-audit - p/secrets - p/owasp-top-ten SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} - SEMGREP_REPO_NAME: "auth0/auth0-PHP" - SEMGREP_REPO_URL: "https://github.com/auth0/auth0-PHP" From 992cfbfc8003a348ba83f39357bd48b719e7d044 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 13 Jun 2023 14:11:02 -0500 Subject: [PATCH 413/525] ci: Update Rector ruleset to 0.17 (#406) --- composer.json | 2 +- rector.php | 74 ++++++++++++++------------------------------------- 2 files changed, 21 insertions(+), 55 deletions(-) diff --git a/composer.json b/composer.json index e89d6116..d26e75b0 100644 --- a/composer.json +++ b/composer.json @@ -55,7 +55,7 @@ "phpstan/phpstan-strict-rules": "^1", "psalm/plugin-laravel": "^2", "psr-mock/http": "^1", - "rector/rector": "^0", + "rector/rector": "^0.17", "spatie/laravel-ray": "^1", "squizlabs/php_codesniffer": "^3", "symfony/cache": "^6", diff --git a/rector.php b/rector.php index ef7303bb..bfe928ea 100644 --- a/rector.php +++ b/rector.php @@ -4,11 +4,11 @@ use Rector\Arguments\Rector\ClassMethod\ArgumentAdderRector; use Rector\Arguments\Rector\FuncCall\FunctionArgumentDefaultValueReplacerRector; +use Rector\Arguments\Rector\MethodCall\SwapMethodCallArgumentsRector; use Rector\Arguments\ValueObject\{ArgumentAdder, ReplaceFuncCallArgumentDefaultValue}; use Rector\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector; -use Rector\CodeQuality\Rector\Assign\{CombinedAssignRector, - SplitListAssignToSeparateLineRector}; +use Rector\CodeQuality\Rector\Assign\CombinedAssignRector; use Rector\CodeQuality\Rector\BooleanAnd\SimplifyEmptyArrayCheckRector; use Rector\CodeQuality\Rector\BooleanNot\{ReplaceMultipleBooleanNotRector, SimplifyDeMorganBinaryRector}; @@ -16,7 +16,6 @@ use Rector\CodeQuality\Rector\Class_\{CompleteDynamicPropertiesRector, InlineConstructorDefaultToPropertyRector}; use Rector\CodeQuality\Rector\ClassMethod\{InlineArrayReturnAssignRector, - NarrowUnionTypeDocRector, OptionalParametersAfterRequiredRector, ReturnTypeFromStrictScalarReturnExprRector}; use Rector\CodeQuality\Rector\Concat\JoinStringConcatRector; @@ -24,15 +23,13 @@ use Rector\CodeQuality\Rector\Equal\UseIdenticalOverEqualWithSameTypeRector; use Rector\CodeQuality\Rector\Expression\{InlineIfToExplicitIfRector, TernaryFalseExpressionToIfRector}; -use Rector\CodeQuality\Rector\For_\{ForRepeatedCountToOwnVariableRector, - ForToForeachRector}; +use Rector\CodeQuality\Rector\For_\ForRepeatedCountToOwnVariableRector; use Rector\CodeQuality\Rector\Foreach_\{ForeachItemsAssignToEmptyArrayToAssignRector, ForeachToInArrayRector, SimplifyForeachToArrayFilterRector, SimplifyForeachToCoalescingRector, UnusedForeachValueToArrayKeysRector}; -use Rector\CodeQuality\Rector\FuncCall\{AddPregQuoteDelimiterRector, - ArrayKeysAndInArrayToArrayKeyExistsRector, +use Rector\CodeQuality\Rector\FuncCall\{ArrayKeysAndInArrayToArrayKeyExistsRector, ArrayMergeOfNonArraysToSimpleArrayRector, BoolvalToTypeCastRector, CallUserFuncWithArrowFunctionToInlineRector, @@ -52,7 +49,6 @@ StrvalToTypeCastRector, UnwrapSprintfOneArgumentRector}; use Rector\CodeQuality\Rector\FunctionLike\{RemoveAlwaysTrueConditionSetInConstructorRector, - SimplifyUselessLastVariableAssignRector, SimplifyUselessVariableRector}; use Rector\CodeQuality\Rector\Identical\{BooleanNotIdenticalToNotIdenticalRector, FlipTypeControlToUseExclusiveTypeRector, @@ -66,7 +62,6 @@ ExplicitBoolCompareRector, ShortenElseIfRector, SimplifyIfElseToTernaryRector, - SimplifyIfExactValueReturnValueRector, SimplifyIfNotNullReturnRector, SimplifyIfNullableReturnRector, SimplifyIfReturnBoolRector}; @@ -76,7 +71,7 @@ LogicalToBooleanRector}; use Rector\CodeQuality\Rector\New_\NewStaticToNewSelfRector; use Rector\CodeQuality\Rector\NotEqual\CommonNotEqualRector; -use Rector\CodeQuality\Rector\PropertyFetch\ExplicitMethodCallOverMagicGetSetRector; +use Rector\CodeQuality\Rector\NullsafeMethodCall\CleanupUnneededNullsafeOperatorRector; use Rector\CodeQuality\Rector\Switch_\SingularSwitchToIfRector; use Rector\CodeQuality\Rector\Ternary\{ArrayKeyExistsTernaryThenValueToCoalescingRector, SimplifyTautologyTernaryRector, @@ -88,14 +83,14 @@ use Rector\CodingStyle\Rector\Catch_\CatchExceptionNameMatchingTypeRector; use Rector\CodingStyle\Rector\Class_\AddArrayDefaultToArrayPropertyRector; use Rector\CodingStyle\Rector\ClassConst\{RemoveFinalFromConstRector, SplitGroupedClassConstantsRector, VarConstantCommentRector}; -use Rector\CodingStyle\Rector\ClassMethod\{FuncGetArgsToVariadicParamRector, MakeInheritedMethodVisibilitySameAsParentRector, NewlineBeforeNewAssignSetRector, RemoveDoubleUnderscoreInMethodNameRector, UnSpreadOperatorRector}; +use Rector\CodingStyle\Rector\ClassMethod\{FuncGetArgsToVariadicParamRector, MakeInheritedMethodVisibilitySameAsParentRector, NewlineBeforeNewAssignSetRector, UnSpreadOperatorRector}; use Rector\CodingStyle\Rector\Closure\StaticClosureRector; use Rector\CodingStyle\Rector\Encapsed\{EncapsedStringsToSprintfRector, WrapEncapsedVariableInCurlyBracesRector}; -use Rector\CodingStyle\Rector\FuncCall\{CallUserFuncArrayToVariadicRector, CallUserFuncToMethodCallRector, ConsistentImplodeRector, ConsistentPregDelimiterRector, CountArrayToEmptyArrayComparisonRector, StrictArraySearchRector, VersionCompareFuncCallToConstantRector}; +use Rector\CodingStyle\Rector\FuncCall\{CallUserFuncArrayToVariadicRector, CallUserFuncToMethodCallRector, ConsistentImplodeRector, CountArrayToEmptyArrayComparisonRector, StrictArraySearchRector, VersionCompareFuncCallToConstantRector}; use Rector\CodingStyle\Rector\If_\NullableCompareToNullRector; use Rector\CodingStyle\Rector\Plus\UseIncrementAssignRector; use Rector\CodingStyle\Rector\PostInc\PostIncDecToPreIncDecRector; -use Rector\CodingStyle\Rector\Property\{AddFalseDefaultToBoolPropertyRector, SplitGroupedPropertiesRector}; +use Rector\CodingStyle\Rector\Property\SplitGroupedPropertiesRector; use Rector\CodingStyle\Rector\String_\{SymplifyQuoteEscapeRector, UseClassKeywordForClassNameResolutionRector}; use Rector\CodingStyle\Rector\Switch_\BinarySwitchToIfElseRector; use Rector\CodingStyle\Rector\Ternary\TernaryConditionVariableAssignmentRector; @@ -104,7 +99,6 @@ use Rector\DeadCode\Rector\Array_\RemoveDuplicatedArrayKeyRector; use Rector\DeadCode\Rector\Assign\{RemoveDoubleAssignRector, RemoveUnusedVariableAssignRector}; -use Rector\DeadCode\Rector\BinaryOp\RemoveDuplicatedInstanceOfRector; use Rector\DeadCode\Rector\BooleanAnd\RemoveAndTrueRector; use Rector\DeadCode\Rector\ClassConst\RemoveUnusedPrivateClassConstantRector; use Rector\DeadCode\Rector\ClassMethod\{RemoveDelegatingParentCallRector, @@ -114,7 +108,6 @@ RemoveUnusedPrivateMethodParameterRector, RemoveUnusedPrivateMethodRector, RemoveUnusedPromotedPropertyRector, - RemoveUselessParamTagRector, RemoveUselessReturnTagRector}; use Rector\DeadCode\Rector\Expression\{RemoveDeadStmtRector, SimplifyMirrorAssignRector}; @@ -122,14 +115,10 @@ RemoveDeadIfForeachForRector, RemoveDeadLoopRector}; use Rector\DeadCode\Rector\Foreach_\RemoveUnusedForeachKeyRector; -use Rector\DeadCode\Rector\FunctionLike\{RemoveDeadReturnRector, - RemoveDuplicatedIfReturnRector}; -use Rector\DeadCode\Rector\If_\{RemoveAlwaysTrueIfConditionRector, - RemoveDeadInstanceOfRector, - RemoveUnusedNonEmptyArrayBeforeForeachRector, +use Rector\DeadCode\Rector\FunctionLike\RemoveDeadReturnRector; +use Rector\DeadCode\Rector\If_\{RemoveUnusedNonEmptyArrayBeforeForeachRector, SimplifyIfElseWithSameContentRector, UnwrapFutureCompatibleIfPhpVersionRector}; -use Rector\DeadCode\Rector\MethodCall\RemoveEmptyMethodCallRector; use Rector\DeadCode\Rector\Node\RemoveNonExistingVarAnnotationRector; use Rector\DeadCode\Rector\Plus\RemoveDeadZeroAndOneOperationRector; use Rector\DeadCode\Rector\Property\{RemoveUnusedPrivatePropertyRector, @@ -145,21 +134,18 @@ use Rector\DeadCode\Rector\TryCatch\RemoveDeadTryCatchRector; use Rector\DependencyInjection\Rector\Class_\ActionInjectionToConstructorInjectionRector; use Rector\EarlyReturn\Rector\Foreach_\ChangeNestedForeachIfsToEarlyContinueRector; -use Rector\EarlyReturn\Rector\If_\{ChangeAndIfToEarlyReturnRector, - ChangeIfElseValueAssignToEarlyReturnRector, +use Rector\EarlyReturn\Rector\If_\{ChangeIfElseValueAssignToEarlyReturnRector, ChangeNestedIfsToEarlyReturnRector, ChangeOrIfContinueToMultiContinueRector, - ChangeOrIfReturnToEarlyReturnRector, RemoveAlwaysElseRector}; use Rector\EarlyReturn\Rector\Return_\{PreparedValueToEarlyReturnRector, ReturnBinaryAndToEarlyReturnRector, ReturnBinaryOrToEarlyReturnRector}; use Rector\EarlyReturn\Rector\StmtsAwareInterface\ReturnEarlyIfVariableRector; -use Rector\Naming\Rector\ClassMethod\{RenameParamToMatchTypeRector, - RenameVariableToMatchNewTypeRector}; use Rector\Naming\Rector\Foreach_\{RenameForeachValueVariableToMatchExprVariableRector, RenameForeachValueVariableToMatchMethodCallReturnTypeRector}; use Rector\Php52\Rector\Property\VarToPublicPropertyRector; +use Rector\Php70\Rector\StmtsAwareInterface\IfIssetToCoalescingRector; use Rector\Php71\Rector\FuncCall\RemoveExtraParametersRector; use Rector\Php80\Rector\Catch_\RemoveUnusedVariableInCatchRector; use Rector\Php80\Rector\Class_\{ClassPropertyAssignToConstructorPromotionRector, @@ -169,10 +155,7 @@ FinalPrivateToPrivateVisibilityRector, SetStateToStaticRector}; use Rector\Php80\Rector\FuncCall\{ClassOnObjectRector, - Php8ResourceReturnToObjectRector, - TokenGetAllToObjectRector}; -use Rector\Php80\Rector\FunctionLike\{MixedTypeRector, - UnionTypesRector}; + Php8ResourceReturnToObjectRector}; use Rector\Php80\Rector\Identical\{StrEndsWithRector, StrStartsWithRector}; use Rector\Php80\Rector\NotIdentical\StrContainsRector; @@ -180,11 +163,9 @@ use Rector\Php80\Rector\Ternary\GetDebugTypeRector; use Rector\PHPUnit\Rector\ClassMethod\RemoveEmptyTestMethodRector; use Rector\Privatization\Rector\Class_\{ChangeGlobalVariablesToPropertiesRector, - ChangeReadOnlyVariableWithDefaultValueToConstantRector, FinalizeClassesWithoutChildrenRector}; use Rector\Privatization\Rector\ClassMethod\PrivatizeFinalClassMethodRector; -use Rector\Privatization\Rector\Property\{ChangeReadOnlyPropertyWithDefaultValueToConstantRector, - PrivatizeFinalClassPropertyRector}; +use Rector\Privatization\Rector\Property\PrivatizeFinalClassPropertyRector; use Rector\PSR4\Rector\FileWithoutNamespace\NormalizeNamespaceByPSR4ComposerAutoloadRector; use Rector\PSR4\Rector\Namespace_\MultipleClassFileToPsr4ClassesRector; use Rector\Renaming\Rector\FuncCall\RenameFunctionRector; @@ -196,11 +177,10 @@ ReturnTypeFromStrictTernaryRector}; use Rector\TypeDeclaration\Rector\ClassMethod\{AddMethodCallBasedStrictParamTypeRector, AddParamTypeBasedOnPHPUnitDataProviderRector, - AddParamTypeFromPropertyTypeRector, AddReturnTypeDeclarationBasedOnParentClassMethodRector, AddVoidReturnTypeWhereNoReturnRector, ArrayShapeFromConstantArrayReturnRector, - ParamAnnotationIncorrectNullableRector, + BoolReturnTypeFromStrictScalarReturnsRector, ParamTypeByMethodCallTypeRector, ParamTypeByParentCallTypeRector, ReturnAnnotationIncorrectNullableRector, @@ -330,12 +310,10 @@ AddArrayDefaultToArrayPropertyRector::class, AddArrowFunctionReturnTypeRector::class, AddClosureReturnTypeRector::class, - AddFalseDefaultToBoolPropertyRector::class, AddMethodCallBasedStrictParamTypeRector::class, AddParamBasedOnParentClassMethodRector::class, AddParamTypeBasedOnPHPUnitDataProviderRector::class, AddParamTypeSplFixedArrayRector::class, - AddPregQuoteDelimiterRector::class, AddReturnTypeDeclarationBasedOnParentClassMethodRector::class, AddReturnTypeDeclarationFromYieldsRector::class, AddVoidReturnTypeWhereNoReturnRector::class, @@ -359,8 +337,6 @@ ChangeNestedForeachIfsToEarlyContinueRector::class, ChangeNestedIfsToEarlyReturnRector::class, ChangeOrIfContinueToMultiContinueRector::class, - ChangeReadOnlyPropertyWithDefaultValueToConstantRector::class, - ChangeReadOnlyVariableWithDefaultValueToConstantRector::class, ChangeSwitchToMatchRector::class, ClassOnObjectRector::class, ClassOnThisVariableObjectRector::class, @@ -372,13 +348,11 @@ CompleteDynamicPropertiesRector::class, ConsecutiveNullCompareReturnsToNullCoalesceQueueRector::class, ConsistentImplodeRector::class, - ConsistentPregDelimiterRector::class, CountArrayToEmptyArrayComparisonRector::class, CountArrayToEmptyArrayComparisonRector::class, EmptyOnNullableObjectToInstanceOfRector::class, EncapsedStringsToSprintfRector::class, ExplicitBoolCompareRector::class, - ExplicitMethodCallOverMagicGetSetRector::class, FinalizeClassesWithoutChildrenRector::class, FinalPrivateToPrivateVisibilityRector::class, FlipTypeControlToUseExclusiveTypeRector::class, @@ -386,7 +360,6 @@ ForeachItemsAssignToEmptyArrayToAssignRector::class, ForeachToInArrayRector::class, ForRepeatedCountToOwnVariableRector::class, - ForToForeachRector::class, FuncGetArgsToVariadicParamRector::class, FuncGetArgsToVariadicParamRector::class, GetClassToInstanceOfRector::class, @@ -402,14 +375,12 @@ LogicalToBooleanRector::class, MakeInheritedMethodVisibilitySameAsParentRector::class, MultipleClassFileToPsr4ClassesRector::class, - NarrowUnionTypeDocRector::class, NewlineBeforeNewAssignSetRector::class, NewStaticToNewSelfRector::class, NormalizeNamespaceByPSR4ComposerAutoloadRector::class, NullableCompareToNullRector::class, OptionalParametersAfterRequiredRector::class, OptionalParametersAfterRequiredRector::class, - // ParamAnnotationIncorrectNullableRector::class, ParamTypeByMethodCallTypeRector::class, ParamTypeByParentCallTypeRector::class, ParamTypeFromStrictTypedPropertyRector::class, @@ -432,13 +403,9 @@ RemoveDeadZeroAndOneOperationRector::class, RemoveDelegatingParentCallRector::class, RemoveDoubleAssignRector::class, - RemoveDoubleUnderscoreInMethodNameRector::class, RemoveDuplicatedArrayKeyRector::class, RemoveDuplicatedCaseInSwitchRector::class, - RemoveDuplicatedIfReturnRector::class, - RemoveDuplicatedInstanceOfRector::class, RemoveEmptyClassMethodRector::class, - RemoveEmptyMethodCallRector::class, RemoveEmptyTestMethodRector::class, RemoveExtraParametersRector::class, RemoveFinalFromConstRector::class, @@ -456,9 +423,9 @@ RemoveUnusedNonEmptyArrayBeforeForeachRector::class, RemoveUnusedPrivateClassConstantRector::class, RemoveUnusedPrivateMethodParameterRector::class, - // RemoveUnusedPrivateMethodRector::class, + RemoveUnusedPrivateMethodRector::class, RemoveUnusedPrivatePropertyRector::class, - // RemoveUnusedPromotedPropertyRector::class, + RemoveUnusedPromotedPropertyRector::class, RemoveUnusedVariableAssignRector::class, RemoveUnusedVariableInCatchRector::class, RemoveUselessReturnTagRector::class, @@ -497,7 +464,6 @@ SimplifyFuncGetArgsCountRector::class, SimplifyIfElseToTernaryRector::class, SimplifyIfElseWithSameContentRector::class, - SimplifyIfExactValueReturnValueRector::class, SimplifyIfNotNullReturnRector::class, SimplifyIfNullableReturnRector::class, SimplifyIfReturnBoolRector::class, @@ -506,14 +472,12 @@ SimplifyRegexPatternRector::class, SimplifyStrposLowerRector::class, SimplifyTautologyTernaryRector::class, - SimplifyUselessLastVariableAssignRector::class, SimplifyUselessVariableRector::class, SingleInArrayToCompareRector::class, SingularSwitchToIfRector::class, SplitDoubleAssignRector::class, SplitGroupedClassConstantsRector::class, SplitGroupedPropertiesRector::class, - SplitListAssignToSeparateLineRector::class, StaticArrowFunctionRector::class, StaticClosureRector::class, StrContainsRector::class, @@ -530,7 +494,6 @@ TernaryFalseExpressionToIfRector::class, TernaryToBooleanOrFalseToBooleanAndRector::class, ThrowWithPreviousExceptionRector::class, - TokenGetAllToObjectRector::class, TypedPropertyFromAssignsRector::class, TypedPropertyFromStrictConstructorRector::class, TypedPropertyFromStrictGetterMethodReturnTypeRector::class, @@ -548,5 +511,8 @@ VarToPublicPropertyRector::class, VersionCompareFuncCallToConstantRector::class, WrapEncapsedVariableInCurlyBracesRector::class, + IfIssetToCoalescingRector::class, + CleanupUnneededNullsafeOperatorRector::class, + BoolReturnTypeFromStrictScalarReturnsRector::class, ]); }; From 2d3d1e9ac819b64b412cbb543a44e4fa8448ade2 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 13 Jun 2023 14:20:27 -0500 Subject: [PATCH 414/525] Add `merge_group` event to CI triggers --- .github/workflows/php_composer_normalize.yml | 3 ++- .github/workflows/php_composer_validate.yml | 3 ++- .github/workflows/php_pest.yml | 3 ++- .github/workflows/php_phpcsf.yml | 3 ++- .github/workflows/php_phpstan.yml | 3 ++- .github/workflows/php_psalm.yml | 3 ++- .github/workflows/php_rector.yml | 3 ++- 7 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.github/workflows/php_composer_normalize.yml b/.github/workflows/php_composer_normalize.yml index 95c696c0..64a831d4 100644 --- a/.github/workflows/php_composer_normalize.yml +++ b/.github/workflows/php_composer_normalize.yml @@ -1,7 +1,8 @@ name: "Composer Normalize" on: - pull_request: {} + pull_request: + merge_group: push: branches: - main diff --git a/.github/workflows/php_composer_validate.yml b/.github/workflows/php_composer_validate.yml index 487d814b..28a6e8c6 100644 --- a/.github/workflows/php_composer_validate.yml +++ b/.github/workflows/php_composer_validate.yml @@ -1,7 +1,8 @@ name: "Composer Validate" on: - pull_request: {} + pull_request: + merge_group: push: branches: - main diff --git a/.github/workflows/php_pest.yml b/.github/workflows/php_pest.yml index f7917679..608ba792 100644 --- a/.github/workflows/php_pest.yml +++ b/.github/workflows/php_pest.yml @@ -1,7 +1,8 @@ name: "PEST" on: - pull_request: {} + pull_request: + merge_group: push: branches: - main diff --git a/.github/workflows/php_phpcsf.yml b/.github/workflows/php_phpcsf.yml index dd9bb6c9..bdec72b4 100644 --- a/.github/workflows/php_phpcsf.yml +++ b/.github/workflows/php_phpcsf.yml @@ -1,7 +1,8 @@ name: "PHP CS Fixer" on: - pull_request: {} + pull_request: + merge_group: push: branches: - main diff --git a/.github/workflows/php_phpstan.yml b/.github/workflows/php_phpstan.yml index aac8c128..b6ba2dc6 100644 --- a/.github/workflows/php_phpstan.yml +++ b/.github/workflows/php_phpstan.yml @@ -1,7 +1,8 @@ name: "PHPStan" on: - pull_request: {} + pull_request: + merge_group: push: branches: - main diff --git a/.github/workflows/php_psalm.yml b/.github/workflows/php_psalm.yml index 7e1d0c6b..9e6c2936 100644 --- a/.github/workflows/php_psalm.yml +++ b/.github/workflows/php_psalm.yml @@ -1,7 +1,8 @@ name: "Psalm" on: - pull_request: {} + pull_request: + merge_group: push: branches: - main diff --git a/.github/workflows/php_rector.yml b/.github/workflows/php_rector.yml index fd0851b1..3fe592e4 100644 --- a/.github/workflows/php_rector.yml +++ b/.github/workflows/php_rector.yml @@ -1,7 +1,8 @@ name: "Rector" on: - pull_request: {} + pull_request: + merge_group: push: branches: - main From 41ca3d6eaf5cc81706f18df9ea3a70322deba774 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 13 Jun 2023 15:25:57 -0500 Subject: [PATCH 415/525] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 14b0eebf..81bda445 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . ``` -2. Authenticate with your Auth0 account: +2. Authenticate with your Auth0 account, choosing "as a user" if prompted: ```shell ./auth0 login @@ -121,7 +121,7 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . ``` -2. Authenticate with your Auth0 account: +2. Authenticate with your Auth0 account, choosing "as a user" if prompted: ```shell ./auth0 login From 134ca6b9d7aaadd969816dab8ddc32d1fd655e13 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 13 Jun 2023 17:12:45 -0500 Subject: [PATCH 416/525] [SDK-4337] fix: Trim quote characters from around environment variable strings (#409) --- src/Configuration.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Configuration.php b/src/Configuration.php index 55113a56..e65bcfa1 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -540,6 +540,8 @@ private static function getValue( string $setting, array | bool | string | int | null $default = null, ): array | bool | string | int | null { + $value = null; + if (defined('AUTH0_OVERRIDE_CONFIGURATION')) { $override = constant('AUTH0_OVERRIDE_CONFIGURATION'); @@ -552,6 +554,10 @@ private static function getValue( $value = self::getEnvironment()[$env] ?? self::getJson()[$json] ?? $default; } + if (is_string($value)) { + $value = trim($value, '\'"'); + } + return $value ?? $default; } } From 6275efea7328a76aaa5fd291cf81f55f94c6c0e5 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 13 Jun 2023 17:13:51 -0500 Subject: [PATCH 417/525] [SDK-4337] fix: Restore host environment variable processing (#408) --- src/Configuration.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Configuration.php b/src/Configuration.php index e65bcfa1..6d5d8ae4 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -551,7 +551,11 @@ private static function getValue( } else { $env = 'AUTH0_' . strtoupper(Str::snake($setting)); $json = self::CONFIG_AUDIENCE === $setting ? 'identifier' : Str::snake($setting); - $value = self::getEnvironment()[$env] ?? self::getJson()[$json] ?? $default; + $value = $_ENV[$env] ?? self::getEnvironment()[$env] ?? self::getJson()[$json] ?? $default; + } + + if (! is_string($value) && ! is_array($value) && ! is_bool($value) && ! is_int($value)) { + $value = null; } if (is_string($value)) { From 10e038b28c5717f75e3c77cceecc483e344e6d0f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 13 Jun 2023 17:19:13 -0500 Subject: [PATCH 418/525] [SDK-4337] feat: Add setting to define search path for configuration files (#407) --- config/auth0.php | 1 + src/Configuration.php | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/config/auth0.php b/config/auth0.php index 02010290..7a5664f6 100644 --- a/config/auth0.php +++ b/config/auth0.php @@ -9,6 +9,7 @@ 'registerGuards' => true, 'registerMiddleware' => true, 'registerAuthenticationRoutes' => true, + 'configurationPath' => null, 'guards' => [ 'default' => [ diff --git a/src/Configuration.php b/src/Configuration.php index 6d5d8ae4..b1cf026d 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -412,7 +412,13 @@ public static function getJson(): array public static function getPath(): string { if (null === self::$path) { - self::$path = base_path() . DIRECTORY_SEPARATOR; + $path = config('auth0.configurationPath'); + + if (! is_string($path)) { + $path = base_path() . DIRECTORY_SEPARATOR; + } + + self::$path = $path; } return self::$path; From 96473014a00aaf30639a1acba1c517d75725ca76 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 13 Jun 2023 17:20:52 -0500 Subject: [PATCH 419/525] [SDK-4338] feat: `GuardAbstract` extends `Illuminate\Contracts\Auth\Guard` (#410) Co-authored-by: Rita Zerrizuela --- src/Guards/GuardAbstract.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Guards/GuardAbstract.php b/src/Guards/GuardAbstract.php index 09f53ef1..7e2b30db 100644 --- a/src/Guards/GuardAbstract.php +++ b/src/Guards/GuardAbstract.php @@ -12,7 +12,7 @@ use Auth0\SDK\Exception\InvalidTokenException; use Auth0\SDK\Token; use Exception; -use Illuminate\Contracts\Auth\{Authenticatable, UserProvider}; +use Illuminate\Contracts\Auth\{Authenticatable, Guard, UserProvider}; use Illuminate\Contracts\Session\Session; use Illuminate\Contracts\Support\{Arrayable, Jsonable}; use JsonSerializable; @@ -27,7 +27,7 @@ * * @api */ -abstract class GuardAbstract +abstract class GuardAbstract implements Guard { protected ?CredentialEntityContract $credential = null; From e33686e1b19bef36a2483b9423c760b0f3248552 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 15 Jun 2023 11:59:22 -0500 Subject: [PATCH 420/525] Temporarily lock Rector to 0.17.0 to avoid upstream breaks. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d26e75b0..23b441ab 100644 --- a/composer.json +++ b/composer.json @@ -55,7 +55,7 @@ "phpstan/phpstan-strict-rules": "^1", "psalm/plugin-laravel": "^2", "psr-mock/http": "^1", - "rector/rector": "^0.17", + "rector/rector": "0.17.0", "spatie/laravel-ray": "^1", "squizlabs/php_codesniffer": "^3", "symfony/cache": "^6", From e556649ebccfec306f20c0862e0c1ded57dc9a97 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 16 Jun 2023 04:12:46 -0500 Subject: [PATCH 421/525] Release 7.9.0 (#411) --- CHANGELOG.md | 14 +++++++++++++- src/ServiceAbstract.php | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ffa934d..32752a35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,22 @@ # Changelog +## [7.9.0](https://github.com/auth0/laravel-auth0/tree/7.8.2) (2023-06-15) + +### Added + +- SDK configuration (`config/auth0.php`) now supports a `configurationPath` property for specifying a custom search path for `.auth0.*.json` and `.env*` files. ([\#407](https://github.com/auth0/laravel-auth0/pull/407)) +- `Auth0\Laravel\Guards\GuardAbstract` now extends `Illuminate\Contracts\Auth\Guard`. ([\#410](https://github.com/auth0/laravel-auth0/pull/410)) + +### Fixed + +- Resolved host environment variables not being loaded as expected when a `.env` file is also used. ([\#408](https://github.com/auth0/laravel-auth0/pull/408)) +- Resolved surrounding quote characters not being trimmed from environment variables and `.env` files during processing. ([\#409](https://github.com/auth0/laravel-auth0/pull/409)) + ## [7.8.1](https://github.com/auth0/laravel-auth0/tree/7.8.1) (2023-05-19) ### Fixed -- Resolved an issue where parsing `.env` files could sometimes throw an exception when handling non-key-value pair strings. ([\#395](https://github.com/auth0/laravel-auth0/pull/395)) +- Resolved an issue where parsing `.env` files could sometimes throw an exception when handling non-key-value pair strings. ([\#395](https://github.com/auth0/laravel-auth0/pull/395)) ## [7.8.0](https://github.com/auth0/laravel-auth0/tree/7.8.0) (2023-05-18) diff --git a/src/ServiceAbstract.php b/src/ServiceAbstract.php index 88b93ce5..46de0dce 100644 --- a/src/ServiceAbstract.php +++ b/src/ServiceAbstract.php @@ -22,7 +22,7 @@ abstract class ServiceAbstract extends InstanceEntityAbstract * * @var string */ - public const VERSION = '7.8.1'; + public const VERSION = '7.9.0'; /** * Decode a PSR-7 HTTP Response Message containing a JSON content body to a PHP array. Returns null if the response was not successful, or the response body was not JSON. From eaebb396bc2bac1a0cd5971ee033ac1dbd5969dc Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 21 Jun 2023 13:03:55 -0500 Subject: [PATCH 422/525] fix: Remove redundant middleware insertion (#415) --- src/Middleware/GuardMiddleware.php | 2 -- src/ServiceProviderAbstract.php | 6 ------ 2 files changed, 8 deletions(-) diff --git a/src/Middleware/GuardMiddleware.php b/src/Middleware/GuardMiddleware.php index 6cc96e70..d5f8be60 100644 --- a/src/Middleware/GuardMiddleware.php +++ b/src/Middleware/GuardMiddleware.php @@ -4,8 +4,6 @@ namespace Auth0\Laravel\Middleware; -use Illuminate\Http\Request; - /** * Assigns a specific guard to the request. * diff --git a/src/ServiceProviderAbstract.php b/src/ServiceProviderAbstract.php index 9947a573..3d444f43 100644 --- a/src/ServiceProviderAbstract.php +++ b/src/ServiceProviderAbstract.php @@ -19,7 +19,6 @@ use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; -use function defined; use function is_string; /** @@ -208,11 +207,6 @@ final public function registerMiddleware( /** * @var \Illuminate\Foundation\Http\Kernel $kernel */ - if (! defined('AUTH0_LARAVEL_RUNNING_TESTS')) { - $kernel->pushMiddleware(AuthenticatorMiddleware::class); - $kernel->pushMiddleware(AuthenticatorMiddleware::class); - } - $kernel->appendMiddlewareToGroup('web', AuthenticatorMiddleware::class); $kernel->appendMiddlewareToGroup('api', AuthorizerMiddleware::class); From 5e3fc3f62bc1784a57c4d565125380416a36dafc Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 21 Jun 2023 14:46:21 -0500 Subject: [PATCH 423/525] Release 7.9.1 --- CHANGELOG.md | 8 +++++++- src/ServiceAbstract.php | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32752a35..22bf9ca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog -## [7.9.0](https://github.com/auth0/laravel-auth0/tree/7.8.2) (2023-06-15) +## [7.9.1](https://github.com/auth0/laravel-auth0/tree/7.9.1) (2023-06-21) + +### Fixed + +- Resolved an issue where, under certain circumstances, the AuthenticationGuard middleware could get erroneously added to the `api` middleware group, causing a session to be established in a stateless request. ([\#415](https://github.com/auth0/laravel-auth0/pull/415)) + +## [7.9.0](https://github.com/auth0/laravel-auth0/tree/7.9.0) (2023-06-15) ### Added diff --git a/src/ServiceAbstract.php b/src/ServiceAbstract.php index 46de0dce..9be17d70 100644 --- a/src/ServiceAbstract.php +++ b/src/ServiceAbstract.php @@ -22,7 +22,7 @@ abstract class ServiceAbstract extends InstanceEntityAbstract * * @var string */ - public const VERSION = '7.9.0'; + public const VERSION = '7.9.1'; /** * Decode a PSR-7 HTTP Response Message containing a JSON content body to a PHP array. Returns null if the response was not successful, or the response body was not JSON. From b25f692cd51bc9efcfb86a54d463bbbbfe0f6961 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 26 Jun 2023 01:39:58 -0500 Subject: [PATCH 424/525] Update GH workflows --- .../{sec_semgrep.yml => cron_semgrep.yml} | 13 ++++--- .../workflows/{sec_snyk.yml => cron_snyk.yml} | 14 ++++---- .github/workflows/php_composer_normalize.yml | 21 ------------ .github/workflows/php_composer_validate.yml | 21 ------------ .github/workflows/pr_await_changes.yml | 17 ++++++++++ .github/workflows/pr_composer.yml | 32 +++++++++++++++++ .../workflows/{php_pest.yml => pr_pest.yml} | 6 ++-- .../{php_phpcsf.yml => pr_phpcsf.yml} | 6 ++-- .../{php_phpstan.yml => pr_phpstan.yml} | 6 ++-- .../workflows/{php_psalm.yml => pr_psalm.yml} | 6 ++-- .../{php_rector.yml => pr_rector.yml} | 6 ++-- .github/workflows/pr_semgrep.yml | 32 +++++++++++++++++ .github/workflows/pr_snyk.yml | 34 +++++++++++++++++++ 13 files changed, 140 insertions(+), 74 deletions(-) rename .github/workflows/{sec_semgrep.yml => cron_semgrep.yml} (56%) rename .github/workflows/{sec_snyk.yml => cron_snyk.yml} (73%) delete mode 100644 .github/workflows/php_composer_normalize.yml delete mode 100644 .github/workflows/php_composer_validate.yml create mode 100644 .github/workflows/pr_await_changes.yml create mode 100644 .github/workflows/pr_composer.yml rename .github/workflows/{php_pest.yml => pr_pest.yml} (87%) rename .github/workflows/{php_phpcsf.yml => pr_phpcsf.yml} (82%) rename .github/workflows/{php_phpstan.yml => pr_phpstan.yml} (82%) rename .github/workflows/{php_psalm.yml => pr_psalm.yml} (80%) rename .github/workflows/{php_rector.yml => pr_rector.yml} (81%) create mode 100644 .github/workflows/pr_semgrep.yml create mode 100644 .github/workflows/pr_snyk.yml diff --git a/.github/workflows/sec_semgrep.yml b/.github/workflows/cron_semgrep.yml similarity index 56% rename from .github/workflows/sec_semgrep.yml rename to .github/workflows/cron_semgrep.yml index ca1ee291..e448560f 100644 --- a/.github/workflows/sec_semgrep.yml +++ b/.github/workflows/cron_semgrep.yml @@ -1,15 +1,18 @@ -name: "Semgrep" +name: "Semgrep (Scheduled)" + +# This workflow will run after a push to the main branch and as a scheduled job. on: push: - branches: - - main - + branches: ["master", "main"] schedule: - - cron: '30 0 1,15 * *' + - cron: "30 0 1,15 * *" + +permissions: {} jobs: semgrep: + name: "Scan" runs-on: ubuntu-latest container: diff --git a/.github/workflows/sec_snyk.yml b/.github/workflows/cron_snyk.yml similarity index 73% rename from .github/workflows/sec_snyk.yml rename to .github/workflows/cron_snyk.yml index 9a9fa1b4..fdf3f658 100644 --- a/.github/workflows/sec_snyk.yml +++ b/.github/workflows/cron_snyk.yml @@ -1,12 +1,16 @@ -name: "Snyk" +name: "Snyk (Scheduled)" + +# This workflow will run after a push to the main branch and as a scheduled job. on: push: - branches: - - main + branches: ["master", "main"] + +permissions: {} jobs: snyk: + name: "Scan" runs-on: ubuntu-latest steps: @@ -19,8 +23,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: actions/checkout@v3 - with: - persist-credentials: false - run: composer install --no-progress @@ -28,5 +30,3 @@ jobs: continue-on-error: true env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} - with: - args: --severity-threshold=high --sarif-file-output=snyk.sarif diff --git a/.github/workflows/php_composer_normalize.yml b/.github/workflows/php_composer_normalize.yml deleted file mode 100644 index 64a831d4..00000000 --- a/.github/workflows/php_composer_normalize.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: "Composer Normalize" - -on: - pull_request: - merge_group: - push: - branches: - - main - -permissions: {} - -jobs: - normalize: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - with: - persist-credentials: false - - - uses: docker://ergebnis/composer-normalize-action diff --git a/.github/workflows/php_composer_validate.yml b/.github/workflows/php_composer_validate.yml deleted file mode 100644 index 28a6e8c6..00000000 --- a/.github/workflows/php_composer_validate.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: "Composer Validate" - -on: - pull_request: - merge_group: - push: - branches: - - main - -permissions: {} - -jobs: - validate: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - with: - persist-credentials: false - - - run: composer validate diff --git a/.github/workflows/pr_await_changes.yml b/.github/workflows/pr_await_changes.yml new file mode 100644 index 00000000..4c650b23 --- /dev/null +++ b/.github/workflows/pr_await_changes.yml @@ -0,0 +1,17 @@ +name: "Pull Request Changes" + +# Monitor for changes to pull requests. + +on: + pull_request: + types: [opened, synchronize, reopened, closed] + +permissions: {} + +jobs: + wait: + name: "Watching" + runs-on: ubuntu-latest + + steps: + - run: echo "Child workflows triggered." diff --git a/.github/workflows/pr_composer.yml b/.github/workflows/pr_composer.yml new file mode 100644 index 00000000..d24abb7c --- /dev/null +++ b/.github/workflows/pr_composer.yml @@ -0,0 +1,32 @@ +name: "Composer" + +on: + pull_request: + merge_group: + push: + branches: ["master", "main"] + +permissions: {} + +jobs: + validate: + name: "Validate" + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - run: composer validate + + normalize: + name: "Normalize" + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - run: composer require --dev ergebnis/composer-normalize + + - run: composer config allow-plugins.ergebnis/composer-normalize true + + - run: composer normalize diff --git a/.github/workflows/php_pest.yml b/.github/workflows/pr_pest.yml similarity index 87% rename from .github/workflows/php_pest.yml rename to .github/workflows/pr_pest.yml index 608ba792..f76d1ce8 100644 --- a/.github/workflows/php_pest.yml +++ b/.github/workflows/pr_pest.yml @@ -4,19 +4,17 @@ on: pull_request: merge_group: push: - branches: - - main + branches: ["master", "main"] permissions: {} jobs: pest: + name: "Scan" runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - with: - persist-credentials: false - uses: shivammathur/setup-php@v2 with: diff --git a/.github/workflows/php_phpcsf.yml b/.github/workflows/pr_phpcsf.yml similarity index 82% rename from .github/workflows/php_phpcsf.yml rename to .github/workflows/pr_phpcsf.yml index bdec72b4..753cce81 100644 --- a/.github/workflows/php_phpcsf.yml +++ b/.github/workflows/pr_phpcsf.yml @@ -4,19 +4,17 @@ on: pull_request: merge_group: push: - branches: - - main + branches: ["master", "main"] permissions: {} jobs: phpcsf: + name: "Scan" runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - with: - persist-credentials: false - uses: shivammathur/setup-php@v2 with: diff --git a/.github/workflows/php_phpstan.yml b/.github/workflows/pr_phpstan.yml similarity index 82% rename from .github/workflows/php_phpstan.yml rename to .github/workflows/pr_phpstan.yml index b6ba2dc6..75f17b89 100644 --- a/.github/workflows/php_phpstan.yml +++ b/.github/workflows/pr_phpstan.yml @@ -4,19 +4,17 @@ on: pull_request: merge_group: push: - branches: - - main + branches: ["master", "main"] permissions: {} jobs: phpstan: + name: "Scan" runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - with: - persist-credentials: false - uses: shivammathur/setup-php@v2 with: diff --git a/.github/workflows/php_psalm.yml b/.github/workflows/pr_psalm.yml similarity index 80% rename from .github/workflows/php_psalm.yml rename to .github/workflows/pr_psalm.yml index 9e6c2936..46689b13 100644 --- a/.github/workflows/php_psalm.yml +++ b/.github/workflows/pr_psalm.yml @@ -4,19 +4,17 @@ on: pull_request: merge_group: push: - branches: - - main + branches: ["master", "main"] permissions: {} jobs: psalm: + name: "Scan" runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - with: - persist-credentials: false - uses: shivammathur/setup-php@v2 with: diff --git a/.github/workflows/php_rector.yml b/.github/workflows/pr_rector.yml similarity index 81% rename from .github/workflows/php_rector.yml rename to .github/workflows/pr_rector.yml index 3fe592e4..594ca491 100644 --- a/.github/workflows/php_rector.yml +++ b/.github/workflows/pr_rector.yml @@ -4,19 +4,17 @@ on: pull_request: merge_group: push: - branches: - - main + branches: ["master", "main"] permissions: {} jobs: rector: + name: "Scan" runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - with: - persist-credentials: false - uses: shivammathur/setup-php@v2 with: diff --git a/.github/workflows/pr_semgrep.yml b/.github/workflows/pr_semgrep.yml new file mode 100644 index 00000000..188b459b --- /dev/null +++ b/.github/workflows/pr_semgrep.yml @@ -0,0 +1,32 @@ +name: "Semgrep" + +on: + workflow_run: + workflows: ["Pull Request Vetted"] + types: + - completed + +permissions: {} + +jobs: + wait: + name: "Scan" + runs-on: ubuntu-latest + + if: contains(github.event.issue.labels.*.name, 'State: Vetted') + + semgrep: + runs-on: ubuntu-latest + + container: + image: returntocorp/semgrep + + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - run: semgrep ci + env: + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} diff --git a/.github/workflows/pr_snyk.yml b/.github/workflows/pr_snyk.yml new file mode 100644 index 00000000..ce7ce115 --- /dev/null +++ b/.github/workflows/pr_snyk.yml @@ -0,0 +1,34 @@ +name: "Snyk" + +on: + workflow_run: + workflows: ["Pull Request Vetted"] + types: + - completed + +permissions: {} + +jobs: + snyk: + name: "Scan" + runs-on: ubuntu-latest + + if: contains(github.event.issue.labels.*.name, 'State: Vetted') + + steps: + - uses: shivammathur/setup-php@v2 + with: + php-version: "8.1" + coverage: none + extensions: mbstring + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/checkout@v3 + + - run: composer install --no-progress + + - uses: snyk/actions/php@master + continue-on-error: true + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} From ec9a0cd066c1ead15c540a008ff621bd931b4c84 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 26 Jun 2023 01:40:47 -0500 Subject: [PATCH 425/525] Update pr_snyk.yml --- .github/workflows/pr_snyk.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/pr_snyk.yml b/.github/workflows/pr_snyk.yml index ce7ce115..8bc0d4c6 100644 --- a/.github/workflows/pr_snyk.yml +++ b/.github/workflows/pr_snyk.yml @@ -2,7 +2,7 @@ name: "Snyk" on: workflow_run: - workflows: ["Pull Request Vetted"] + workflows: ["Pull Request Changes"] types: - completed @@ -13,8 +13,6 @@ jobs: name: "Scan" runs-on: ubuntu-latest - if: contains(github.event.issue.labels.*.name, 'State: Vetted') - steps: - uses: shivammathur/setup-php@v2 with: From ca82325dee0734a2650d6aa6faa7ba94a3e76af9 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 26 Jun 2023 01:40:49 -0500 Subject: [PATCH 426/525] Update pr_semgrep.yml --- .github/workflows/pr_semgrep.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/pr_semgrep.yml b/.github/workflows/pr_semgrep.yml index 188b459b..70e5b5b1 100644 --- a/.github/workflows/pr_semgrep.yml +++ b/.github/workflows/pr_semgrep.yml @@ -2,7 +2,7 @@ name: "Semgrep" on: workflow_run: - workflows: ["Pull Request Vetted"] + workflows: ["Pull Request Changes"] types: - completed @@ -13,8 +13,6 @@ jobs: name: "Scan" runs-on: ubuntu-latest - if: contains(github.event.issue.labels.*.name, 'State: Vetted') - semgrep: runs-on: ubuntu-latest From e574e72fd6328201330ec1f439e0b30597f01d64 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 26 Jun 2023 01:42:14 -0500 Subject: [PATCH 427/525] Update pr_semgrep.yml --- .github/workflows/pr_semgrep.yml | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/.github/workflows/pr_semgrep.yml b/.github/workflows/pr_semgrep.yml index 70e5b5b1..e8949f5b 100644 --- a/.github/workflows/pr_semgrep.yml +++ b/.github/workflows/pr_semgrep.yml @@ -13,18 +13,15 @@ jobs: name: "Scan" runs-on: ubuntu-latest - semgrep: - runs-on: ubuntu-latest + container: + image: returntocorp/semgrep - container: - image: returntocorp/semgrep + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + github-token: ${{ secrets.GITHUB_TOKEN }} - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.sha }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - - run: semgrep ci - env: - SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} + - run: semgrep ci + env: + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} From 0a552f5fb8a9b582c0017c692fa13f441af1f892 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 26 Jun 2023 01:42:19 -0500 Subject: [PATCH 428/525] Update pr_snyk.yml --- .github/workflows/pr_snyk.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/pr_snyk.yml b/.github/workflows/pr_snyk.yml index 8bc0d4c6..74852bdf 100644 --- a/.github/workflows/pr_snyk.yml +++ b/.github/workflows/pr_snyk.yml @@ -23,6 +23,9 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + github-token: ${{ secrets.GITHUB_TOKEN }} - run: composer install --no-progress From 3ad82377d4577a229ddefe2ffb9704384a88d3d7 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 16:58:19 -0500 Subject: [PATCH 429/525] Documentation updates --- README.md | 235 ++++++++++++++++++++---------------------- docs/Configuration.md | 216 ++++++++++++++++++++++++++++++++++---- docs/Events.md | 39 ++++--- docs/Installation.md | 195 ++++++++++++++++++++++++++++++++--- docs/Management.md | 10 +- docs/Support.md | 24 +++++ 6 files changed, 540 insertions(+), 179 deletions(-) create mode 100644 docs/Support.md diff --git a/README.md b/README.md index 81bda445..5ae1c82c 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,29 @@ -![laravel-auth0](https://cdn.auth0.com/website/sdks/banners/laravel-auth0-banner.png) - -

-Build Status -Code Coverage -Total Downloads -License -

+![Auth0 Laravel SDK](https://cdn.auth0.com/website/sdks/banners/laravel-auth0-banner.png) + +
+ +
+ +- [Requirements](#requirements) +- [Getting Started](#getting-started) + - [1. Install the SDK](#1-install-the-sdk) + - [2. Install the CLI](#2-install-the-cli) + - [3. Configure the SDK](#3-configure-the-sdk) +- [Documentation](#documentation) +- [QuickStarts](#quickstarts) +- [Contributing](#contributing) +- [Code of Conduct](#code-of-conduct) +- [Security](#security) +- [License](#license) ## Requirements -Your application must use a [supported Laravel version](https://laravelversions.com/en), and your environment must run a [supported PHP version](https://www.php.net/supported-versions.php). We do not support versions of Laravel or PHP that are no longer supported by their maintainers. +Your application must use a [supported Laravel version](https://laravelversions.com/en), and your environment must run a [supported PHP version](https://www.php.net/supported-versions.php). | SDK | Laravel | PHP | Supported Until | | ---- | ------- | ---- | --------------- | @@ -19,34 +33,29 @@ Your application must use a [supported Laravel version](https://laravelversions. | | | 8.1+ | Feb 2024 | | | | 8.0+ | Nov 2023 | +Please review [our support policy](./docs/Support.md) for more information. + You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). -## Installation +## Getting Started -
+The following is our recommended approach to getting started with the SDK. Alternatives are available in [our expanded installation guide](./docs/Installation.md). -Using Quickstart (Fastest) +### 1. Install the SDK -- Run the following command to create a new Laravel 9 project pre-configured with the SDK: +- For new applications, run the following command to create a new Laravel 9 project pre-configured with the SDK: ```shell - composer create-project auth0-samples/laravel auth0-laravel-app + composer create-project auth0-samples/laravel auth0-laravel-app && cd auth0-laravel-app ``` ---- - -
- -
-Using Composer - -1. Run the following command in your project directory to install the SDK: +- For existing applications, you can install the SDK using Composer: ```shell - composer require auth0/login:^7.8 --update-with-all-dependencies + composer require auth0/login:^7.9 --update-with-all-dependencies ``` -2. Generate an SDK configuration file for your application: + In this case, you will also need to generate an SDK configuration file for your application: ```shell php artisan vendor:publish --tag auth0 @@ -54,30 +63,46 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h
-## Configuration +### 2. Install the CLI -
-Using JSON (Fastest) +1. Install the [Auth0 CLI](https://github.com/auth0/auth0-cli) to manage your account from the command line: -1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your project directory: + ```shell + curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . + sudo mv ./auth0 /usr/local/bin + ``` - > **Note** - > If you are using the Quickstart, skip to the next step. +
+ Using Homebrew (macOS) +   ```shell - curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . + brew tap auth0/auth0-cli && brew install auth0 ``` +
-2. Authenticate with your Auth0 account, choosing "as a user" if prompted: +
+ Using Scoop (Windows) +   + + ```cmd + scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git + scoop install auth0 + ``` +
+ +2. Run the following command to authenticate the CLI with your Auth0 account. Choose "as a user," and follow the prompts. ```shell - ./auth0 login + auth0 login ``` -3. Register a new application with Auth0: +### 3. Configure the SDK + +1. Register a new application with Auth0: ```shell - ./auth0 apps create \ + auth0 apps create \ --name "My Laravel Application" \ --type "regular" \ --auth-method "post" \ @@ -88,10 +113,10 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h --json > .auth0.app.json ``` -4. Register a new API with Auth0: +2. Register a new API with Auth0: ```shell - ./auth0 apis create \ + auth0 apis create \ --name "My Laravel Application API" \ --identifier "https://github.com/auth0/laravel-auth0" \ --offline-access \ @@ -99,91 +124,37 @@ You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](h --json > .auth0.api.json ``` -5. Add the new files to `.gitignore`: +3. Add the new files to `.gitignore`: ```bash echo ".auth0.*.json" >> .gitignore ``` ---- - -
- -
-Using Environment Variables - -1. Download the [Auth0 CLI](https://github.com/auth0/auth0-cli) to your project directory: - - > **Note** - > If you are using the Quickstart, skip to the next step. - - ```shell - curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . - ``` - -2. Authenticate with your Auth0 account, choosing "as a user" if prompted: - - ```shell - ./auth0 login - ``` - -3. Register a new application with Auth0: +
+ Using Windows PowerShell +   - ```shell - ./auth0 apps create \ - --name "My Laravel Application" \ - --type "regular" \ - --auth-method "post" \ - --callbacks "http://localhost:8000/callback" \ - --logout-urls "http://localhost:8000/" \ - --reveal-secrets \ - --no-input + ```powershell + Add-Content .gitignore "`n.auth0.*.json" ``` +
- Make a note of the `client_id` and `client_secret` values in the output. +
+ Using Windows Command Prompt +   -4. Register a new API with Auth0: - - ```shell - ./auth0 apis create \ - --name "My Laravel Application API" \ - --identifier "https://github.com/auth0/laravel-auth0" \ - --offline-access \ - --no-input + ```cmd + echo .auth0.*.json >> .gitignore ``` +
-5. Open the `.env` file in your project directory. Add the following lines, replacing the values with the ones you noted in the previous steps: - - ```ini - # The Auth0 domain for your tenant (e.g. tenant.region.auth0.com): - AUTH0_DOMAIN=... - - # The application `client_id` you noted above: - AUTH0_CLIENT_ID=... - - # The application `client_secret` you noted above: - AUTH0_CLIENT_SECRET=... - - # The API `identifier` you used above: - AUTH0_AUDIENCE=... - ``` - - Additional variables are available. More on those in the [configuration guide](./docs/Configuration.md#environment-variables). - -
- -## Quickstarts - -- [Session-based Authentication](https://auth0.com/docs/quickstart/webapp/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) -- [Token-based Authorization](https://auth0.com/docs/quickstart/backend/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) - -## Examples +## Integration Examples
-Authentication +User Authentication   -The SDK automatically registers all the necessary authentication services within the `web` middleware group for your application. Once you have [configured the SDK](#configuration) your users will be able to authenticate with your application using Auth0. +The SDK automatically registers all the necessary authentication services within the `web` middleware group for your application. Once you have [configured the SDK](./docs/Management.md#api-application-authorization) your users will be able to authenticate with your application using Auth0. The SDK automatically registers the following routes to facilitate authentication: @@ -201,12 +172,12 @@ The SDK automatically registers the following routes to facilitate authenticatio
-Access Control +Route Authorization (Access Control)   -The SDK automatically registers its authentication and authorization guards within the `web` and `api` middleware groups for your Laravel application. +The SDK automatically registers its authentication and authorization guards within the `web` and `api` middleware groups for your Laravel application, respectively. -To require a user to be authenticated to access a route, use Laravel's `auth` middleware: +For `web` routes, you can use Laravel's `auth` middleware to require that a user be authenticated to access a route: ```php Route::get('/private', function () { @@ -214,11 +185,19 @@ Route::get('/private', function () { })->middleware('auth'); ``` -You can also require that the user have specific permissions to access a route, using Laravel's `can` middleware: +For `api` routes, you can use Laravel's `auth` middleware to require that a request be authenticated with a valid bearer token to access a route: + +```php +Route::get('/api/private', function () { + return response()->json(['message' => 'Hello! You included a valid token with your request.']); +})->middleware('auth'); +``` + +In addition to requiring that a user be authenticated, you can also require that the user have specific permissions to access a route, using Laravel's `can` middleware: ```php Route::get('/scope', function () { - return response('You have the `read:messages` permissions, and can therefore access this resource.'); + return response('You have the `read:messages` permission, and can therefore access this resource.'); })->middleware('auth')->can('read:messages'); ``` @@ -274,15 +253,14 @@ Route::get('/', function () {
-Management API +Management API Calls   -You can issue [Auth0 Management API](https://auth0.com/docs/api/management/v2) calls through the SDK's `management()` method. +Once you've [authorized your application to make Management API calls](./docs/Management.md#api-application-authorization), you'll be able to engage nearly any of the [Auth0 Management API endpoints](https://auth0.com/docs/api/management/v2) using the SDK. -> **Note** -> Before your application can make calls to the Management API, you must [enable your application to communicate with the Management API](./docs/Management.md#management-api-permissions) or configure the SDK with [a management token](./docs/Configuration.md#management-token). +Each endpoint has its own Management API class, all of which can be accessed through the Facade's `management()` method. -For example, you can update a user's metadata by calling the `management()->users()->update()` method: +For example, to update a user's metadata, you can call the `management()->users()->update()` method: ```php use Auth0\Laravel\Facade\Auth0; @@ -324,21 +302,26 @@ All the SDK's Management API methods are [documented here](./docs/Management.md) ## Documentation -- [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. -- [Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. -- [Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2). -- [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent). -- [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. -- [Octane](./docs/Octane.md) — We do not support using the SDK with [Octane](https://laravel.com/docs/octane) at this time. +- [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. +- [Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. +- [Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2). +- [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent). +- [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. +- [Octane](./docs/Octane.md) — We do not support using the SDK with [Octane](https://laravel.com/docs/octane) at this time. You may also find the following resources helpful: -- [Auth0 Documentation Hub](https://www.auth0.com/docs) -- [Auth0 Management API Explorer](https://auth0.com/docs/api/management/v2) -- [Auth0 Authentication API Explorer](https://auth0.com/docs/api/authentication) +- [Auth0 Documentation Hub](https://www.auth0.com/docs) +- [Auth0 Management API Explorer](https://auth0.com/docs/api/management/v2) +- [Auth0 Authentication API Explorer](https://auth0.com/docs/api/authentication) Contributions to improve our documentation [are welcomed](https://github.com/auth0/laravel-auth0/pull). +## QuickStarts + +- [Session-based Authentication](https://auth0.com/docs/quickstart/webapp/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) +- [Token-based Authorization](https://auth0.com/docs/quickstart/backend/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) + ## Community The [Auth0 Community](https://community.auth0.com) is where you can get support, ask questions, and share your projects. diff --git a/docs/Configuration.md b/docs/Configuration.md index af34589a..f9ea06ae 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -1,28 +1,55 @@ # Configuration -> **Note:** -> This is an addendum to the [README](../README.md) file. Please review that guidance first. +- [SDK Configuration](#sdk-configuration) + - [JSON Configuration Files](#json-configuration-files) + - [Environment Variables](#environment-variables) + - [Order of Priority](#order-of-priority) + - [Default Behavior](#default-behavior) + - [Guard Registration](#guard-registration) + - [Middleware Registration](#middleware-registration) + - [Route Registration](#route-registration) +- [Auth0 Configuration](#auth0-configuration) + - [Auth0 Applications](#auth0-applications) + - [Creating Applications with the CLI](#creating-applications-with-the-cli) + - [Creating Applications Manually](#creating-applications-manually) + - [Modifying Applications with the CLI](#modifying-applications-using-the-cli) + - [Modifying Applications Manually](#modifying-applications-manually) + - [Auth0 APIs](#auth0-apis) + - [Creating APIs with the CLI](#creating-apis-with-the-cli) + - [Creating APIs Manually](#creating-apis-manually) + - [Modifying APIs with the CLI](#modifying-apis-using-the-cli) + - [Modifying APIs Manually](#modifying-apis-manually) + +## SDK Configuration + +This guide addresses v2 of the SDK configuration format. You can determine which version you are using by evaluating the constant prepended to the returned array in your application's `config/auth0.php` file, prefixed with `Configuration::VERSION_`. For example: -This document covers 'version 2' of the SDK configuration format. You can determine which version you are using by looking for the `Configuration::VERSION_` const returned with the `config/auth0.php` array. +```php +return Configuration::VERSION_2 + [ + // ... +]; +``` -## JSON Configuration (Preferred) +If you do not see such a value, you are most likely using an outdated configuration format, and should upgrade by running `php artisan vendor:publish --tag auth0 --force` from your project directory. You will lose any alterations you have made to this file in the process. + +### JSON Configuration Files The preferred method of SDK configuration is to use JSON exported from the [Auth0 CLI](https://auth0.com/docs/cli). This allows you to use the CLI to manage your Auth0 configuration, and then export the configuration to JSON for use by the SDK. The SDK will look for the following files in the project directory, in the order listed: -- `auth0.json` -- `auth0..json` -- `auth0.api.json` -- `auth0.app.json` -- `auth0.api..json` -- `auth0.app..json` +- `auth0.json` +- `auth0..json` +- `auth0.api.json` +- `auth0.app.json` +- `auth0.api..json` +- `auth0.app..json` Where `` is the value of Laravel's `APP_ENV` environment variable (if set.) Duplicate keys in the files listed above will be overwritten in the order listed. -## Environment Variables +### Environment Variables -The SDK also supports configuration using environment variables. These can be defined in the host environment, or in a `.env` file in the project directory. +The SDK also supports configuration using environment variables. These can be defined within the host environment, or using so-called dotenv (`.env`, or `.env.*`) files in the project directory. | Variable | Description | | --------------------- | ---------------------------------------------------------------------------------------------------- | @@ -34,7 +61,7 @@ The SDK also supports configuration using environment variables. These can be de | `AUTH0_SCOPE` | `String (comma-delimited list)` The scopes for your application. Defaults to 'openid,profile,email'. | | `AUTH0_ORGANIZATION` | `String (comma-delimited list)` The organizations for your application. | -The following environment variables are also supported, but should not be adjusted unless you know what you are doing: +The following environment variables are supported, but should not be adjusted unless you know what you are doing: | Variable | Description | | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -59,13 +86,15 @@ The following environment variables are also supported, but should not be adjust | `AUTH0_CLIENT_ASSERTION_SIGNING_ALGORITHM` | `String` The algorithm to use for signing client assertions. Defaults to `RS256`. | | `AUTH0_PUSHED_AUTHORIZATION_REQUEST` | `Boolean` Whether the SDK should use Pushed Authorization Requests during authentication. Note that your tenant must have this feature enabled. Defaults to `false`. | -## Overriding Automatic Behavior +### Order of Priority + +### Default Behavior -### Guard Registration +#### Guard Registration By default, the SDK will register the Authentication and Authorization guards with your Laravel application, as well as a compatible [User Provider](./Users.md). -You can disable this behavior by setting `registerGuards` to false in your `config/auth0.php` file. +You can disable this behavior by setting `registerGuards` to `false` in your `config/auth0.php` file. To register the guards manually, update the arrays in your `config/auth.php` file to include the following additions: @@ -91,11 +120,11 @@ To register the guards manually, update the arrays in your `config/auth.php` fil ], ``` -### Middleware Registration +#### Middleware Registration By default, the SDK will register the Authentication and Authorization guards within your application's `web` and `api` middleware groups. -You can disable this behavior by setting `registerMiddleware` to false in your `config/auth0.php` file. +You can disable this behavior by setting `registerMiddleware` to `false` in your `config/auth0.php` file. To register the middleware manually, update your `app/Http/Kernel.php` file and include the following additions: @@ -127,7 +156,7 @@ For `routes/api.php`, add the following before any routes: Auth::shouldUse('auth0-api'); ``` -### Authentication Routes +#### Route Registration By default, the SDK will register the following routes for authentication: @@ -137,7 +166,7 @@ By default, the SDK will register the following routes for authentication: | `GET` | `/logout` | `logout` | `Auth0\Laravel\Controllers\LogoutController` | Logs the user out. | | `GET` | `/callback` | `callback` | `Auth0\Laravel\Controllers\CallbackController` | Handles the callback from Auth0. | -You can disable this behavior by setting `registerAuthenticationRoutes` to false in your `config/auth0.php` file. +You can disable this behavior by setting `registerAuthenticationRoutes` to `false` in your `config/auth0.php` file. If you've disabled the automatic registration of routes, you must register the routes manually for authentication to work. @@ -157,5 +186,148 @@ Or you can call the SDK Facade's `routes()` method in your `routes/web.php` file Auth0::routes(); ``` -- These must be registered within the `web` middleware group, as they rely on sessions. -- Requests must be routed through the SDK's Authenticator guard. +- These must be registered within the `web` middleware group, as they rely on sessions. +- Requests must be routed through the SDK's Authenticator guard. + +## Auth0 Configuration + +The following guidance is provided to help you configure your Auth0 tenant for use with the SDK. It is not intended to be a comprehensive guide to configuring Auth0. Please refer to the [Auth0 documentation](https://auth0.com/docs) for more information. + +### Auth0 Applications + +#### Creating Applications with the CLI + +Use the CLI's `apps create` command to create a new Auth0 Application: + +```shell +auth0 apps create \ + --name "My Laravel Application" \ + --type "regular" \ + --auth-method "post" \ + --callbacks "http://localhost:8000/callback" \ + --logout-urls "http://localhost:8000/" \ + --reveal-secrets \ + --no-input +``` + +If you are configuring the SDK for this application, make note of the `client_id` and `client_secret` values returned by the command. Follow the guidance in the [configuration guide](#configuration) to configure the SDK using these values. + +The following parameters used in this example are of note: + +- `--type` - The [application type](https://auth0.com/docs/get-started/applications). + - For Laravel applications, this should always be set to `regular`. +- `--auth-method` - This represents the 'Token Endpoint Authentication Method' used for authentication. + - For Laravel applications, this should always be set to `post`. +- `--callbacks` - The callback URLs to use for authentication. + - In development, this should be set to `http://localhost:8000/callback` or as appropriate. + - In production, adjust this value to match your application's Internet-accessible URL for its`/callback`` route. + - This value can be a comma-separated list of URLs. +- `--logout-urls` - The logout URLs to use for authentication. + - In development, this should be set to `http://localhost:8000` or as appropriate. + - In production, adjust this value to match where your application redirects end users after logging out. The value should be an Internet-accessible URL. + - This value can be a comma-separated list of URLs. + +Please refer to the [CLI documentation](https://auth0.github.io/auth0-cli/auth0_apps_create.html) for additional information on the `apps create` command. + +#### Modifying Applications using the CLI + +Use the CLI's `apps update` command to create a new Auth0 API: + +```shell +auth0 apps update %CLIENT_ID% \ + --name "My Updated Laravel Application" \ + --callbacks "https://production/callback,http://localhost:8000/callback" \ + --logout-urls "https://production/logout,http://localhost:8000" \ + --no-input +``` + +Substitute `%CLIENT_ID%` with your application's Client ID. Depending on how you configured the SDK, this value can be found: + +- In the `.auth0.app.json` file in your project's root directory, as the `client_id` property value. +- In the `.env` file in your project's root directory, as the `AUTH0_CLIENT_ID` property value. +- As the `AUTH0_CLIENT_ID` environment variable. +- Evaluating the output from the CLI's `apps list` command. + +Please refer to the [CLI documentation](https://auth0.github.io/auth0-cli/auth0_apps_update.html) for additional information on the `apps update` command. + +#### Creating Applications Manually + +1. Log in to your [Auth0 Dashboard](https://manage.auth0.com/). +2. Click the **Applications** menu item in the left navigation bar. +3. Click the **Create Application** button. +4. Enter a name for your application. +5. Select **Regular Web Applications** as the application type. +6. Click the **Create** button. +7. Click the **Settings** tab. +8. Set the **Token Endpoint Authentication Method** to `POST`. +9. Set the **Allowed Callback URLs** to `http://localhost:8000/callback` or as appropriate. +10. Set the **Allowed Logout URLs** to `http://localhost:8000` or as appropriate. +11. Click the **Save Changes** button. + +#### Modifying Applications Manually + +1. Log in to your [Auth0 Dashboard](https://manage.auth0.com/). +2. Click the **Applications** menu item in the left navigation bar. +3. Click the name of the application you wish to modify. +4. Click the **Settings** tab. +5. Modify the properties you wish to update as appropriate. +6. Click the **Save Changes** button. + +### Auth0 APIs + +#### Creating APIs with the CLI + +Use the CLI's `apis create` command to create a new Auth0 API: + +```shell +auth0 apis create \ + --name "My Laravel Application API" \ + --identifier "https://github.com/auth0/laravel-auth0" \ + --offline-access \ + --no-input +``` + +If you are configuring the SDK for this API, make note of the `identifier` you used here. Follow the guidance in the [configuration guide](#configuration) to configure the SDK using this value. + +The following parameters are of note: + +- `--identifier` - The [unique identifier](https://auth0.com/docs/get-started/apis/api-settings#general-settings) for your API, sometimes referred to as the `audience`. This can be any value you wish, but it must be unique within your account. It cannot be changed later. +- `--offline-access` - This enables the use of [Refresh Tokens](https://auth0.com/docs/tokens/refresh-tokens) for your API. This is not required for the SDK to function. + +Please refer to the [CLI documentation](https://auth0.github.io/auth0-cli/auth0_apis_create.html) for additional information on the `apis create` command. + +#### Modifying APIs using the CLI + +Use the CLI's `apis update` command to create a new Auth0 API: + +```shell +auth0 apis update %IDENTIFIER% \ + --name "My Updated Laravel Application API" \ + --token-lifetime 6100 \ + --offline-access=false \ + --scopes "letter:write,letter:read" \ + --no-input +``` + +Substitute `%IDENTIFIER%` with your API's unique identifier. + +Please refer to the [CLI documentation](https://auth0.github.io/auth0-cli/auth0_apis_update.html) for additional information on the `apis update` command. + +#### Creating APIs Manually + +1. Log in to your [Auth0 Dashboard](https://manage.auth0.com/). +2. Click the **APIs** menu item in the left navigation bar. +3. Click the **Create API** button. +4. Enter a name for your API. +5. Enter a unique identifier for your API. This can be any value you wish, but it must be unique within your account. It cannot be changed later. +6. Click the **Create** button. + +#### Modifying APIs Manually + +1. Log in to your [Auth0 Dashboard](https://manage.auth0.com/). +2. Click the **APIs** menu item in the left navigation bar. +3. Click the name of the API you wish to modify. +4. Modify the properties you wish to update as appropriate. +5. Click the **Save Changes** button. + +Additional information on Auth0 application settings [can be found here](https://auth0.com/docs/get-started/applications/application-settings). diff --git a/docs/Events.md b/docs/Events.md index 408f6cde..358f7680 100644 --- a/docs/Events.md +++ b/docs/Events.md @@ -1,8 +1,19 @@ # Events -**The SDK raises events during the authentication process.** Your application can listen to these events and respond to them if desired. For example, you might want to log the user's information to a database when they log in. +- [Introduction](#introduction) +- [SDK Controller Events](#sdk-controller-events) + - [Login Events](#login-events) + - [Callback Events](#callback-events) + - [Logout Events](#logout-events) +- [Deprecated SDK Events](#deprecated-sdk-events) + - [Authentication Middleware Events](#authentication-middleware-events) + - [Authorization Middleware Events](#authorization-middleware-events) -To listen for events, you must first create a listener class. These usually live in your application's `app/Listeners` directory. The following example shows how to listen to the `lluminate\Auth\Events\Login` event: +## Introduction + +Your application can listen to events raised by the SDK, and respond to them if desired. For example, you might want to log the user's information to a database when they log in. + +To listen for these events, you must first create a listener class within your application. These usually live in your `app/Listeners` directory. The following example shows how to listen for the `Illuminate\Auth\Events\Login` event: ```php namespace App\Listeners; @@ -18,7 +29,7 @@ final class LogSuccessfulLogin } ``` -Be sure to register your event listeners in your `app/Providers/EventServiceProvider.php` file, for example: +You should also register your event listeners in your application's `app/Providers/EventServiceProvider.php` file, for example: ```php use Illuminate\Auth\Events\Login; @@ -28,26 +39,28 @@ use Illuminate\Support\Facades\Event; public function boot(): void { Event::listen( - Login::class, - [LogSuccessfulLogin::class, 'handle'] + Login::class, // The event class. + [LogSuccessfulLogin::class, 'handle'] // Your listener class and method. ); } ``` You can learn more about working with the Laravel event system in the [Laravel documentation](https://laravel.com/docs/events). -## Login Controller Events +## SDK Controller Events -During login with `Auth0\Laravel\Controllers\LoginController` the following events may be raised: +### Login Events + +During user authentication triggered by `Auth0\Laravel\Controllers\LoginController` (the `/login` route, by default) the following events may be raised: | Event | Description | | -------------------------------------- | -------------------------------------------------------------------------------------------- | | `Illuminate\Auth\Events\Login` | Raised when a user is logging in. The model of the user is provided with the event. | | `Auth0\Laravel\Events\LoginAttempting` | Raised before the login redirect is issued, allowing an opportunity to customize parameters. | -## Callback Controller Events +### Callback Events -During callback with `Auth0\Laravel\Controllers\CallbackController` the following events may be raised: +During user authentication callback triggered by `Auth0\Laravel\Controllers\CallbackController` (the `/callback` route, by default) the following events may be raised: | Event | Description | | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -57,15 +70,17 @@ During callback with `Auth0\Laravel\Controllers\CallbackController` the followin | `Illuminate\Auth\Events\Validated` | Raised when authentication was successful, but immediately before the user's session is established. | | `Auth0\Laravel\Events\AuthenticationSucceeded` | Raised when authentication was successful. The model of the authenticated user is provided with the event. | -## Logout Controller Events +### Logout Events -During logout with `Auth0\Laravel\Controllers\LogoutController` the following events may be raised: +During user logout by `Auth0\Laravel\Controllers\LogoutController` (the `/logout` route, by default) the following events may be raised: | Event | Description | | ------------------------------- | ------------------------------------------------------------------------------------ | | `Illuminate\Auth\Events\Logout` | Raised when a user is logging out. The model of the user is provided with the event. | -## Deprecated Middleware Events +## Deprecated SDK Events + +The following events are deprecated and will be removed in a future release. They are replaced by the events listed in the previous section. ### Authentication Middleware Events diff --git a/docs/Installation.md b/docs/Installation.md index e7d61889..24932f9c 100644 --- a/docs/Installation.md +++ b/docs/Installation.md @@ -1,22 +1,191 @@ # Installation -> **Note:** -> This is an addendum to the [README](../README.md) file. Please review that guidance first. +- [Prerequisites](#prerequisites) +- [Install the SDK](#install-the-sdk) + - [Using Quickstart (Recommended)](#using-quickstart-recommended) + - [Installation with Composer](#installation-with-composer) + - [Create a Laravel Application](#create-a-laravel-application) + - [Install the SDK](#install-the-sdk-1) +- [Install the CLI](#install-the-cli) + - [Authenticate the CLI](#authenticate-the-cli) +- [Configure the SDK](#configure-the-sdk) + - [Using JSON (Recommended)](#using-json-recommended) + - [Using Environment Variables](#using-environment-variables) -## Alternative Configuration Methods +## Prerequisites -Although our guidance is to use the Auth0 CLI to create the JSON configuration files for the SDK, we recognize that this may not be possible in all cases. +To integrate our SDK, your application must use a [supported Laravel version](https://laravelversions.com/en), and your environment must run a [supported PHP version](https://www.php.net/supported-versions.php). We do not support versions of either that are no longer supported by their maintainers. Please review [our support policy](./Support.md) for more information. -### Environment Variables +| SDK | Laravel | PHP | Supported Until | +| ---- | ------- | ---- | --------------- | +| 7.5+ | 10 | 8.2+ | Feb 2025 | +| | | 8.1+ | Nov 2024 | +| 7.0+ | 9 | 8.2+ | Feb 2024 | +| | | 8.1+ | Feb 2024 | +| | | 8.0+ | Nov 2023 | -The SDK supports the use of environment variables to configure the SDK. These can be defined in the `.env` file in the root of your project, or in your hosting environment. +You will also need [Composer 2.0+](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). -To successfully use the SDK, you must provide the following environment variables at a minimum: +## Install the SDK -| Variable | Description | -| --------------------- | --------------------------------------- | -| `AUTH0_DOMAIN` | The Auth0 domain for your tenant. | -| `AUTH0_CLIENT_ID` | The Client ID for your application. | -| `AUTH0_CLIENT_SECRET` | The Client Secret for your application. | +Ensure that your development environment has [supported versions](#prerequisites) of PHP and [Composer](https://getcomposer.org/) installed. If you're using macOS, PHP and Composer can be installed via [Homebrew](https://brew.sh/). It's also advisable to [install Node and NPM](https://nodejs.org/). -For a full list of supported environment variables, see [Configuration](./Configuration.md). +### Using Quickstart (Recommended) + +- Run the following command to create a new Laravel 9 project pre-configured with the SDK: + + ```shell + composer create-project auth0-samples/laravel auth0-laravel-app + ``` + +### Installation with Composer + +#### Create a Laravel Application + +- If you do not already have one, you can Create a new Laravel 9 application with the following command: + + ```shell + composer create-project laravel/laravel:^9.0 auth0-laravel-app + ``` + +#### Install the SDK + +1. Run the following command in your project directory to install the SDK: + + ```shell + composer require auth0/login:^7.8 --update-with-all-dependencies + ``` + +2. Generate an SDK configuration file for your application: + + ```shell + php artisan vendor:publish --tag auth0 + ``` + +## Install the CLI + +Install the [Auth0 CLI](https://github.com/auth0/auth0-cli) to create and manage Auth0 resources from the command line. + +- macOS with [Homebrew](https://brew.sh/): + + ```shell + brew tap auth0/auth0-cli && brew install auth0 + ``` + +- Linux or macOS: + + ```shell + curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . + sudo mv ./auth0 /usr/local/bin + ``` + +- Windows with [Scoop](https://scoop.sh/): + + ```cmd + scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git + scoop install auth0 + ``` + +### Authenticate the CLI + +- Authenticate with your Auth0 account: + + ```shell + auth0 login + ``` + + Choose "as a user," and follow the prompts to log in. + +## Configure the SDK + +### Using JSON (Recommended) + +1. Register a new application with Auth0: + + ```shell + auth0 apps create \ + --name "My Laravel Application" \ + --type "regular" \ + --auth-method "post" \ + --callbacks "http://localhost:8000/callback" \ + --logout-urls "http://localhost:8000/" \ + --reveal-secrets \ + --no-input \ + --json > .auth0.app.json + ``` + +2. Register a new API with Auth0: + + ```shell + auth0 apis create \ + --name "My Laravel Application API" \ + --identifier "https://github.com/auth0/laravel-auth0" \ + --offline-access \ + --no-input \ + --json > .auth0.api.json + ``` + +3. Add the new files to `.gitignore`: + + Linux and macOS: + + ```bash + echo ".auth0.*.json" >> .gitignore + ``` + + Windows PowerShell: + + ```powershell + Add-Content .gitignore "`n.auth0.*.json" + ``` + + Windows Command Prompt: + + ```cmd + echo .auth0.*.json >> .gitignore + ``` + +### Using Environment Variables + +1. Register a new application with Auth0: + + ```shell + auth0 apps create \ + --name "My Laravel Application" \ + --type "regular" \ + --auth-method "post" \ + --callbacks "http://localhost:8000/callback" \ + --logout-urls "http://localhost:8000/" \ + --reveal-secrets \ + --no-input + ``` + + Make a note of the `client_id` and `client_secret` values in the output. + +2. Register a new API with Auth0: + + ```shell + auth0 apis create \ + --name "My Laravel Application API" \ + --identifier "https://github.com/auth0/laravel-auth0" \ + --offline-access \ + --no-input + ``` + +3. Open the `.env` file found inside your project directory, and add the following lines, replacing the values with the ones you noted in the previous steps: + + ```ini + # The Auth0 domain for your tenant (e.g. tenant.region.auth0.com): + AUTH0_DOMAIN=... + + # The application `client_id` you noted above: + AUTH0_CLIENT_ID=... + + # The application `client_secret` you noted above: + AUTH0_CLIENT_SECRET=... + + # The API `identifier` you used above: + AUTH0_AUDIENCE=... + ``` + + Additional configuration environment variables can be found in the [configuration guide](./Configuration.md#environment-variables). diff --git a/docs/Management.md b/docs/Management.md index 31584cd4..3ff45e0f 100644 --- a/docs/Management.md +++ b/docs/Management.md @@ -2,12 +2,6 @@ The Auth0 Laravel SDK provides easy-to-use methods to access Auth0's Management API endpoints. Nearly every endpoint of the Management API is available to use with your Laravel application. For more information about any of these endpoints, see the [Management API Explorer](https://auth0.com/docs/api/management/v2). -## Management API Permissions - -Before making Management API calls you must enable your application to communicate with the Management API. This can be done from the [Auth0 Dashboard's API page](https://manage.auth0.com/#/apis/), choosing `Auth0 Management API`, and selecting the 'Machine to Machine Applications' tab. Authorize your Laravel application, and then click the down arrow to choose the scopes you wish to grant. - -## Accessing the Management API - The Management API class can be accessed through the `management()` method on the Auth0 Laravel SDK service. You can pull the Auth0 SDK instance from the Laravel service container using dependency injection, or use the `Auth0` facade. Once you have an instance, you can call any of the [available endpoints](#available-endpoints). ```php @@ -16,6 +10,10 @@ use Auth0\Laravel\Facade\Auth0; Auth0::management(); ``` +## API Application Authorization + +Before making Management API calls you must permit your application to communicate with the Management API. This can be done from the [Auth0 Dashboard's API page](https://manage.auth0.com/#/apis/), choosing `Auth0 Management API`, and selecting the 'Machine to Machine Applications' tab. Authorize your Laravel application, and then click the down arrow to choose the scopes you wish to grant. + ## Available endpoints - [Actions](#actions) diff --git a/docs/Support.md b/docs/Support.md new file mode 100644 index 00000000..92a3607d --- /dev/null +++ b/docs/Support.md @@ -0,0 +1,24 @@ +# Support + +To integrate our SDK, your application must use a [supported Laravel version](https://laravelversions.com/en), and your environment must run a [supported PHP version](https://www.php.net/supported-versions.php). We do not support versions of either that are no longer supported by their maintainers. + +| SDK | Laravel | PHP | Supported Until | +| ---- | ------- | ---- | --------------- | +| 7.5+ | 10 | 8.2+ | Feb 2025 | +| | | 8.1+ | Nov 2024 | +| 7.0+ | 9 | 8.2+ | Feb 2024 | +| | | 8.1+ | Feb 2024 | +| | | 8.0+ | Nov 2023 | + +You will also need [Composer 2.0+](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). + +## Support Policy + +The SDK follows the [Laravel support policy](https://laravel.com/docs/master/releases#support-policy) and will be supported until the Laravel version it supports reaches end-of-life, or it is no longer technically feasible to support. + +## Getting Support + +- If you believe you've found a bug, please [create an issue on GitHub](https://github.com/auth0/laravel-auth0). +- For questions and community support, please [join the Auth0 Community](https://community.auth0.com/). +- For paid support plans, please [contact us directly](https://auth0.com/contact-us). +- For more information about Auth0 Support, please visit our [Support Center](https://support.auth0.com/). From 494dd779a021d51cdb0340a098eed9fd491992e3 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 17:06:48 -0500 Subject: [PATCH 430/525] Update README.md --- README.md | 46 +++++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 5ae1c82c..a056c410 100644 --- a/README.md +++ b/README.md @@ -43,13 +43,13 @@ The following is our recommended approach to getting started with the SDK. Alter ### 1. Install the SDK -- For new applications, run the following command to create a new Laravel 9 project pre-configured with the SDK: +- For **new applications**, we offer a quickstart template — a version of the default Laravel 9 starter project pre-configured for use with the Auth0 SDK: ```shell composer create-project auth0-samples/laravel auth0-laravel-app && cd auth0-laravel-app ``` -- For existing applications, you can install the SDK using Composer: +- For **existing applications**, you can install the SDK using Composer: ```shell composer require auth0/login:^7.9 --update-with-all-dependencies @@ -103,25 +103,25 @@ The following is our recommended approach to getting started with the SDK. Alter ```shell auth0 apps create \ - --name "My Laravel Application" \ - --type "regular" \ - --auth-method "post" \ - --callbacks "http://localhost:8000/callback" \ - --logout-urls "http://localhost:8000/" \ - --reveal-secrets \ - --no-input \ - --json > .auth0.app.json + --name "My Laravel Application" \ + --type "regular" \ + --auth-method "post" \ + --callbacks "http://localhost:8000/callback" \ + --logout-urls "http://localhost:8000/" \ + --reveal-secrets \ + --no-input \ + --json > .auth0.app.json ``` 2. Register a new API with Auth0: ```shell auth0 apis create \ - --name "My Laravel Application API" \ - --identifier "https://github.com/auth0/laravel-auth0" \ - --offline-access \ - --no-input \ - --json > .auth0.api.json + --name "My Laravel Application API" \ + --identifier "https://github.com/auth0/laravel-auth0" \ + --offline-access \ + --no-input \ + --json > .auth0.api.json ``` 3. Add the new files to `.gitignore`: @@ -258,7 +258,7 @@ Route::get('/', function () { Once you've [authorized your application to make Management API calls](./docs/Management.md#api-application-authorization), you'll be able to engage nearly any of the [Auth0 Management API endpoints](https://auth0.com/docs/api/management/v2) using the SDK. -Each endpoint has its own Management API class, all of which can be accessed through the Facade's `management()` method. +Each endpoint has its own Management API class, all of which can be accessed through the Facade's `management()` method. API responses are returned as [PSR-7 messages](https://www.php-fig.org/psr/psr-7/), and can be converted into native arrays using the SDK's `json()` method. For example, to update a user's metadata, you can call the `management()->users()->update()` method: @@ -272,23 +272,19 @@ Route::get('/colors', function () { Auth0::management()->users()->update( id: auth()->id(), body: [ - 'user_metadata' => [ - 'color' => $colors[random_int(0, count($colors) - 1)] - ] + 'user_metadata' => [ + 'color' => $colors[random_int(0, count($colors) - 1)] + ] ] ); // Retrieve the user's updated profile. $profile = Auth0::management()->users()->get(auth()->id()); - // For interoperability, the SDK returns all API responses as - // PSR-7 Responses that contain the JSON response. - - // You can use the `json()` helper to unpack the PSR-7, and - // convert the API's JSON response to a native PHP array. + // Convert the PSR-7 response into a native array. $profile = Auth0::json($profile); - // Read the user's profile. + // Extract some values from the user's profile. $color = $profile['user_metadata']['color'] ?? 'unknown'; $name = auth()->user()->name; From d954da28047a215e243a102fff3ad96e8db2674e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 17:26:44 -0500 Subject: [PATCH 431/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a056c410..0611bb5a 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ The following is our recommended approach to getting started with the SDK. Alter ```
-2. Run the following command to authenticate the CLI with your Auth0 account. Choose "as a user," and follow the prompts. +2. Authenticate the CLI with your Auth0 account. Choose "as a user," and follow the prompts. ```shell auth0 login From 9518b5bed8c111acf5fc61ff128b03d8641a6b68 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 17:26:46 -0500 Subject: [PATCH 432/525] Update Installation.md --- docs/Installation.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/Installation.md b/docs/Installation.md index 24932f9c..38c5e40f 100644 --- a/docs/Installation.md +++ b/docs/Installation.md @@ -32,7 +32,7 @@ Ensure that your development environment has [supported versions](#prerequisites ### Using Quickstart (Recommended) -- Run the following command to create a new Laravel 9 project pre-configured with the SDK: +- Create a new Laravel 9 project pre-configured with the SDK: ```shell composer create-project auth0-samples/laravel auth0-laravel-app @@ -50,7 +50,7 @@ Ensure that your development environment has [supported versions](#prerequisites #### Install the SDK -1. Run the following command in your project directory to install the SDK: +1. Run the following command from your project directory to install the SDK: ```shell composer require auth0/login:^7.8 --update-with-all-dependencies @@ -88,14 +88,12 @@ Install the [Auth0 CLI](https://github.com/auth0/auth0-cli) to create and manage ### Authenticate the CLI -- Authenticate with your Auth0 account: +- Authenticate the CLI with your Auth0 account. Choose "as a user," and follow the prompts. ```shell auth0 login ``` - Choose "as a user," and follow the prompts to log in. - ## Configure the SDK ### Using JSON (Recommended) From 34615371444dc1e5fa762f3ac8f14033713fa44f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 17:40:42 -0500 Subject: [PATCH 433/525] Update README.md --- README.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/README.md b/README.md index 0611bb5a..5cc67dfb 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ - [1. Install the SDK](#1-install-the-sdk) - [2. Install the CLI](#2-install-the-cli) - [3. Configure the SDK](#3-configure-the-sdk) + - [4. Run the Application](#4-run-the-application) - [Documentation](#documentation) - [QuickStarts](#quickstarts) - [Contributing](#contributing) @@ -148,6 +149,40 @@ The following is our recommended approach to getting started with the SDK. Alter ```
+### 4. Run the Application + +You can now run the application using the built-in PHP web server: + +```shell +php artisan serve +``` + +Your application should now be accessible from your browser at [http://localhost:8000](http://localhost:8000). + +- **Testing Authentication** + You can log in or out by visiting the [`/login`](http://localhost:8000/login) or [`/logout`](http://localhost:8000/logout) routes, respectively. + +- **Testing API Authorization** + To test `/api` routes, you can generate a test token using the CLI. In the following example, substitute `%AUDIENCE%` with the identifier of the API you created in step 3 above. + + ```shell + auth0 test token \ + --audience %AUDIENCE% \ + --scopes "read:messages" + ``` + + Use the token returned by the command to make requests to your API: + + ```shell + curl --request GET \ + --url http://localhost:8000/api/private \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' + ``` + +- **Deploying to Production** +For guidance on moving your application to production, see [our deployment guide](./docs/Deployment.md). + ## Integration Examples
From aac7830b912aec201b79a498f47e0cc157bc760d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 17:40:45 -0500 Subject: [PATCH 434/525] Create Deployment.md --- docs/Deployment.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/Deployment.md diff --git a/docs/Deployment.md b/docs/Deployment.md new file mode 100644 index 00000000..e69de29b From 57f7abc7abfeb2c3a721a02f5c2a30ef9bf3f525 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 17:41:14 -0500 Subject: [PATCH 435/525] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5cc67dfb..04c18c83 100644 --- a/README.md +++ b/README.md @@ -167,17 +167,17 @@ Your application should now be accessible from your browser at [http://localhost ```shell auth0 test token \ - --audience %AUDIENCE% \ - --scopes "read:messages" + --audience %AUDIENCE% \ + --scopes "read:messages" ``` Use the token returned by the command to make requests to your API: ```shell curl --request GET \ - --url http://localhost:8000/api/private \ - --header 'Accept: application/json' \ - --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' + --url http://localhost:8000/api/private \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' ``` - **Deploying to Production** From ebd23f83a632ecf8c5f4a5c3a04e9ffa03f62b2f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 18:21:03 -0500 Subject: [PATCH 436/525] Update Deployment.md --- docs/Deployment.md | 190 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) diff --git a/docs/Deployment.md b/docs/Deployment.md index e69de29b..25a19bb3 100644 --- a/docs/Deployment.md +++ b/docs/Deployment.md @@ -0,0 +1,190 @@ +# Deployment + +When you're ready to deploy your application to production, there are some important things you can do to make sure your application is running as efficiently as possible. In this document, we'll cover some great starting points for making sure your Laravel application is deployed properly. + +- [Updating the Auth0 Configuration](#updating-the-auth0-configuration) +- [Cookies](#cookies) +- [Server Configuration](#server-configuration) +- [Optimization](#optimization) + +## Updating the Auth0 Configuration + +When migrating your Laravel application from local development to production, you will need to update your Auth0 application's configuration to reflect the new URLs for your application. You can do this by logging into the [Auth0 Dashboard](https://manage.auth0.com/) and updating the following fields: + +- **Allowed Callback URLs**: The URL that Auth0 will redirect to after the user authenticates. This should be set to the Internet-accessible URL of your application's `/callback` route. +- **Allowed Logout URLs**: The URL that Auth0 will redirect to after the user logs out. This should be set to an appropriate Internet-accessible URL of your application. + +Note that you can include multiple URLs in these fields by separating them with commas, for example: + +``` +https://example.com/callback,http://localhost:8000/callback +``` + +See [the configuration guide](/docs/configuration.md) for additional guidance on updating configuration properties. + +## TLS / HTTPS + +Auth0 requires that all applications use TLS/HTTPS. This is a requirement for all applications, regardless of whether they are running in production or development, with the exception of applications running on `localhost`. If you are running your application in a development environment, you can use a self-signed certificate. However, you should ensure that your application is running over TLS/HTTPS in production. + +Let's Encrypt is a great option for obtaining free TLS/HTTPS certificates for your application. You can find instructions for obtaining a certificate for your server at [https://letsencrypt.org/getting-started/](https://letsencrypt.org/getting-started/). + +## Cookies + +Depending on the integration approach, you may encounter instances where the cookies delivered by the application exceed the default allowances of your web server. This can result in errors such as `400 Bad Request`. If you encounter this issue, you should increase the header size limits of your web server to accommodate the larger cookies. The server configurations below include examples of how to do this for common web servers. + +You should also ensure your application's `config/session.php` file is configured securely. The default configuration provided by Laravel is a great starting point, but you should double check that the `secure` option is set to `true`, that the `same_site` option is set to `lax` or `strict`, and the `http_only` option is set to `true`. + +## Server Configuration + +Please ensure, like all the example configurations provided below, that your web server directs all requests to your application's `public/index.php` file. You should **never** attempt to move the `index.php` file to your project's root, as serving the application from the project root will expose many sensitive configuration files to the public Internet. + +### Caddy 2 + +If you are deploying your application to a server that is running Caddy, you may use the following configuration file as a starting point for configuring your web server. Most likely, this file will need to be customized depending on your server's configuration. + +```nginx +example.com { + root * /var/www/example.com/public + + encode zstd gzip + file_server + + limits { + header 4kb + } + + header { + X-XSS-Protection "1; mode=block" + X-Content-Type-Options "nosniff" + X-Frame-Options "SAMEORIGIN" + } + + php_fastcgi unix//var/run/php/php8.1-fpm.sock +} +``` + +### Nginx + +```nginx +server { + listen 80; + listen [::]:80; + server_name example.com; + root /var/www/example.com/public; + + add_header X-XSS-Protection "1; mode=block"; + add_header X-Content-Type-Options "nosniff"; + add_header X-Frame-Options "SAMEORIGIN"; + + large_client_header_buffers 4 32k; + + index index.php; + + charset utf-8; + + location / { + try_files $uri $uri/ /index.php?$query_string; + } + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + error_page 404 /index.php; + + location ~ \.php$ { + fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + include fastcgi_params; + } + + location ~ /\.(?!well-known).* { + deny all; + } +} +``` + +### Apache + +```apache + + ServerName example.com + ServerAdmin admin@example.com + DocumentRoot /var/www/html/example.com/public + + LimitRequestFieldSize 16384 + + + AllowOverride All + + + + Header set X-XSS-Protection "1; mode=block" + Header always set X-Content-Type-Options nosniff + Header always set X-Frame-Options SAMEORIGIN + + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + +``` + +## Optimization + +### Autoloader Optimization + +When deploying to production, make sure that you are optimizing Composer's class autoloader map so Composer can quickly find the proper file to load for a given class: + +```shell +composer install --optimize-autoloader --no-dev +``` + +Be sure to use the `--no-dev` option in production. This will prevent Composer from installing any development dependencies your project's dependencies may have. + +### Dependencies Lockfile + +You should include your `composer.lock` file in your project's source control repository. Fo project's dependencies can be installed much faster with this file is present. Your production environment does not run `composer update` directly. Instead, you can run the `composer update` command locally when you want to update your dependencies, and then commit the updated `composer.lock` file to your repository. Be sure you are running the same major PHP version as your production environment, to avoid introducing compatibility issues. + +Because the `composer.lock` file includes specific versions of your dependencies, other developers on your team will be using the same versions of the dependencies as you. This will help prevent bugs and compatibility issues from appearing in production that aren't present during development. + +### Caching Configuration + +When deploying your application to production, you should make sure that you run the config:cache Artisan command during your deployment process: + +```shell +php artisan config:cache +``` + +This command will combine all of Laravel's configuration files into a single, cached file, which greatly reduces the number of trips the framework must make to the filesystem when loading your configuration values. + +### Caching Events + +If your application is utilizing event discovery, you should cache your application's event to listener mappings during your deployment process. This can be accomplished by invoking the event:cache Artisan command during deployment: + +```shell +php artisan event:cache +``` + +### Caching Routes + +If you are building a large application with many routes, you should make sure that you are running the route:cache Artisan command during your deployment process: + +```shell +php artisan route:cache +``` + +This command reduces all of your route registrations into a single method call within a cached file, improving the performance of route registration when registering hundreds of routes. + +### Caching Views +When deploying your application to production, you should make sure that you run the view:cache Artisan command during your deployment process: + +```shell +php artisan view:cache +``` + +This command precompiles all your Blade views so they are not compiled on demand, improving the performance of each request that returns a view. + +## Debug Mode + +The debug option in your `config/app.php` configuration file determines how much information about an error is actually displayed to the user. By default, this option is set to respect the value of the `APP_DEBUG` environment variable, which is stored in your application's .env file. + +**In your production environment, this value should always be `false`. If the `APP_DEBUG` variable is set to `true` in production, you risk exposing sensitive configuration values to your application's end users.** From 30a77d64964f41229f43867f76a143eb8d4187c5 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 18:25:04 -0500 Subject: [PATCH 437/525] Update Deployment.md --- docs/Deployment.md | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/docs/Deployment.md b/docs/Deployment.md index 25a19bb3..463163d0 100644 --- a/docs/Deployment.md +++ b/docs/Deployment.md @@ -2,12 +2,23 @@ When you're ready to deploy your application to production, there are some important things you can do to make sure your application is running as efficiently as possible. In this document, we'll cover some great starting points for making sure your Laravel application is deployed properly. -- [Updating the Auth0 Configuration](#updating-the-auth0-configuration) +- [Auth0 Configuration](#auth0-configuration) +- [TLS / HTTPS](#tls--https) - [Cookies](#cookies) - [Server Configuration](#server-configuration) + - [Caddy](#caddy) + - [Nginx](#nginx) + - [Apache](#apache) - [Optimization](#optimization) + - [Autoloader](#autoloader) + - [Dependencies](#dependencies) + - [Caching Configuration](#caching-configuration) + - [Caching Events](#caching-events) + - [Caching Routes](#caching-routes) + - [Caching Views](#caching-views) + - [Debug Mode](#debug-mode) -## Updating the Auth0 Configuration +## Auth0 Configuration When migrating your Laravel application from local development to production, you will need to update your Auth0 application's configuration to reflect the new URLs for your application. You can do this by logging into the [Auth0 Dashboard](https://manage.auth0.com/) and updating the following fields: @@ -38,9 +49,7 @@ You should also ensure your application's `config/session.php` file is configure Please ensure, like all the example configurations provided below, that your web server directs all requests to your application's `public/index.php` file. You should **never** attempt to move the `index.php` file to your project's root, as serving the application from the project root will expose many sensitive configuration files to the public Internet. -### Caddy 2 - -If you are deploying your application to a server that is running Caddy, you may use the following configuration file as a starting point for configuring your web server. Most likely, this file will need to be customized depending on your server's configuration. +### Caddy ```nginx example.com { @@ -130,7 +139,7 @@ server { ## Optimization -### Autoloader Optimization +### Autoloader When deploying to production, make sure that you are optimizing Composer's class autoloader map so Composer can quickly find the proper file to load for a given class: @@ -140,7 +149,7 @@ composer install --optimize-autoloader --no-dev Be sure to use the `--no-dev` option in production. This will prevent Composer from installing any development dependencies your project's dependencies may have. -### Dependencies Lockfile +### Dependencies You should include your `composer.lock` file in your project's source control repository. Fo project's dependencies can be installed much faster with this file is present. Your production environment does not run `composer update` directly. Instead, you can run the `composer update` command locally when you want to update your dependencies, and then commit the updated `composer.lock` file to your repository. Be sure you are running the same major PHP version as your production environment, to avoid introducing compatibility issues. @@ -175,6 +184,7 @@ php artisan route:cache This command reduces all of your route registrations into a single method call within a cached file, improving the performance of route registration when registering hundreds of routes. ### Caching Views + When deploying your application to production, you should make sure that you run the view:cache Artisan command during your deployment process: ```shell From 515d44e2c527b07b7468336716322ef4d9dd6e8e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 18:25:18 -0500 Subject: [PATCH 438/525] Update Deployment.md --- docs/Deployment.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Deployment.md b/docs/Deployment.md index 463163d0..0a3179e6 100644 --- a/docs/Deployment.md +++ b/docs/Deployment.md @@ -27,7 +27,7 @@ When migrating your Laravel application from local development to production, yo Note that you can include multiple URLs in these fields by separating them with commas, for example: -``` +```txt https://example.com/callback,http://localhost:8000/callback ``` From fe97ce2586da289ad1a941ea2b78219daac5d2c0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 18:25:40 -0500 Subject: [PATCH 439/525] Update Deployment.md --- docs/Deployment.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/Deployment.md b/docs/Deployment.md index 0a3179e6..e5fd83ec 100644 --- a/docs/Deployment.md +++ b/docs/Deployment.md @@ -25,11 +25,7 @@ When migrating your Laravel application from local development to production, yo - **Allowed Callback URLs**: The URL that Auth0 will redirect to after the user authenticates. This should be set to the Internet-accessible URL of your application's `/callback` route. - **Allowed Logout URLs**: The URL that Auth0 will redirect to after the user logs out. This should be set to an appropriate Internet-accessible URL of your application. -Note that you can include multiple URLs in these fields by separating them with commas, for example: - -```txt -https://example.com/callback,http://localhost:8000/callback -``` +Note that you can include multiple URLs in these fields by separating them with commas, for example `https://example.com/callback,http://localhost:8000/callback`. See [the configuration guide](/docs/configuration.md) for additional guidance on updating configuration properties. From 5219c5f0e77f69973b8fc174269ee763536eb4f0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 18:26:56 -0500 Subject: [PATCH 440/525] Update Deployment.md --- docs/Deployment.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Deployment.md b/docs/Deployment.md index e5fd83ec..c02cf7d2 100644 --- a/docs/Deployment.md +++ b/docs/Deployment.md @@ -1,6 +1,6 @@ # Deployment -When you're ready to deploy your application to production, there are some important things you can do to make sure your application is running as efficiently as possible. In this document, we'll cover some great starting points for making sure your Laravel application is deployed properly. +When you're preparing to deploy your application to production, there are some basic steps you can take to make sure your application is running as smoothly and securely as possible. In this guide, we'll cover some starting points for making sure your application is deployed properly. - [Auth0 Configuration](#auth0-configuration) - [TLS / HTTPS](#tls--https) From 4e1a11cd8da469ae49116622563148457f37a149 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 18:28:56 -0500 Subject: [PATCH 441/525] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 04c18c83..dedce3a6 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ ## Requirements -Your application must use a [supported Laravel version](https://laravelversions.com/en), and your environment must run a [supported PHP version](https://www.php.net/supported-versions.php). +Your application must use a [supported Laravel version](https://laravelversions.com/en), and your host environment must be running a [supported PHP version](https://www.php.net/supported-versions.php). Please review [our support policy](./docs/Support.md) for more information. | SDK | Laravel | PHP | Supported Until | | ---- | ------- | ---- | --------------- | @@ -34,8 +34,6 @@ Your application must use a [supported Laravel version](https://laravelversions. | | | 8.1+ | Feb 2024 | | | | 8.0+ | Nov 2023 | -Please review [our support policy](./docs/Support.md) for more information. - You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). ## Getting Started From b511fb08f496ce55767de71916dec7cd10dcb159 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 18:37:14 -0500 Subject: [PATCH 442/525] Update README.md --- README.md | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index dedce3a6..7f1650d6 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ The following is our recommended approach to getting started with the SDK. Alter ```shell brew tap auth0/auth0-cli && brew install auth0 ``` +
@@ -88,6 +89,7 @@ The following is our recommended approach to getting started with the SDK. Alter scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git scoop install auth0 ``` +
2. Authenticate the CLI with your Auth0 account. Choose "as a user," and follow the prompts. @@ -136,6 +138,7 @@ The following is our recommended approach to getting started with the SDK. Alter ```powershell Add-Content .gitignore "`n.auth0.*.json" ``` +
@@ -145,6 +148,7 @@ The following is our recommended approach to getting started with the SDK. Alter ```cmd echo .auth0.*.json >> .gitignore ``` +
### 4. Run the Application @@ -161,23 +165,34 @@ Your application should now be accessible from your browser at [http://localhost You can log in or out by visiting the [`/login`](http://localhost:8000/login) or [`/logout`](http://localhost:8000/logout) routes, respectively. - **Testing API Authorization** - To test `/api` routes, you can generate a test token using the CLI. In the following example, substitute `%AUDIENCE%` with the identifier of the API you created in step 3 above. + To test `/api` routes, you can generate a test token using the CLI. In the following example, substitute `%IDENTIFIER%` with the identifier of the API you created in step 3 above. ```shell auth0 test token \ - --audience %AUDIENCE% \ + --audience %IDENTIFIER% \ --scopes "read:messages" ``` - Use the token returned by the command to make requests to your API: + You can now make requests to your application's API routes by providing the test token as a header in the request. Substitute `%TOKEN%` with the token returned by the previous step. ```shell curl --request GET \ - --url http://localhost:8000/api/private \ + --url http://localhost:8000/api/example \ --header 'Accept: application/json' \ - --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' + --header 'Authorization: Bearer %TOKEN%' ``` +
+ Using Windows PowerShell +   + + ```powershell + Invoke-WebRequest http://localhost:8000/api/example ` + -Headers @{'Accept' = 'application/json'; 'Authorization' = 'Bearer %TOKEN%'} + ``` + +
+ - **Deploying to Production** For guidance on moving your application to production, see [our deployment guide](./docs/Deployment.md). From e4195e05a1f858637383c28798b85e18dec178e3 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 18:41:12 -0500 Subject: [PATCH 443/525] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7f1650d6..403b12fd 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ Your application should now be accessible from your browser at [http://localhost You can log in or out by visiting the [`/login`](http://localhost:8000/login) or [`/logout`](http://localhost:8000/logout) routes, respectively. - **Testing API Authorization** - To test `/api` routes, you can generate a test token using the CLI. In the following example, substitute `%IDENTIFIER%` with the identifier of the API you created in step 3 above. + To test `/api` routes, generate a test token using the CLI. ```shell auth0 test token \ @@ -173,7 +173,9 @@ Your application should now be accessible from your browser at [http://localhost --scopes "read:messages" ``` - You can now make requests to your application's API routes by providing the test token as a header in the request. Substitute `%TOKEN%` with the token returned by the previous step. +

Substitute %IDENTIFIER% with the identifier of the API you created in step 3 above.

+ + With this, you can make requests to your application's API routes by including the token as a header in requests. ```shell curl --request GET \ @@ -182,6 +184,8 @@ Your application should now be accessible from your browser at [http://localhost --header 'Authorization: Bearer %TOKEN%' ``` +

Substitute %TOKEN% with the test token returned in the previous step./small>

+
Using Windows PowerShell   From 18eb50c6635775fb5645087bb50da87c35e673e2 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 18:41:29 -0500 Subject: [PATCH 444/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 403b12fd..32dee381 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,7 @@ Your application should now be accessible from your browser at [http://localhost --header 'Authorization: Bearer %TOKEN%' ``` -

Substitute %TOKEN% with the test token returned in the previous step./small>

+

Substitute %TOKEN% with the test token returned in the previous step.

Using Windows PowerShell From 518f1e8ed02cfe031aacd1d9c77ac7b096bfdaf8 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 18:42:27 -0500 Subject: [PATCH 445/525] Update Deployment.md --- docs/Deployment.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/Deployment.md b/docs/Deployment.md index c02cf7d2..9dd6160a 100644 --- a/docs/Deployment.md +++ b/docs/Deployment.md @@ -49,22 +49,22 @@ Please ensure, like all the example configurations provided below, that your web ```nginx example.com { - root * /var/www/example.com/public + root * /var/www/example.com/public - encode zstd gzip - file_server + encode zstd gzip + file_server - limits { - header 4kb - } + limits { + header 4kb + } - header { - X-XSS-Protection "1; mode=block" - X-Content-Type-Options "nosniff" - X-Frame-Options "SAMEORIGIN" - } + header { + X-XSS-Protection "1; mode=block" + X-Content-Type-Options "nosniff" + X-Frame-Options "SAMEORIGIN" + } - php_fastcgi unix//var/run/php/php8.1-fpm.sock + php_fastcgi unix//var/run/php/php8.1-fpm.sock } ``` From e3dc64b63454e42e16c9772dec30d2cc8b2e806a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 18:52:47 -0500 Subject: [PATCH 446/525] Update README.md --- README.md | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 32dee381..47cae9c7 100644 --- a/README.md +++ b/README.md @@ -206,9 +206,7 @@ For guidance on moving your application to production, see [our deployment guide User Authentication   -The SDK automatically registers all the necessary authentication services within the `web` middleware group for your application. Once you have [configured the SDK](./docs/Management.md#api-application-authorization) your users will be able to authenticate with your application using Auth0. - -The SDK automatically registers the following routes to facilitate authentication: +The SDK automatically registers all the necessary routes and authentication services within the `web` middleware group of your application to enable users to authenticate without requiring you to write any code. | Route | Purpose | | ----------- | ---------------------------------- | @@ -216,8 +214,7 @@ The SDK automatically registers the following routes to facilitate authenticatio | `/logout` | Logs the user out. | | `/callback` | Handles the callback from Auth0. | -> **Note** -> See [the configuration guide](./docs/Configuration.md#authentication-routes) for information on customizing this behavior. +If these routes conflict with your application architecture, you can override this default behavior by [adjusting the SDK configuration](./docs/Configuration.md#route-registration). --- @@ -253,8 +250,7 @@ Route::get('/scope', function () { })->middleware('auth')->can('read:messages'); ``` -> **Note** -> Permissions require that [RBAC](https://auth0.com/docs/manage-users/access-control/rbac) be enabled within [your API settings](https://manage.auth0.com/#/apis). +Permissions require that [RBAC](https://auth0.com/docs/manage-users/access-control/rbac) be enabled within [your API settings](https://manage.auth0.com/#/apis). --- @@ -264,9 +260,9 @@ Route::get('/scope', function () { Users and Tokens   -Laravel's `Auth` Facade (or the `auth()` global helper) can be used to retrieve information about the authenticated user, or the access token used to authorize the request. +Laravel's `Auth` Facade can be used to retrieve information about the authenticated user or token associated with a request. -For example, for routes using the `web` middleware group in `routes/web.php`: +For routes using the `web` middleware group in `routes/web.php`: ```php Route::get('/', function () { @@ -282,7 +278,7 @@ Route::get('/', function () { }); ``` -Alternatively, for routes using the `api` middleware group in `routes/api.php`: +For routes using the `api` middleware group in `routes/api.php`: ```php Route::get('/', function () { @@ -308,9 +304,9 @@ Route::get('/', function () { Management API Calls   -Once you've [authorized your application to make Management API calls](./docs/Management.md#api-application-authorization), you'll be able to engage nearly any of the [Auth0 Management API endpoints](https://auth0.com/docs/api/management/v2) using the SDK. +Once you've [authorized your application to make Management API calls](./docs/Management.md#api-application-authorization), you'll be able to engage nearly any of the [Auth0 Management API endpoints](https://auth0.com/docs/api/management/v2) through the SDK. -Each endpoint has its own Management API class, all of which can be accessed through the Facade's `management()` method. API responses are returned as [PSR-7 messages](https://www.php-fig.org/psr/psr-7/), and can be converted into native arrays using the SDK's `json()` method. +Each API endpoint has its own SDK class which can be accessed through the Facade's `management()` factory method. For interoperability, network responses from the API are returned as [PSR-7 messages](https://www.php-fig.org/psr/psr-7/). These can be converted into native arrays using the SDK's `json()` method. For example, to update a user's metadata, you can call the `management()->users()->update()` method: @@ -355,6 +351,7 @@ All the SDK's Management API methods are [documented here](./docs/Management.md) - [Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2). - [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent). - [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. +- [Deployment](./docs/Deployment.md) — Deploying your application to production. - [Octane](./docs/Octane.md) — We do not support using the SDK with [Octane](https://laravel.com/docs/octane) at this time. You may also find the following resources helpful: From b6659372f4d247c8744e157de4684f066c3f392d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 18:57:35 -0500 Subject: [PATCH 447/525] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 47cae9c7..f696d5ee 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@

+**The Auth0 Laravel SDK is a Laravel package that allows you to effortlessly add support for [Auth0](https://auth0.com) to your application.** The SDK enables developers to add user authentication to their apps without writing any code, interact with the extensive Management API, implement permissions-based access control to routes, and more. + - [Requirements](#requirements) - [Getting Started](#getting-started) - [1. Install the SDK](#1-install-the-sdk) From 75177ca5e7ea1ce49372b9003b2e7f4cf29c463e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 19:01:32 -0500 Subject: [PATCH 448/525] Update README.md --- README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index f696d5ee..8bd47f7c 100644 --- a/README.md +++ b/README.md @@ -44,19 +44,19 @@ The following is our recommended approach to getting started with the SDK. Alter ### 1. Install the SDK -- For **new applications**, we offer a quickstart template — a version of the default Laravel 9 starter project pre-configured for use with the Auth0 SDK: +- For **new applications**, we offer a quickstart template — a version of the default Laravel 9 starter project pre-configured for use with the Auth0 SDK. ```shell composer create-project auth0-samples/laravel auth0-laravel-app && cd auth0-laravel-app ``` -- For **existing applications**, you can install the SDK using Composer: +- For **existing applications**, you can install the SDK using Composer. ```shell composer require auth0/login:^7.9 --update-with-all-dependencies ``` - In this case, you will also need to generate an SDK configuration file for your application: + In this case, you will also need to generate an SDK configuration file for your application. ```shell php artisan vendor:publish --tag auth0 @@ -66,7 +66,7 @@ The following is our recommended approach to getting started with the SDK. Alter ### 2. Install the CLI -1. Install the [Auth0 CLI](https://github.com/auth0/auth0-cli) to manage your account from the command line: +1. Install the [Auth0 CLI](https://github.com/auth0/auth0-cli) to manage your account from the command line. ```shell curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . @@ -102,7 +102,7 @@ The following is our recommended approach to getting started with the SDK. Alter ### 3. Configure the SDK -1. Register a new application with Auth0: +1. Register a new application with Auth0. ```shell auth0 apps create \ @@ -116,7 +116,7 @@ The following is our recommended approach to getting started with the SDK. Alter --json > .auth0.app.json ``` -2. Register a new API with Auth0: +2. Register a new API with Auth0. ```shell auth0 apis create \ @@ -127,7 +127,7 @@ The following is our recommended approach to getting started with the SDK. Alter --json > .auth0.api.json ``` -3. Add the new files to `.gitignore`: +3. Add the new files to `.gitignore`. ```bash echo ".auth0.*.json" >> .gitignore @@ -155,7 +155,7 @@ The following is our recommended approach to getting started with the SDK. Alter ### 4. Run the Application -You can now run the application using the built-in PHP web server: +You can now run the application using the built-in PHP web server. ```shell php artisan serve @@ -228,7 +228,7 @@ If these routes conflict with your application architecture, you can override th The SDK automatically registers its authentication and authorization guards within the `web` and `api` middleware groups for your Laravel application, respectively. -For `web` routes, you can use Laravel's `auth` middleware to require that a user be authenticated to access a route: +For `web` routes, you can use Laravel's `auth` middleware to require that a user be authenticated to access a route. ```php Route::get('/private', function () { @@ -236,7 +236,7 @@ Route::get('/private', function () { })->middleware('auth'); ``` -For `api` routes, you can use Laravel's `auth` middleware to require that a request be authenticated with a valid bearer token to access a route: +For `api` routes, you can use Laravel's `auth` middleware to require that a request be authenticated with a valid bearer token to access a route. ```php Route::get('/api/private', function () { @@ -244,7 +244,7 @@ Route::get('/api/private', function () { })->middleware('auth'); ``` -In addition to requiring that a user be authenticated, you can also require that the user have specific permissions to access a route, using Laravel's `can` middleware: +In addition to requiring that a user be authenticated, you can also require that the user have specific permissions to access a route, using Laravel's `can` middleware. ```php Route::get('/scope', function () { @@ -264,7 +264,7 @@ Permissions require that [RBAC](https://auth0.com/docs/manage-users/access-contr Laravel's `Auth` Facade can be used to retrieve information about the authenticated user or token associated with a request. -For routes using the `web` middleware group in `routes/web.php`: +For routes using the `web` middleware group in `routes/web.php`. ```php Route::get('/', function () { @@ -280,7 +280,7 @@ Route::get('/', function () { }); ``` -For routes using the `api` middleware group in `routes/api.php`: +For routes using the `api` middleware group in `routes/api.php`. ```php Route::get('/', function () { @@ -310,7 +310,7 @@ Once you've [authorized your application to make Management API calls](./docs/Ma Each API endpoint has its own SDK class which can be accessed through the Facade's `management()` factory method. For interoperability, network responses from the API are returned as [PSR-7 messages](https://www.php-fig.org/psr/psr-7/). These can be converted into native arrays using the SDK's `json()` method. -For example, to update a user's metadata, you can call the `management()->users()->update()` method: +For example, to update a user's metadata, you can call the `management()->users()->update()` method. ```php use Auth0\Laravel\Facade\Auth0; From be38408670c5289ca489bde0ff79913db33a02cd Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 19:08:08 -0500 Subject: [PATCH 449/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8bd47f7c..521e34bc 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@

-**The Auth0 Laravel SDK is a Laravel package that allows you to effortlessly add support for [Auth0](https://auth0.com) to your application.** The SDK enables developers to add user authentication to their apps without writing any code, interact with the extensive Management API, implement permissions-based access control to routes, and more. +**The Auth0 Laravel SDK is a PHP package that fully integrates support for [Auth0](https://auth0.com) into your Laravel application.** It enables zero code user authentication, full support for the extensive Management API, supports permissions-based access control for routes, and more. - [Requirements](#requirements) - [Getting Started](#getting-started) From 353ce5c08cb313f68ce9845fa2a03ba48ebadd8c Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 19:08:50 -0500 Subject: [PATCH 450/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 521e34bc..bd0faaff 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@

-**The Auth0 Laravel SDK is a PHP package that fully integrates support for [Auth0](https://auth0.com) into your Laravel application.** It enables zero code user authentication, full support for the extensive Management API, supports permissions-based access control for routes, and more. +**The Auth0 Laravel SDK is a PHP package that integrates [Auth0](https://auth0.com) into your Laravel application.** It includes zero code user authentication, full support for the extensive Management API, permissions-based access control for routes, and more. - [Requirements](#requirements) - [Getting Started](#getting-started) From 6678b0e0a7a423baf86b60fd6fcc735f9205d040 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 19:14:46 -0500 Subject: [PATCH 451/525] Update README.md --- README.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index bd0faaff..f753744d 100644 --- a/README.md +++ b/README.md @@ -155,19 +155,19 @@ The following is our recommended approach to getting started with the SDK. Alter ### 4. Run the Application -You can now run the application using the built-in PHP web server. +Boot the application using PHP's built-in web server. ```shell php artisan serve ``` -Your application should now be accessible from your browser at [http://localhost:8000](http://localhost:8000). +Direct your browser to [http://localhost:8000](http://localhost:8000) to experiment with the application. -- **Testing Authentication** - You can log in or out by visiting the [`/login`](http://localhost:8000/login) or [`/logout`](http://localhost:8000/logout) routes, respectively. +- **Authentication** + Users can log in or out of the application by visiting the [`/login`](http://localhost:8000/login) or [`/logout`](http://localhost:8000/logout) routes, respectively. -- **Testing API Authorization** - To test `/api` routes, generate a test token using the CLI. +- **API Authorization** + For simplicity sake, generate a test token using the CLI. ```shell auth0 test token \ @@ -176,8 +176,8 @@ Your application should now be accessible from your browser at [http://localhost ```

Substitute %IDENTIFIER% with the identifier of the API you created in step 3 above.

- - With this, you can make requests to your application's API routes by including the token as a header in requests. + + Now you can send requests to the `/api` endpoints of the application, including the token as a header. ```shell curl --request GET \ @@ -199,8 +199,7 @@ Your application should now be accessible from your browser at [http://localhost
-- **Deploying to Production** -For guidance on moving your application to production, see [our deployment guide](./docs/Deployment.md). +When you're ready to deploy your application to production, review [our deployment guide](./docs/Deployment.md) for best practices and advice on securing Laravel. ## Integration Examples From fe583c503005d5be2d2c56ffb7e2b2a1c0be90c5 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 19:18:43 -0500 Subject: [PATCH 452/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f753744d..db1948de 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@

-**The Auth0 Laravel SDK is a PHP package that integrates [Auth0](https://auth0.com) into your Laravel application.** It includes zero code user authentication, full support for the extensive Management API, permissions-based access control for routes, and more. +**The Auth0 Laravel SDK is a PHP package that integrates [Auth0](https://auth0.com) into your Laravel application.** It includes zero-code user authentication, full support for the extensive Management API, permissions-based access control for routes, and more. - [Requirements](#requirements) - [Getting Started](#getting-started) From 6a2c18e265c51673dfccc072076ed844ddcf3ea1 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 19:19:17 -0500 Subject: [PATCH 453/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index db1948de..d07438a8 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@

-**The Auth0 Laravel SDK is a PHP package that integrates [Auth0](https://auth0.com) into your Laravel application.** It includes zero-code user authentication, full support for the extensive Management API, permissions-based access control for routes, and more. +**The Auth0 Laravel SDK is a PHP package that integrates [Auth0](https://auth0.com) into your Laravel application.** It includes no-code user authentication, full support for the extensive Management API, permissions-based access control for routes, and more. - [Requirements](#requirements) - [Getting Started](#getting-started) From 7eb3760d336a2db1ee842815b6392a3e92fb4745 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 19:19:51 -0500 Subject: [PATCH 454/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d07438a8..5544a7fe 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@

-**The Auth0 Laravel SDK is a PHP package that integrates [Auth0](https://auth0.com) into your Laravel application.** It includes no-code user authentication, full support for the extensive Management API, permissions-based access control for routes, and more. +**The Auth0 Laravel SDK is a PHP package that integrates [Auth0](https://auth0.com) into your Laravel application.** It includes no-code user authentication, extensive Management API support, permissions-based routing access control, and more. - [Requirements](#requirements) - [Getting Started](#getting-started) From 1da147b7803706727304b8be6f30bdb80a5acab8 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 19:35:16 -0500 Subject: [PATCH 455/525] Update Configuration.md --- docs/Configuration.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/Configuration.md b/docs/Configuration.md index f9ea06ae..a3160458 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -88,6 +88,35 @@ The following environment variables are supported, but should not be adjusted un ### Order of Priority +The SDK compiles configuration data from multiple potential sources, in the following order: + +- `.auth0.json` files +- `.env` (dotenv) files +- Host environment variables + +> **Note:** +> In the filenames listed below, `%APP_ENV%` is replaced by the application's configured `APP_ENV` environment variable, if one is set. + +It begins by loading matching JSON configuration files from the project's root directory, in the following order: + +- `.auth0.json` +- `.auth0.%APP_ENV%.json` +- `.auth0.api.json` +- `.auth0.app.json` +- `.auth0.api.%APP_ENV%.json` +- `.auth0.app.%APP_ENV%.json` + +It then loads configuration data from available `.env` (dotenv) configuration files, in the following order. + +- `.env` +- `.env.auth0` +- `.env.%APP_ENV%` +- `.env.%APP_ENV%.auth0` + +Finally, it loads environment variables from the host environment. + +Note that duplicate configuration keys will be overwritten by the last value loaded, so the host environment variables will always override any matching values set in JSON or dotenv files. + ### Default Behavior #### Guard Registration From e91262d29a273fe4ae6f38c1e6fb0bf9441c4c8e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 19:37:54 -0500 Subject: [PATCH 456/525] Update Configuration.md --- docs/Configuration.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index a3160458..64539ea9 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -88,7 +88,7 @@ The following environment variables are supported, but should not be adjusted un ### Order of Priority -The SDK compiles configuration data from multiple potential sources, in the following order: +The SDK collects configuration data from multiple potential sources, in the following order: - `.auth0.json` files - `.env` (dotenv) files @@ -115,7 +115,9 @@ It then loads configuration data from available `.env` (dotenv) configuration fi Finally, it loads environment variables from the host environment. -Note that duplicate configuration keys will be overwritten by the last value loaded, so the host environment variables will always override any matching values set in JSON or dotenv files. +Duplicate configuration data is overwritten by the value from the last source loaded. For example, if the `AUTH0_DOMAIN` environment variable is set in both the `.env` file and the host environment, the value from the host environment will be used. + +Although JSON configuration keys are different from their associated environment variable counterparts, these are translated automatically by the SDK. For example, the `domain` key in the JSON configuration files is translated to the `AUTH0_DOMAIN` environment variable. ### Default Behavior From c7e5cf198c86cb5d20aa123dbd459790b96a3cb0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 19:39:39 -0500 Subject: [PATCH 457/525] Update Configuration.md --- docs/Configuration.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/Configuration.md b/docs/Configuration.md index 64539ea9..f21700fc 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -127,6 +127,13 @@ By default, the SDK will register the Authentication and Authorization guards wi You can disable this behavior by setting `registerGuards` to `false` in your `config/auth0.php` file. +```php +return Configuration::VERSION_2 + [ + 'registerGuards' => false, + // ... +]; +``` + To register the guards manually, update the arrays in your `config/auth.php` file to include the following additions: ```php @@ -157,6 +164,13 @@ By default, the SDK will register the Authentication and Authorization guards wi You can disable this behavior by setting `registerMiddleware` to `false` in your `config/auth0.php` file. +```php +return Configuration::VERSION_2 + [ + 'registerMiddleware' => false, + // ... +]; +``` + To register the middleware manually, update your `app/Http/Kernel.php` file and include the following additions: ```php @@ -199,6 +213,13 @@ By default, the SDK will register the following routes for authentication: You can disable this behavior by setting `registerAuthenticationRoutes` to `false` in your `config/auth0.php` file. +```php +return Configuration::VERSION_2 + [ + 'registerAuthenticationRoutes' => false, + // ... +]; +``` + If you've disabled the automatic registration of routes, you must register the routes manually for authentication to work. ```php From 6913d568eb572fa914be260c243e97f0ac854aeb Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 19:42:04 -0500 Subject: [PATCH 458/525] Update Configuration.md --- docs/Configuration.md | 68 +++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index f21700fc..37d24e90 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -26,7 +26,7 @@ This guide addresses v2 of the SDK configuration format. You can determine which ```php return Configuration::VERSION_2 + [ - // ... + // ... ]; ``` @@ -129,8 +129,8 @@ You can disable this behavior by setting `registerGuards` to `false` in your `co ```php return Configuration::VERSION_2 + [ - 'registerGuards' => false, - // ... + 'registerGuards' => false, + // ... ]; ``` @@ -138,23 +138,23 @@ To register the guards manually, update the arrays in your `config/auth.php` fil ```php 'guards' => [ - 'auth0-session' => [ - 'driver' => 'auth0.authenticator', - 'provider' => 'auth0-provider', - 'configuration' => 'web', - ], - 'auth0-api' => [ - 'driver' => 'auth0.authorizer', - 'provider' => 'auth0-provider', - 'configuration' => 'api', - ], + 'auth0-session' => [ + 'driver' => 'auth0.authenticator', + 'provider' => 'auth0-provider', + 'configuration' => 'web', + ], + 'auth0-api' => [ + 'driver' => 'auth0.authorizer', + 'provider' => 'auth0-provider', + 'configuration' => 'api', + ], ], 'providers' => [ - 'auth0-provider' => [ - 'driver' => 'auth0.provider', - 'repository' => 'auth0.repository', - ], + 'auth0-provider' => [ + 'driver' => 'auth0.provider', + 'repository' => 'auth0.repository', + ], ], ``` @@ -166,8 +166,8 @@ You can disable this behavior by setting `registerMiddleware` to `false` in your ```php return Configuration::VERSION_2 + [ - 'registerMiddleware' => false, - // ... + 'registerMiddleware' => false, + // ... ]; ``` @@ -175,17 +175,15 @@ To register the middleware manually, update your `app/Http/Kernel.php` file and ```php protected $middlewareGroups = [ - 'web' => [ - // ... - \Auth0\Laravel\Middleware\AuthenticatorMiddleware::class, - // ... - ], - - 'api' => [ - // ... - \Auth0\Laravel\Middleware\AuthorizerMiddleware::class, - // ... - ], + 'web' => [ + \Auth0\Laravel\Middleware\AuthenticatorMiddleware::class, + // ... + ], + + 'api' => [ + \Auth0\Laravel\Middleware\AuthorizerMiddleware::class, + // ... + ], ]; ``` @@ -215,8 +213,8 @@ You can disable this behavior by setting `registerAuthenticationRoutes` to `fals ```php return Configuration::VERSION_2 + [ - 'registerAuthenticationRoutes' => false, - // ... + 'registerAuthenticationRoutes' => false, + // ... ]; ``` @@ -226,9 +224,9 @@ If you've disabled the automatic registration of routes, you must register the r use Auth0\Laravel\Controllers\{LoginController, LogoutController, CallbackController}; Route::group(['middleware' => ['guard:auth0-session'], static function (): void { - Route::get('/login', LoginController::class)->name('login'); - Route::get('/logout', LogoutController::class)->name('logout'); - Route::get('/callback', CallbackController::class)->name('callback'); + Route::get('/login', LoginController::class)->name('login'); + Route::get('/logout', LogoutController::class)->name('logout'); + Route::get('/callback', CallbackController::class)->name('callback'); }); ``` From ae1a0fd789c0abeefffb6dbaeabe0c475002e397 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 19:57:04 -0500 Subject: [PATCH 459/525] Update README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 5544a7fe..c3510fb7 100644 --- a/README.md +++ b/README.md @@ -28,13 +28,13 @@ Your application must use a [supported Laravel version](https://laravelversions.com/en), and your host environment must be running a [supported PHP version](https://www.php.net/supported-versions.php). Please review [our support policy](./docs/Support.md) for more information. -| SDK | Laravel | PHP | Supported Until | -| ---- | ------- | ---- | --------------- | -| 7.5+ | 10 | 8.2+ | Feb 2025 | -| | | 8.1+ | Nov 2024 | -| 7.0+ | 9 | 8.2+ | Feb 2024 | -| | | 8.1+ | Feb 2024 | -| | | 8.0+ | Nov 2023 | +| SDK | Laravel | PHP | Supported Until | +| ---- | -------------------------------------------- | ----------------------------------------------- | --------------- | +| 7.5+ | [10](https://laravel.com/docs/10.x/releases) | [8.2+](https://www.php.net/releases/8.2/en.php) | Feb 2025 | +| | | [8.1+](https://www.php.net/releases/8.1/en.php) | Nov 2024 | +| 7.0+ | [9](https://laravel.com/docs/9.x/releases) | [8.2+](https://www.php.net/releases/8.2/en.php) | Feb 2024 | +| | | [8.1+](https://www.php.net/releases/8.1/en.php) | Feb 2024 | +| | | [8.0+](https://www.php.net/releases/8.0/en.php) | Nov 2023 | You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). From 887839313b66ca302e2a8f72c8883424cd509e80 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 19:57:44 -0500 Subject: [PATCH 460/525] Update README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c3510fb7..e6966d98 100644 --- a/README.md +++ b/README.md @@ -28,13 +28,13 @@ Your application must use a [supported Laravel version](https://laravelversions.com/en), and your host environment must be running a [supported PHP version](https://www.php.net/supported-versions.php). Please review [our support policy](./docs/Support.md) for more information. -| SDK | Laravel | PHP | Supported Until | -| ---- | -------------------------------------------- | ----------------------------------------------- | --------------- | -| 7.5+ | [10](https://laravel.com/docs/10.x/releases) | [8.2+](https://www.php.net/releases/8.2/en.php) | Feb 2025 | -| | | [8.1+](https://www.php.net/releases/8.1/en.php) | Nov 2024 | -| 7.0+ | [9](https://laravel.com/docs/9.x/releases) | [8.2+](https://www.php.net/releases/8.2/en.php) | Feb 2024 | -| | | [8.1+](https://www.php.net/releases/8.1/en.php) | Feb 2024 | -| | | [8.0+](https://www.php.net/releases/8.0/en.php) | Nov 2023 | +| SDK | Laravel | PHP | Supported Until | +| ---- | ---------------------------------------------- | ----------------------------------------------- | --------------- | +| 7.5+ | [10.x](https://laravel.com/docs/10.x/releases) | [8.2+](https://www.php.net/releases/8.2/en.php) | Feb 2025 | +| | | [8.1+](https://www.php.net/releases/8.1/en.php) | Nov 2024 | +| 7.0+ | [9.x](https://laravel.com/docs/9.x/releases) | [8.2+](https://www.php.net/releases/8.2/en.php) | Feb 2024 | +| | | [8.1+](https://www.php.net/releases/8.1/en.php) | Feb 2024 | +| | | [8.0+](https://www.php.net/releases/8.0/en.php) | Nov 2023 | You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). From cdc2fe8d5014bc7af845524c8f3b71779a24ea0b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 28 Jun 2023 20:09:48 -0500 Subject: [PATCH 461/525] Update README.md --- README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e6966d98..a6fd9ee3 100644 --- a/README.md +++ b/README.md @@ -70,9 +70,16 @@ The following is our recommended approach to getting started with the SDK. Alter ```shell curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . + ``` + + Move the CLI to a directory in your `PATH` to make it available system-wide. + + ```shell sudo mv ./auth0 /usr/local/bin ``` +

💡 If you prefer not to move the CLI, simply substitute `auth0` in the CLI steps below with `./auth0`.

+
Using Homebrew (macOS)   @@ -94,7 +101,7 @@ The following is our recommended approach to getting started with the SDK. Alter
-2. Authenticate the CLI with your Auth0 account. Choose "as a user," and follow the prompts. +2. Authenticate the CLI with your Auth0 account. Choose "as a user" if prompted. ```shell auth0 login @@ -175,7 +182,7 @@ Direct your browser to [http://localhost:8000](http://localhost:8000) to experim --scopes "read:messages" ``` -

Substitute %IDENTIFIER% with the identifier of the API you created in step 3 above.

+

Substitute %IDENTIFIER% with the identifier of the API you created in step 3 above.

Now you can send requests to the `/api` endpoints of the application, including the token as a header. @@ -186,7 +193,7 @@ Direct your browser to [http://localhost:8000](http://localhost:8000) to experim --header 'Authorization: Bearer %TOKEN%' ``` -

Substitute %TOKEN% with the test token returned in the previous step.

+

Substitute %TOKEN% with the test token returned in the previous step.

Using Windows PowerShell From 6060c9a6fe2cd051d30c5ae42eb91cbc7de2c82a Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Wed, 5 Jul 2023 15:43:31 +1000 Subject: [PATCH 462/525] Refactor unit tests to include testing the find() method (#421) --- tests/Unit/Guards/AuthenticationGuardTest.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/Unit/Guards/AuthenticationGuardTest.php b/tests/Unit/Guards/AuthenticationGuardTest.php index 834fef9f..97e7c589 100644 --- a/tests/Unit/Guards/AuthenticationGuardTest.php +++ b/tests/Unit/Guards/AuthenticationGuardTest.php @@ -64,16 +64,15 @@ }); }); -it('gets a user from a valid session using find()', function (): void { - getJson($this->route) - ->assertStatus(Response::HTTP_OK); +it('retrieves the authenticated user from a valid session using find()', function (): void { + $result = $this->guard->find(); - expect($this->guard) - ->user()->getAuthIdentifier()->toBe('hello|world'); + expect($result)->toBeInstanceOf(CredentialEntity::class); + expect($result->getUser())->toBeInstanceOf(StatefulUser::class); }); -it('gets a user from a valid session using user()', function (): void { - getJson($this->route2) +it('retrieves the authenticated user from a valid session using user()', function (): void { + getJson($this->route) ->assertStatus(Response::HTTP_OK); expect($this->guard) From 1a3d56b6a6142d9e6d2448d71f02de5945281551 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 5 Jul 2023 00:44:03 -0500 Subject: [PATCH 463/525] Restore code coverage to 100% --- tests/Unit/Guards/AuthenticationGuardTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Unit/Guards/AuthenticationGuardTest.php b/tests/Unit/Guards/AuthenticationGuardTest.php index 97e7c589..9796c5fa 100644 --- a/tests/Unit/Guards/AuthenticationGuardTest.php +++ b/tests/Unit/Guards/AuthenticationGuardTest.php @@ -69,6 +69,8 @@ expect($result)->toBeInstanceOf(CredentialEntity::class); expect($result->getUser())->toBeInstanceOf(StatefulUser::class); + + expect($this->guard->user()->getAuthIdentifier())->toBe('hello|world'); }); it('retrieves the authenticated user from a valid session using user()', function (): void { From 7d175e4ab7fc37f8fb53d2e135e320e0ba24284e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 5 Jul 2023 01:17:02 -0500 Subject: [PATCH 464/525] Restore `pushMiddleware()` call --- src/ServiceProviderAbstract.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ServiceProviderAbstract.php b/src/ServiceProviderAbstract.php index 3d444f43..fea7dd29 100644 --- a/src/ServiceProviderAbstract.php +++ b/src/ServiceProviderAbstract.php @@ -19,6 +19,7 @@ use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; +use function defined; use function is_string; /** @@ -204,9 +205,15 @@ final public function registerMiddleware( ): void { if (true === config('auth0.registerMiddleware')) { $kernel = $this->app->make(Kernel::class); + /** * @var \Illuminate\Foundation\Http\Kernel $kernel */ + if (! defined('AUTH0_LARAVEL_RUNNING_TESTS')) { + $kernel->pushMiddleware(AuthenticatorMiddleware::class); + $kernel->pushMiddleware(AuthorizerMiddleware::class); + } + $kernel->appendMiddlewareToGroup('web', AuthenticatorMiddleware::class); $kernel->appendMiddlewareToGroup('api', AuthorizerMiddleware::class); From ddcf6f7ec21d06b4fbd54ab674f8d7c109fdfb36 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 5 Jul 2023 01:20:15 -0500 Subject: [PATCH 465/525] Update ServiceProviderAbstract.php --- src/ServiceProviderAbstract.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/ServiceProviderAbstract.php b/src/ServiceProviderAbstract.php index fea7dd29..659df976 100644 --- a/src/ServiceProviderAbstract.php +++ b/src/ServiceProviderAbstract.php @@ -19,7 +19,6 @@ use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; -use function defined; use function is_string; /** @@ -209,10 +208,6 @@ final public function registerMiddleware( /** * @var \Illuminate\Foundation\Http\Kernel $kernel */ - if (! defined('AUTH0_LARAVEL_RUNNING_TESTS')) { - $kernel->pushMiddleware(AuthenticatorMiddleware::class); - $kernel->pushMiddleware(AuthorizerMiddleware::class); - } $kernel->appendMiddlewareToGroup('web', AuthenticatorMiddleware::class); $kernel->appendMiddlewareToGroup('api', AuthorizerMiddleware::class); From 5184e687fbf82f42e9aae31fbd421c0041459dfc Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 5 Jul 2023 01:20:29 -0500 Subject: [PATCH 466/525] Update ServiceProviderAbstract.php --- src/ServiceProviderAbstract.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ServiceProviderAbstract.php b/src/ServiceProviderAbstract.php index 659df976..3a212746 100644 --- a/src/ServiceProviderAbstract.php +++ b/src/ServiceProviderAbstract.php @@ -208,7 +208,6 @@ final public function registerMiddleware( /** * @var \Illuminate\Foundation\Http\Kernel $kernel */ - $kernel->appendMiddlewareToGroup('web', AuthenticatorMiddleware::class); $kernel->appendMiddlewareToGroup('api', AuthorizerMiddleware::class); From 38a550752af37c302c85f245b5636f559c14fbae Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 5 Jul 2023 02:00:27 -0500 Subject: [PATCH 467/525] fix: Ignore default AUTH0_ dotenv values (#422) --- src/Configuration.php | 19 ++++++++++++++++++- tests/Unit/ConfigurationTest.php | 23 +++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/Configuration.php b/src/Configuration.php index b1cf026d..c7a27ece 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -557,7 +557,24 @@ private static function getValue( } else { $env = 'AUTH0_' . strtoupper(Str::snake($setting)); $json = self::CONFIG_AUDIENCE === $setting ? 'identifier' : Str::snake($setting); - $value = $_ENV[$env] ?? self::getEnvironment()[$env] ?? self::getJson()[$json] ?? $default; + + $value = getenv($env); + + if (! is_string($value)) { + $value = null; + } + + $value ??= self::getEnvironment()[$env] ?? null; + + $value = match ($setting) { + self::CONFIG_DOMAIN => '{DOMAIN}' === $value ? null : $value, + self::CONFIG_CLIENT_ID => '{CLIENT_ID}' === $value ? null : $value, + self::CONFIG_CLIENT_SECRET => '{CLIENT_SECRET}' === $value ? null : $value, + self::CONFIG_AUDIENCE => '{API_IDENTIFIER}' === $value ? null : $value, + default => $value, + }; + + $value ??= self::getJson()[$json] ?? $default; } if (! is_string($value) && ! is_array($value) && ! is_bool($value) && ! is_int($value)) { diff --git a/tests/Unit/ConfigurationTest.php b/tests/Unit/ConfigurationTest.php index 8911b96a..f654d5ca 100644 --- a/tests/Unit/ConfigurationTest.php +++ b/tests/Unit/ConfigurationTest.php @@ -83,6 +83,29 @@ ->toBeNull(); }); +test('get() ignores quickstart placeholders', function (): void { + putenv('AUTH0_DOMAIN={DOMAIN}'); + putenv('AUTH0_CLIENT_ID={CLIENT_ID}'); + putenv('AUTH0_CLIENT_SECRET={CLIENT_SECRET}'); + putenv('AUTH0_AUDIENCE={API_IDENTIFIER}'); + putenv('AUTH0_CUSTOM_DOMAIN=https://example.com'); + + expect(Configuration::get(Configuration::CONFIG_CUSTOM_DOMAIN)) + ->toBeString('https://example.com/'); + + expect(Configuration::get(Configuration::CONFIG_DOMAIN)) + ->toBeNull(); + + expect(Configuration::get(Configuration::CONFIG_CLIENT_ID)) + ->toBeNull(); + + expect(Configuration::get(Configuration::CONFIG_CLIENT_SECRET)) + ->toBeNull(); + + expect(Configuration::get(Configuration::CONFIG_AUDIENCE)) + ->toBeNull(); +}); + test('get() behaves as expected', function (): void { config(['test' => [ Configuration::CONFIG_AUDIENCE => implode(',', [uniqid(), uniqid()]), From 91477dbb792e5b35f71308376ba8f2b4a235d54d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 5 Jul 2023 03:23:56 -0500 Subject: [PATCH 468/525] fix: Inject Guards into MiddlewarePriority manifest (#423) --- src/ServiceProviderAbstract.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ServiceProviderAbstract.php b/src/ServiceProviderAbstract.php index 3a212746..c3b48b25 100644 --- a/src/ServiceProviderAbstract.php +++ b/src/ServiceProviderAbstract.php @@ -209,10 +209,10 @@ final public function registerMiddleware( * @var \Illuminate\Foundation\Http\Kernel $kernel */ $kernel->appendMiddlewareToGroup('web', AuthenticatorMiddleware::class); - $kernel->appendMiddlewareToGroup('api', AuthorizerMiddleware::class); + $kernel->prependToMiddlewarePriority(AuthenticatorMiddleware::class); - $router->pushMiddlewareToGroup('web', AuthenticatorMiddleware::class); - $router->pushMiddlewareToGroup('api', AuthorizerMiddleware::class); + $kernel->appendMiddlewareToGroup('api', AuthorizerMiddleware::class); + $kernel->prependToMiddlewarePriority(AuthorizerMiddleware::class); } } From 994b927e6520b5d2aa074cbe41d80b012188d06b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Jul 2023 01:40:47 -0500 Subject: [PATCH 469/525] Bump to 7.10.0 --- CHANGELOG.md | 19 +++++++++++++++++++ composer.json | 2 +- src/Entities/InstanceEntityAbstract.php | 2 +- src/ServiceAbstract.php | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22bf9ca0..85414d9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## [7.10.0](https://github.com/auth0/laravel-auth0/tree/7.9.1) (2023-07-24) + +### Added + +- Organization Name support added for Authentication API and token handling ¹ + +### Changed + +- Guards are now registered with the priority middleware list. +- Bumped `auth0-php` dependency version range to `^8.7`. +- Updated telemetry to indicate new `laravel` package name (previously `laravel-auth0`.) + +### Fixed + +- Addressed issue where placeholder `AUTH0_` dotenv values could erroneously be interpreted as true configuration values. + +> **Note** +> ¹ To use this feature, an Auth0 tenant must have support for it enabled. This feature is not yet available to all tenants. + ## [7.9.1](https://github.com/auth0/laravel-auth0/tree/7.9.1) (2023-06-21) ### Fixed diff --git a/composer.json b/composer.json index 23b441ab..5a6b83dc 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,7 @@ "require": { "php": "^8.0", "ext-json": "*", - "auth0/auth0-php": "^8.6", + "auth0/auth0-php": "^8.7", "illuminate/contracts": "^9 || ^10", "illuminate/http": "^9 || ^10", "illuminate/support": "^9 || ^10", diff --git a/src/Entities/InstanceEntityAbstract.php b/src/Entities/InstanceEntityAbstract.php index 73ac293f..deed06ba 100644 --- a/src/Entities/InstanceEntityAbstract.php +++ b/src/Entities/InstanceEntityAbstract.php @@ -285,7 +285,7 @@ protected function getTokenCachePool(): CacheItemPoolInterface protected function setSdkTelemetry(): self { HttpTelemetry::setEnvProperty('Laravel', app()->version()); - HttpTelemetry::setPackage('laravel-auth0', Service::VERSION); + HttpTelemetry::setPackage('laravel', Service::VERSION); return $this; } diff --git a/src/ServiceAbstract.php b/src/ServiceAbstract.php index 9be17d70..ca286d07 100644 --- a/src/ServiceAbstract.php +++ b/src/ServiceAbstract.php @@ -22,7 +22,7 @@ abstract class ServiceAbstract extends InstanceEntityAbstract * * @var string */ - public const VERSION = '7.9.1'; + public const VERSION = '7.10.0'; /** * Decode a PSR-7 HTTP Response Message containing a JSON content body to a PHP array. Returns null if the response was not successful, or the response body was not JSON. From a1e12a43cc2d2cfc10d75465c16d7f52d196ed8e Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Jul 2023 02:31:23 -0500 Subject: [PATCH 470/525] Bump to 7.10.0 --- CHANGELOG.md | 10 +++---- .../CallbackControllerAbstract.php | 27 ++++++++++++++++--- src/Guards/GuardAbstract.php | 4 +++ 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85414d9c..da28609c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,17 +4,17 @@ ### Added -- Organization Name support added for Authentication API and token handling ¹ +- Organization Name support added for Authentication API and token handling ¹ ### Changed -- Guards are now registered with the priority middleware list. -- Bumped `auth0-php` dependency version range to `^8.7`. -- Updated telemetry to indicate new `laravel` package name (previously `laravel-auth0`.) +- Guards are now registered with the priority middleware list. +- Bumped `auth0-php` dependency version range to `^8.7`. +- Updated telemetry to indicate new `laravel` package name (previously `laravel-auth0`.) ### Fixed -- Addressed issue where placeholder `AUTH0_` dotenv values could erroneously be interpreted as true configuration values. +- Addressed issue where placeholder `AUTH0_` dotenv values could erroneously be interpreted as true configuration values. > **Note** > ¹ To use this feature, an Auth0 tenant must have support for it enabled. This feature is not yet available to all tenants. diff --git a/src/Controllers/CallbackControllerAbstract.php b/src/Controllers/CallbackControllerAbstract.php index 758a73cb..b1f54de6 100644 --- a/src/Controllers/CallbackControllerAbstract.php +++ b/src/Controllers/CallbackControllerAbstract.php @@ -74,7 +74,7 @@ public function __invoke( event(new Failed($guard::class, $guard->user(), $credentials)); - $guard->sdk()->clear(); + $this->clearSession($guard, true, true, true); // Throw hookable $event to allow custom error handling scenarios. $event = new AuthenticationFailed($throwable, true); @@ -101,8 +101,7 @@ public function __invoke( 'error' => ['error' => $error, 'description' => $errorDescription], ])); - // Clear the local session via the Auth0-PHP SDK: - $guard->sdk()->clear(); + $this->clearSession($guard, true, true, true); // Create a dynamic exception to report the API error response $exception = new CallbackControllerException(sprintf(CallbackControllerException::MSG_API_RESPONSE, $error, $errorDescription)); @@ -131,6 +130,8 @@ public function __invoke( if ($credential instanceof CredentialEntityContract && $user instanceof Authenticatable) { event(new Validated($guard::class, $user)); + $this->clearSession($guard); + /** * @var Guard $guard */ @@ -151,4 +152,24 @@ public function __invoke( return redirect()->intended('/'); } + + private function clearSession( + GuardAbstract $guard, + $clearTransientStorage = true, + $clearPersistentStorage = true, + $clearSdkStorage = false + ): void + { + if ($clearTransientStorage) { + $guard->service()->getConfiguration()->getTransientStorage()->purge(); + } + + if ($clearPersistentStorage) { + $guard->service()->getConfiguration()->getSessionStorage()->purge(); + } + + if ($clearSdkStorage) { + $guard->sdk()->clear(); + } + } } diff --git a/src/Guards/GuardAbstract.php b/src/Guards/GuardAbstract.php index 7e2b30db..64ae1fb9 100644 --- a/src/Guards/GuardAbstract.php +++ b/src/Guards/GuardAbstract.php @@ -238,6 +238,10 @@ final public function sdk( return $this->sdk->getSdk(); } + final public function service(): InstanceEntityContract { + return $this->sdk; + } + final public function stopImpersonating(): void { $this->impersonating = null; From fbb6ee5f86228b97f0a5d5aa7036aea72a2409ee Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Jul 2023 02:36:58 -0500 Subject: [PATCH 471/525] Bump to 7.10.0 --- .../CallbackControllerAbstract.php | 19 ++++++++++--------- src/Guards/GuardAbstract.php | 3 ++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Controllers/CallbackControllerAbstract.php b/src/Controllers/CallbackControllerAbstract.php index b1f54de6..ce78b156 100644 --- a/src/Controllers/CallbackControllerAbstract.php +++ b/src/Controllers/CallbackControllerAbstract.php @@ -155,17 +155,18 @@ public function __invoke( private function clearSession( GuardAbstract $guard, - $clearTransientStorage = true, - $clearPersistentStorage = true, - $clearSdkStorage = false - ): void - { - if ($clearTransientStorage) { - $guard->service()->getConfiguration()->getTransientStorage()->purge(); + bool $clearTransientStorage = true, + bool $clearPersistentStorage = true, + bool $clearSdkStorage = false, + ): void { + $service = $guard->service() ?? null; + + if ($clearTransientStorage && null !== $service) { + $service->getConfiguration()->getTransientStorage()?->purge(); } - if ($clearPersistentStorage) { - $guard->service()->getConfiguration()->getSessionStorage()->purge(); + if ($clearPersistentStorage && null !== $service) { + $service->getConfiguration()->getSessionStorage()?->purge(); } if ($clearSdkStorage) { diff --git a/src/Guards/GuardAbstract.php b/src/Guards/GuardAbstract.php index 64ae1fb9..4e71107f 100644 --- a/src/Guards/GuardAbstract.php +++ b/src/Guards/GuardAbstract.php @@ -238,7 +238,8 @@ final public function sdk( return $this->sdk->getSdk(); } - final public function service(): InstanceEntityContract { + final public function service(): ?InstanceEntityContract + { return $this->sdk; } From dca454830dd6edd7f211ae17878ddc8c4b3d3f9b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Jul 2023 02:39:30 -0500 Subject: [PATCH 472/525] Bump to 7.10.0 --- src/Controllers/CallbackControllerAbstract.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Controllers/CallbackControllerAbstract.php b/src/Controllers/CallbackControllerAbstract.php index ce78b156..c91ca7a9 100644 --- a/src/Controllers/CallbackControllerAbstract.php +++ b/src/Controllers/CallbackControllerAbstract.php @@ -5,7 +5,7 @@ namespace Auth0\Laravel\Controllers; use Auth0\Laravel\Auth\Guard; -use Auth0\Laravel\Entities\CredentialEntityContract; +use Auth0\Laravel\Entities\{CredentialEntityContract, InstanceEntityContract}; use Auth0\Laravel\Events\{AuthenticationFailed, AuthenticationSucceeded}; use Auth0\Laravel\Exceptions\ControllerException; use Auth0\Laravel\Exceptions\Controllers\CallbackControllerException; @@ -161,11 +161,11 @@ private function clearSession( ): void { $service = $guard->service() ?? null; - if ($clearTransientStorage && null !== $service) { + if ($clearTransientStorage && $service instanceof InstanceEntityContract) { $service->getConfiguration()->getTransientStorage()?->purge(); } - if ($clearPersistentStorage && null !== $service) { + if ($clearPersistentStorage && $service instanceof InstanceEntityContract) { $service->getConfiguration()->getSessionStorage()?->purge(); } From d5a77aa0c420b217e7f4bb89feeaa8adfc0d22fe Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Sun, 6 Aug 2023 23:56:02 -0500 Subject: [PATCH 473/525] Update callback controller to avoid clearing of token cache --- src/Controllers/CallbackControllerAbstract.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Controllers/CallbackControllerAbstract.php b/src/Controllers/CallbackControllerAbstract.php index c91ca7a9..c23ea955 100644 --- a/src/Controllers/CallbackControllerAbstract.php +++ b/src/Controllers/CallbackControllerAbstract.php @@ -74,7 +74,7 @@ public function __invoke( event(new Failed($guard::class, $guard->user(), $credentials)); - $this->clearSession($guard, true, true, true); + $this->clearSession($guard); // Throw hookable $event to allow custom error handling scenarios. $event = new AuthenticationFailed($throwable, true); @@ -101,7 +101,7 @@ public function __invoke( 'error' => ['error' => $error, 'description' => $errorDescription], ])); - $this->clearSession($guard, true, true, true); + $this->clearSession($guard); // Create a dynamic exception to report the API error response $exception = new CallbackControllerException(sprintf(CallbackControllerException::MSG_API_RESPONSE, $error, $errorDescription)); @@ -137,6 +137,7 @@ public function __invoke( */ $guard->login($credential, Guard::SOURCE_SESSION); + $request->session()->invalidate(); $request->session()->regenerate(); $event = new AuthenticationSucceeded($user); @@ -157,7 +158,7 @@ private function clearSession( GuardAbstract $guard, bool $clearTransientStorage = true, bool $clearPersistentStorage = true, - bool $clearSdkStorage = false, + bool $clearSdkStorage = true, ): void { $service = $guard->service() ?? null; From 137f68bc84d85cb9336219631196c0b0d3938c06 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 7 Aug 2023 01:11:42 -0500 Subject: [PATCH 474/525] Bump to 7.10.1 --- CHANGELOG.md | 156 +++++++++++++++++++++------------------- src/ServiceAbstract.php | 2 +- 2 files changed, 82 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da28609c..18660a68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,20 +1,26 @@ # Changelog -## [7.10.0](https://github.com/auth0/laravel-auth0/tree/7.9.1) (2023-07-24) +## [7.10.1](https://github.com/auth0/laravel-auth0/tree/7.10.1) (2023-08-07) + +### Fixed + +- Addressed an issue where, under certain circumstances, permissions state could be lost after authenticating. + +## [7.10.0](https://github.com/auth0/laravel-auth0/tree/7.10.0) (2023-07-24) ### Added -- Organization Name support added for Authentication API and token handling ¹ +- Organization Name support added for Authentication API and token handling ¹ ### Changed -- Guards are now registered with the priority middleware list. -- Bumped `auth0-php` dependency version range to `^8.7`. -- Updated telemetry to indicate new `laravel` package name (previously `laravel-auth0`.) +- Guards are now registered with the priority middleware list. +- Bumped `auth0-php` dependency version range to `^8.7`. +- Updated telemetry to indicate new `laravel` package name (previously `laravel-auth0`.) ### Fixed -- Addressed issue where placeholder `AUTH0_` dotenv values could erroneously be interpreted as true configuration values. +- Addressed issue where placeholder `AUTH0_` dotenv values could erroneously be interpreted as true configuration values. > **Note** > ¹ To use this feature, an Auth0 tenant must have support for it enabled. This feature is not yet available to all tenants. @@ -23,98 +29,98 @@ ### Fixed -- Resolved an issue where, under certain circumstances, the AuthenticationGuard middleware could get erroneously added to the `api` middleware group, causing a session to be established in a stateless request. ([\#415](https://github.com/auth0/laravel-auth0/pull/415)) +- Resolved an issue where, under certain circumstances, the AuthenticationGuard middleware could get erroneously added to the `api` middleware group, causing a session to be established in a stateless request. ([\#415](https://github.com/auth0/laravel-auth0/pull/415)) ## [7.9.0](https://github.com/auth0/laravel-auth0/tree/7.9.0) (2023-06-15) ### Added -- SDK configuration (`config/auth0.php`) now supports a `configurationPath` property for specifying a custom search path for `.auth0.*.json` and `.env*` files. ([\#407](https://github.com/auth0/laravel-auth0/pull/407)) -- `Auth0\Laravel\Guards\GuardAbstract` now extends `Illuminate\Contracts\Auth\Guard`. ([\#410](https://github.com/auth0/laravel-auth0/pull/410)) +- SDK configuration (`config/auth0.php`) now supports a `configurationPath` property for specifying a custom search path for `.auth0.*.json` and `.env*` files. ([\#407](https://github.com/auth0/laravel-auth0/pull/407)) +- `Auth0\Laravel\Guards\GuardAbstract` now extends `Illuminate\Contracts\Auth\Guard`. ([\#410](https://github.com/auth0/laravel-auth0/pull/410)) ### Fixed -- Resolved host environment variables not being loaded as expected when a `.env` file is also used. ([\#408](https://github.com/auth0/laravel-auth0/pull/408)) -- Resolved surrounding quote characters not being trimmed from environment variables and `.env` files during processing. ([\#409](https://github.com/auth0/laravel-auth0/pull/409)) +- Resolved host environment variables not being loaded as expected when a `.env` file is also used. ([\#408](https://github.com/auth0/laravel-auth0/pull/408)) +- Resolved surrounding quote characters not being trimmed from environment variables and `.env` files during processing. ([\#409](https://github.com/auth0/laravel-auth0/pull/409)) ## [7.8.1](https://github.com/auth0/laravel-auth0/tree/7.8.1) (2023-05-19) ### Fixed -- Resolved an issue where parsing `.env` files could sometimes throw an exception when handling non-key-value pair strings. ([\#395](https://github.com/auth0/laravel-auth0/pull/395)) +- Resolved an issue where parsing `.env` files could sometimes throw an exception when handling non-key-value pair strings. ([\#395](https://github.com/auth0/laravel-auth0/pull/395)) ## [7.8.0](https://github.com/auth0/laravel-auth0/tree/7.8.0) (2023-05-18) ### Added -- This release adds support for authenticating using **[Pushed Authorization Requests](https://www.rfc-editor.org/rfc/rfc6749)**. +- This release adds support for authenticating using **[Pushed Authorization Requests](https://www.rfc-editor.org/rfc/rfc6749)**. -- This release introduces **two new Authentication Guards** which provide a streamlined integration experience for developers that need to simultaneously support both session-based authentication and token-based endpoint authorization in their Laravel applications. +- This release introduces **two new Authentication Guards** which provide a streamlined integration experience for developers that need to simultaneously support both session-based authentication and token-based endpoint authorization in their Laravel applications. | Guard | Class | Description | | --------------------- | ----------------------------------------------- | ----------------------------- | | `auth0.authenticator` | `Auth0\Laravel\Auth\Guards\AuthenticationGuard` | Session-based authentication. | | `auth0.authorizer` | `Auth0\Laravel\Auth\Guards\AuthorizationGuard` | Token-based authorization. | -- These guards are compatible with Laravel's Authentication API and support the standard `auth` middleware. +- These guards are compatible with Laravel's Authentication API and support the standard `auth` middleware. -- These guards are compatible with Laravel's Authorization API and support the standard `can` middleware, and the `Guard` facade, and work with the Policies API. +- These guards are compatible with Laravel's Authorization API and support the standard `can` middleware, and the `Guard` facade, and work with the Policies API. -- 3 new pre-built Guards are available: `scope` and `permission`, as well as a dynamic `*:*`. This enables you to verify whether the user's access token has a particular scope or (if RBAC is enabled on the Auth0 API) a particular permission. For example `Gate::check('scope', 'email')` or `Route::get(/*...*/)->can('read:messages')`. +- 3 new pre-built Guards are available: `scope` and `permission`, as well as a dynamic `*:*`. This enables you to verify whether the user's access token has a particular scope or (if RBAC is enabled on the Auth0 API) a particular permission. For example `Gate::check('scope', 'email')` or `Route::get(/*...*/)->can('read:messages')`. -- The SDK now automatically registers these guards to Laravel's standard `web` and `api` middleware groups, respectively. Manual Guard setup in `config/auth.php` is no longer necessary. +- The SDK now automatically registers these guards to Laravel's standard `web` and `api` middleware groups, respectively. Manual Guard setup in `config/auth.php` is no longer necessary. -- The SDK now automatically registers the Authentication routes. Manual route setup in `routes/web.php` is no longer necessary. +- The SDK now automatically registers the Authentication routes. Manual route setup in `routes/web.php` is no longer necessary. -- 2 new routing Middleware have been added: `Auth0\Laravel\Http\Middleware\AuthenticatorMiddleware` and `Auth0\Laravel\Http\Middleware\AuthorizerMiddleware`. These are automatically registered with your Laravel application, and ensure the Auth0 Guards are used for authentication for `web` routes and authorization for `api` routes, respectively. This replaces the need for the `guard` middleware or otherwise manual Guard assignment in your routes. +- 2 new routing Middleware have been added: `Auth0\Laravel\Http\Middleware\AuthenticatorMiddleware` and `Auth0\Laravel\Http\Middleware\AuthorizerMiddleware`. These are automatically registered with your Laravel application, and ensure the Auth0 Guards are used for authentication for `web` routes and authorization for `api` routes, respectively. This replaces the need for the `guard` middleware or otherwise manual Guard assignment in your routes. ### Improved -- We've introduced **a new configuration syntax**. This new syntax is more flexible and allows for more complex configuration scenarios, and introduces support for multiple guard instances. Developers using the previous syntax will have their existing configurations applied to all guards uniformly. +- We've introduced **a new configuration syntax**. This new syntax is more flexible and allows for more complex configuration scenarios, and introduces support for multiple guard instances. Developers using the previous syntax will have their existing configurations applied to all guards uniformly. -- The SDK can now **configure itself using a `.auth0.json` file in the project root directory**. This file can be generated [using the Auth0 CLI](./docs/Configuration.md), and provides a significantly simpler configuration experience for developers. +- The SDK can now **configure itself using a `.auth0.json` file in the project root directory**. This file can be generated [using the Auth0 CLI](./docs/Configuration.md), and provides a significantly simpler configuration experience for developers. -- The previous `auth0.guard` Guard (`Auth0\Laravel\Auth\Guard`) has been **refactored** as a lightweight wrapper around the new `AuthenticationGuard` and `AuthorizationGuard` guards. +- The previous `auth0.guard` Guard (`Auth0\Laravel\Auth\Guard`) has been **refactored** as a lightweight wrapper around the new `AuthenticationGuard` and `AuthorizationGuard` guards. ## [7.7.0](https://github.com/auth0/laravel-auth0/tree/7.7.0) (2023-04-26) ### Added -- `Auth0\Laravel\Auth0` now has a `management()` shortcut method for issuing Management API calls. ([\#376](https://github.com/auth0/laravel-auth0/pull/376)) +- `Auth0\Laravel\Auth0` now has a `management()` shortcut method for issuing Management API calls. ([\#376](https://github.com/auth0/laravel-auth0/pull/376)) -- `Auth0\Laravel\Auth0\Guard` now has a `refreshUser()` method for querying `/userinfo` endpoint and refreshing the authenticated user's cached profile data. ([\#375](https://github.com/auth0/laravel-auth0/pull/375)) +- `Auth0\Laravel\Auth0\Guard` now has a `refreshUser()` method for querying `/userinfo` endpoint and refreshing the authenticated user's cached profile data. ([\#375](https://github.com/auth0/laravel-auth0/pull/375)) -- `Auth0\Laravel\Http\Controller\Stateful\Login` now raises a `LoginAttempting` event, offering an opportunity to customize the authorization parameters before the login redirect is issued. ([\#382](https://github.com/auth0/laravel-auth0/pull/382)) +- `Auth0\Laravel\Http\Controller\Stateful\Login` now raises a `LoginAttempting` event, offering an opportunity to customize the authorization parameters before the login redirect is issued. ([\#382](https://github.com/auth0/laravel-auth0/pull/382)) ### Improved -- The `tokenCache`, `managementTokenCache`, `sessionStorage` and `transientStorage` configuration values now support `false` or `string` values pointing to class names (e.g. `\Some\Cache::class`) or class aliases (e.g. `cache.psr6`) registered with Laravel. ([\#381](https://github.com/auth0/laravel-auth0/pull/381)) +- The `tokenCache`, `managementTokenCache`, `sessionStorage` and `transientStorage` configuration values now support `false` or `string` values pointing to class names (e.g. `\Some\Cache::class`) or class aliases (e.g. `cache.psr6`) registered with Laravel. ([\#381](https://github.com/auth0/laravel-auth0/pull/381)) ## [7.6.0](https://github.com/auth0/laravel-auth0/tree/7.6.0) (2023-04-12) ### Added -- `Auth0\Laravel\Http\Middleware\Guard`, new middleware that forces Laravel to route requests through a group using a specific Guard. ([\#362](https://github.com/auth0/laravel-auth0/pull/362)) +- `Auth0\Laravel\Http\Middleware\Guard`, new middleware that forces Laravel to route requests through a group using a specific Guard. ([\#362](https://github.com/auth0/laravel-auth0/pull/362)) ### Improved -- `Auth0\Laravel\Http\Middleware\Stateful\Authenticate` now remembers the intended route (using `redirect()->setIntendedUrl()`) before kicking off the authentication flow redirect. Users will be returned to the memorized intended route after completing their authentication flow. ([\#364](https://github.com/auth0/laravel-auth0/pull/364)) +- `Auth0\Laravel\Http\Middleware\Stateful\Authenticate` now remembers the intended route (using `redirect()->setIntendedUrl()`) before kicking off the authentication flow redirect. Users will be returned to the memorized intended route after completing their authentication flow. ([\#364](https://github.com/auth0/laravel-auth0/pull/364)) ### Fixed -- legacyGuardUserMethod behavior should use `$session`, not `$token` ([\#353](https://github.com/auth0/laravel-auth0/pull/365)) +- legacyGuardUserMethod behavior should use `$session`, not `$token` ([\#353](https://github.com/auth0/laravel-auth0/pull/365)) ## [7.5.2](https://github.com/auth0/laravel-auth0/tree/7.5.2) (2023-04-10) ### Fixed -- Relaxed response types from middleware to use low-level `Symfony\Component\HttpFoundation\Response` class, allowing for broader and custom response types. +- Relaxed response types from middleware to use low-level `Symfony\Component\HttpFoundation\Response` class, allowing for broader and custom response types. ## [7.5.1](https://github.com/auth0/laravel-auth0/tree/7.5.1) (2023-04-04) ### Fixed -- Resolved an issue wherein custom user repositories could fail to be instantiated under certain circumstances. +- Resolved an issue wherein custom user repositories could fail to be instantiated under certain circumstances. ## [7.5.0](https://github.com/auth0/laravel-auth0/tree/7.5.0) (2023-04-03) @@ -122,30 +128,30 @@ This release includes support for Laravel 10, and major improvements to the inte ### Added -- Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) -- New `Auth0\Laravel\Traits\Imposter` trait to allow for easier testing. [Example usage](./tests/Unit/Traits/ImpersonateTest.php) -- New Exception types have been added for more precise error-catching. +- Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) +- New `Auth0\Laravel\Traits\Imposter` trait to allow for easier testing. [Example usage](./tests/Unit/Traits/ImpersonateTest.php) +- New Exception types have been added for more precise error-catching. ### Improved The following changes have no effect on the external API of this package but may affect internal usage. -- `Guard` will now more reliably detect changes in the underlying Auth0-PHP SDK session state. -- `Guard` will now more reliably sync changes back to the underlying Auth0-PHP SDK session state. -- `StateInstance` concept has been replaced by a new `Credentials` entity. -- `Guard` updated to use new `Credentials` entity as primary internal storage for user data. -- `Auth0\Laravel\Traits\ActingAsAuth0User` was updated to use new `Credentials` entity. -- The HTTP middleware has been refactored to more clearly differentiate between token and session-based identities. -- The `authenticate`, `authenticate.optional` and `authorize.optional` HTTP middleware now supports scope filtering, as `authorize` already did. +- `Guard` will now more reliably detect changes in the underlying Auth0-PHP SDK session state. +- `Guard` will now more reliably sync changes back to the underlying Auth0-PHP SDK session state. +- `StateInstance` concept has been replaced by a new `Credentials` entity. +- `Guard` updated to use new `Credentials` entity as primary internal storage for user data. +- `Auth0\Laravel\Traits\ActingAsAuth0User` was updated to use new `Credentials` entity. +- The HTTP middleware has been refactored to more clearly differentiate between token and session-based identities. +- The `authenticate`, `authenticate.optional` and `authorize.optional` HTTP middleware now supports scope filtering, as `authorize` already did. -- Upgraded test suite to use PEST 2.0 framework. -- Updated test coverage to 100%. +- Upgraded test suite to use PEST 2.0 framework. +- Updated test coverage to 100%. ### Fixed -- A 'Session store not set on request' error could occur when downstream applications implemented unit testing that uses the Guard. This should be resolved now. -- `Guard` would not always honor the `provider` configuration value in `config/auth.php`. -- `Guard` is no longer defined as a Singleton to better support applications that need multi-guard configurations. +- A 'Session store not set on request' error could occur when downstream applications implemented unit testing that uses the Guard. This should be resolved now. +- `Guard` would not always honor the `provider` configuration value in `config/auth.php`. +- `Guard` is no longer defined as a Singleton to better support applications that need multi-guard configurations. ### Notes @@ -163,43 +169,43 @@ We identified an issue with using identical alias naming for both the Guard and ### Added -- feat: Add `Auth0\Laravel\Event\Middleware\...` event hooks [\#340](https://github.com/auth0/laravel-auth0/pull/340) -- feat: Add `Auth0\Laravel\Event\Configuration\Building` event hook [\#339](https://github.com/auth0/laravel-auth0/pull/339) +- feat: Add `Auth0\Laravel\Event\Middleware\...` event hooks [\#340](https://github.com/auth0/laravel-auth0/pull/340) +- feat: Add `Auth0\Laravel\Event\Configuration\Building` event hook [\#339](https://github.com/auth0/laravel-auth0/pull/339) ## [7.3.0](https://github.com/auth0/laravel-auth0/tree/7.3.0) (2022-11-07) ### Added -- add: Raise additional Laravel Auth Events [\#331](https://github.com/auth0/laravel-auth0/pull/331) +- add: Raise additional Laravel Auth Events [\#331](https://github.com/auth0/laravel-auth0/pull/331) ### Fixed -- fix: `env()` incorrectly assigns `cookieExpires` to a `string` value [\#332](https://github.com/auth0/laravel-auth0/pull/332) -- fix: Auth0\Laravel\Cache\LaravelCachePool::createItem returning a cache miss [\#329](https://github.com/auth0/laravel-auth0/pull/329) +- fix: `env()` incorrectly assigns `cookieExpires` to a `string` value [\#332](https://github.com/auth0/laravel-auth0/pull/332) +- fix: Auth0\Laravel\Cache\LaravelCachePool::createItem returning a cache miss [\#329](https://github.com/auth0/laravel-auth0/pull/329) ## [7.2.2](https://github.com/auth0/laravel-auth0/tree/7.2.2) (2022-10-19) ### Fixed -- Restore `php artisan vendor:publish` command [\#321](https://github.com/auth0/laravel-auth0/pull/321) -- Bump minimum `auth0/auth0-php` version to `^8.3.4` [\#322](https://github.com/auth0/laravel-auth0/pull/322) +- Restore `php artisan vendor:publish` command [\#321](https://github.com/auth0/laravel-auth0/pull/321) +- Bump minimum `auth0/auth0-php` version to `^8.3.4` [\#322](https://github.com/auth0/laravel-auth0/pull/322) ## [7.2.1](https://github.com/auth0/laravel-auth0/tree/7.2.1) (2022-10-13) ### Fixed -- `Auth0\Laravel\Auth0` no longer requires a session configuration for stateless strategies, restoring previous behavior. [\#317](https://github.com/auth0/laravel-auth0/pull/317) -- The SDK now requires `^3.0` of the `psr/cache` dependency, to accommodate breaking changes made in the upstream interface (typed parameters and return types) for PHP 8.0+. [\#316](https://github.com/auth0/laravel-auth0/pull/316) +- `Auth0\Laravel\Auth0` no longer requires a session configuration for stateless strategies, restoring previous behavior. [\#317](https://github.com/auth0/laravel-auth0/pull/317) +- The SDK now requires `^3.0` of the `psr/cache` dependency, to accommodate breaking changes made in the upstream interface (typed parameters and return types) for PHP 8.0+. [\#316](https://github.com/auth0/laravel-auth0/pull/316) ## [7.2.0](https://github.com/auth0/laravel-auth0/tree/7.2.0) (2022-10-10) ### Improved -- `Auth0\Laravel\Store\LaravelSession` has been added as the default `sessionStorage` and `transientStorage` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Session APIs](https://laravel.com/docs/9.x/session) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307)¹ -- `Auth0\Laravel\Cache\LaravelCachePool` and `Auth0\Laravel\Cache\LaravelCacheItem` have been added as the default `tokenCache` and `managementTokenCache` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Cache APIs](https://laravel.com/docs/9.x/cache) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) -- `Auth0\Laravel\Auth\Guard` now supports the `viaRemember` method. [\#306](https://github.com/auth0/laravel-auth0/pull/306) -- `Auth0\Laravel\Http\Middleware\Stateless\Authorize` now returns a 401 status instead of 403 for unauthenticated users. [\#304](https://github.com/auth0/laravel-auth0/issues/304) -- PHP 8.0 is now the minimum supported runtime version. Please review the [README](README.md) for more information on support windows. +- `Auth0\Laravel\Store\LaravelSession` has been added as the default `sessionStorage` and `transientStorage` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Session APIs](https://laravel.com/docs/9.x/session) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307)¹ +- `Auth0\Laravel\Cache\LaravelCachePool` and `Auth0\Laravel\Cache\LaravelCacheItem` have been added as the default `tokenCache` and `managementTokenCache` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Cache APIs](https://laravel.com/docs/9.x/cache) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) +- `Auth0\Laravel\Auth\Guard` now supports the `viaRemember` method. [\#306](https://github.com/auth0/laravel-auth0/pull/306) +- `Auth0\Laravel\Http\Middleware\Stateless\Authorize` now returns a 401 status instead of 403 for unauthenticated users. [\#304](https://github.com/auth0/laravel-auth0/issues/304) +- PHP 8.0 is now the minimum supported runtime version. Please review the [README](README.md) for more information on support windows. ¹ This change may require your application's users to re-authenticate. You can avoid this by changing the `sessionStorage` and `transientStorage` options in your SDK configuration to their previous default instances of `Auth0\SDK\Store\CookieStore`, but it is recommended you migrate to the new `LaravelSession` default. @@ -207,37 +213,37 @@ We identified an issue with using identical alias naming for both the Guard and ### Improved -- Return interfaces instead of concrete classes [\#296](https://github.com/auth0/laravel-auth0/pull/296) -- change: Use class names for `app()` calls [\#291](https://github.com/auth0/laravel-auth0/pull/291) +- Return interfaces instead of concrete classes [\#296](https://github.com/auth0/laravel-auth0/pull/296) +- change: Use class names for `app()` calls [\#291](https://github.com/auth0/laravel-auth0/pull/291) ### Fixed -- Fix: `Missing Code` error on Callback Route for Octane Customers [\#297](https://github.com/auth0/laravel-auth0/pull/297) +- Fix: `Missing Code` error on Callback Route for Octane Customers [\#297](https://github.com/auth0/laravel-auth0/pull/297) ## [7.0.1](https://github.com/auth0/laravel-auth0/tree/7.0.1) (2022-06-01) ### Fixed -- Fixed an issue in `Auth0\Laravel\Http\Controller\Stateful\Callback` where `$errorDescription`'s value was assigned an incorrect value when an error was encountered. [\#266](https://github.com/auth0/laravel-auth0/pull/288) +- Fixed an issue in `Auth0\Laravel\Http\Controller\Stateful\Callback` where `$errorDescription`'s value was assigned an incorrect value when an error was encountered. [\#266](https://github.com/auth0/laravel-auth0/pull/288) ## [7.0.0](https://github.com/auth0/laravel-auth0/tree/7.0.0) (2022-03-21) Auth0 Laravel SDK v7 includes many significant changes over previous versions: -- Support for Laravel 9. -- Support for Auth0-PHP SDK 8. -- New authentication route controllers for plug-and-play login support. -- Improved authentication middleware for regular web applications. -- New authorization middleware for token-based backend API applications. +- Support for Laravel 9. +- Support for Auth0-PHP SDK 8. +- New authentication route controllers for plug-and-play login support. +- Improved authentication middleware for regular web applications. +- New authorization middleware for token-based backend API applications. As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes. Please review the [upgrade guide](UPGRADE.md) thoroughly to understand the changes required to migrate your application to v7. ### Breaking Changes -- Namespace has been updated from `Auth0\Login` to `Auth0\Laravel` -- Auth0-PHP SDK dependency updated to V8 -- New configuration format -- SDK now self-registers its services and middleware -- New UserProvider API +- Namespace has been updated from `Auth0\Login` to `Auth0\Laravel` +- Auth0-PHP SDK dependency updated to V8 +- New configuration format +- SDK now self-registers its services and middleware +- New UserProvider API > Changelog entries for releases prior to 8.0 have been relocated to [CHANGELOG.ARCHIVE.md](CHANGELOG.ARCHIVE.md). diff --git a/src/ServiceAbstract.php b/src/ServiceAbstract.php index ca286d07..1fd9fceb 100644 --- a/src/ServiceAbstract.php +++ b/src/ServiceAbstract.php @@ -22,7 +22,7 @@ abstract class ServiceAbstract extends InstanceEntityAbstract * * @var string */ - public const VERSION = '7.10.0'; + public const VERSION = '7.10.1'; /** * Decode a PSR-7 HTTP Response Message containing a JSON content body to a PHP array. Returns null if the response was not successful, or the response body was not JSON. From 828ae5af17e90a40ac79fbd961ae145c4fc92692 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 9 Aug 2023 00:22:58 -0500 Subject: [PATCH 475/525] Bump to 7.11.0 --- CHANGELOG.md | 24 ++ README.md | 13 +- composer.json | 2 +- docs/Configuration.md | 2 +- docs/Cookies.md | 47 +++ docs/Eloquent.md | 269 ++++++++++++++++++ docs/Installation.md | 2 +- docs/Management.md | 48 ++-- docs/Sessions.md | 41 +++ docs/Telescope.md | 50 ++++ docs/Users.md | 146 +++++----- phpstan.neon.dist | 1 + psalm.xml.dist | 1 + rector.php | 1 - src/Bridges/SessionBridgeAbstract.php | 57 ++-- .../CallbackControllerAbstract.php | 64 ++--- src/Controllers/LoginControllerAbstract.php | 10 +- src/Controllers/LogoutControllerAbstract.php | 1 + src/Entities/InstanceEntityAbstract.php | 19 +- src/Events.php | 100 +++++++ src/Events/Auth0EventContract.php | 4 - src/Events/AuthenticationFailed.php | 2 +- src/Events/AuthenticationFailedAbstract.php | 34 +-- src/Events/AuthenticationFailedContract.php | 33 +-- src/Events/AuthenticationSucceeded.php | 2 +- .../AuthenticationSucceededAbstract.php | 25 +- .../AuthenticationSucceededContract.php | 20 +- .../BuildingConfigurationEvent.php | 2 +- .../BuildingConfigurationEventAbstract.php | 21 +- .../BuildingConfigurationEventContract.php | 18 +- .../Configuration/BuiltConfigurationEvent.php | 2 +- .../BuiltConfigurationEventAbstract.php | 23 +- .../BuiltConfigurationEventContract.php | 19 +- src/Events/EventAbstract.php | 18 +- src/Events/EventContract.php | 6 +- src/Events/LoginAttempting.php | 2 +- src/Events/LoginAttemptingAbstract.php | 21 +- src/Events/LoginAttemptingContract.php | 18 +- .../Middleware/StatefulMiddlewareRequest.php | 5 + .../StatefulMiddlewareRequestAbstract.php | 28 +- .../StatefulMiddlewareRequestContract.php | 6 + .../Middleware/StatelessMiddlewareRequest.php | 5 + .../StatelessMiddlewareRequestAbstract.php | 28 +- .../StatelessMiddlewareRequestContract.php | 6 + src/Events/TokenExpired.php | 2 +- src/Events/TokenExpiredAbstract.php | 4 + src/Events/TokenExpiredContract.php | 1 + src/Events/TokenRefreshFailed.php | 2 +- src/Events/TokenRefreshFailedAbstract.php | 4 + src/Events/TokenRefreshFailedContract.php | 1 + src/Events/TokenRefreshSucceeded.php | 2 +- src/Events/TokenRefreshSucceededAbstract.php | 4 + src/Events/TokenRefreshSucceededContract.php | 1 + src/Events/TokenVerificationAttempting.php | 2 +- .../TokenVerificationAttemptingAbstract.php | 22 +- .../TokenVerificationAttemptingContract.php | 18 +- src/Events/TokenVerificationFailed.php | 2 +- .../TokenVerificationFailedAbstract.php | 26 +- .../TokenVerificationFailedContract.php | 22 +- src/Events/TokenVerificationSucceeded.php | 2 +- .../TokenVerificationSucceededAbstract.php | 25 +- .../TokenVerificationSucceededContract.php | 20 +- src/EventsContract.php | 118 ++++++++ src/Guards/AuthenticationGuard.php | 45 ++- src/Guards/GuardAbstract.php | 14 +- .../AuthenticateMiddlewareAbstract.php | 15 +- ...AuthenticateOptionalMiddlewareAbstract.php | 14 +- .../AuthorizeMiddlewareAbstract.php | 14 +- .../AuthorizeOptionalMiddlewareAbstract.php | 14 +- src/ServiceAbstract.php | 2 +- src/UserProviderAbstract.php | 69 ++++- tests/Pest.php | 41 +++ tests/TestCase.php | 38 --- tests/Unit/Bridges/SessionBridgeTest.php | 8 +- .../Controllers/CallbackControllerTest.php | 10 +- .../Unit/Controllers/LoginControllerTest.php | 12 +- .../Unit/Controllers/LogoutControllerTest.php | 12 +- .../Middleware/AuthenticateMiddlewareTest.php | 53 ++-- .../AuthenticateOptionalMiddlewareTest.php | 50 ++-- .../AuthorizeOptionalMiddlewareTest.php | 40 +-- tests/Unit/Traits/ActingAsAuth0UserTest.php | 9 +- 81 files changed, 1368 insertions(+), 616 deletions(-) create mode 100644 docs/Cookies.md create mode 100644 docs/Eloquent.md create mode 100644 docs/Sessions.md create mode 100644 docs/Telescope.md create mode 100644 src/Events.php create mode 100644 src/EventsContract.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 18660a68..cb950f4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## [7.11.0](https://github.com/auth0/laravel-auth0/tree/7.10.1) (2023-08-08) + +### Added + +- Significant performance improvements by eliminating redundant user queries. +- Compatibility support for [Laravel Telescope](https://laravel.com/docs/telescope). See [docs/Telescope.md](./docs/Telescope.md) for more information. +- A refactored Events API has been introduced. See [docs/Events.md](./docs/Events.md) for more information. +- `AUTH0_SESSION_STORAGE` and `AUTH0_TRANSIENT_STORAGE` now support a `cookie` value to enable the native Auth0-PHP SDK cookie session handler. See [docs/Cookies.md](./docs/Cookies.md) for more information. + +### Fixed + +- Addressed an issue where, under certain circumstances, the first user authentication attempt after a session invalidation could fail. + +### Changed + +- Session regeneration/invalidation has been refactored. +- Discarded sessions are now deleted when they are invalidated by the SDK, rather than wait for Laravel to garbage collect. +- Session storage has been refactored. Session data is now stored as a JSON array in a single `auth0_session` entry in the Laravel session store, rather than in multiple keys. + +### Documentation + +- A demonstration Eloquent user model and repository implementation has been added to [docs/Eloquent.md](./docs/Eloquent.md). +- A new [docs/Sessions.md](./docs/Sessions.md) document has been added for guidance on the various session driver options available. + ## [7.10.1](https://github.com/auth0/laravel-auth0/tree/7.10.1) (2023-08-07) ### Fixed diff --git a/README.md b/README.md index a6fd9ee3..2dd1a499 100644 --- a/README.md +++ b/README.md @@ -356,11 +356,18 @@ All the SDK's Management API methods are [documented here](./docs/Management.md) - [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. - [Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. -- [Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2). -- [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent). +- [Sessions](./docs/Sessions.md) — Guidance on deciding which Laravel Session API driver to use. +- [Cookies](./docs/Cookies.md) — Important notes about using Laravel's Cookie session driver, and alternative options. +- [Management API](./docs/Management.md) — Using the SDK to work with the [Auth0 Management API](https://auth0.com/docs/api/management/v2). +- [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent) models. - [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. - [Deployment](./docs/Deployment.md) — Deploying your application to production. -- [Octane](./docs/Octane.md) — We do not support using the SDK with [Octane](https://laravel.com/docs/octane) at this time. + +You may find the following integration guidance useful: + +- [Laravel Eloquent](./docs/Eloquent.md) — [Eloquent ORM](https://laravel.com/docs/eloquent) is supported. +- [Laravel Octane](./docs/Octane.md) — [Octane](https://laravel.com/docs/octane) is not supported at this time. +- [Laravel Telescope](./docs/Telescope.md) — [Telescope](https://laravel.com/docs/telescope) is compatible as of SDK v7.11.0. You may also find the following resources helpful: diff --git a/composer.json b/composer.json index 5a6b83dc..ea0e84be 100644 --- a/composer.json +++ b/composer.json @@ -114,7 +114,7 @@ "pest:coverage": "@php vendor/bin/pest --coverage --parallel --no-progress", "pest:debug": "@php vendor/bin/pest --fail-on-risky --stop-on-defect", "pest:profile": "@php vendor/bin/pest --profile", - "pest": "@php vendor/bin/pest --order-by random --fail-on-risky --stop-on-defect --coverage --parallel --min=95", + "pest": "@php vendor/bin/pest --order-by random --fail-on-risky --stop-on-defect --parallel", "phpcs:fix": "@php vendor/bin/php-cs-fixer fix", "phpcs": "@php vendor/bin/php-cs-fixer fix --dry-run --diff", "phpstan": "@php vendor/bin/phpstan analyze", diff --git a/docs/Configuration.md b/docs/Configuration.md index 37d24e90..8ecdb293 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -268,7 +268,7 @@ The following parameters used in this example are of note: - For Laravel applications, this should always be set to `regular`. - `--auth-method` - This represents the 'Token Endpoint Authentication Method' used for authentication. - For Laravel applications, this should always be set to `post`. -- `--callbacks` - The callback URLs to use for authentication. +- `--callbacks` - The callback URLs to use for authentication. - In development, this should be set to `http://localhost:8000/callback` or as appropriate. - In production, adjust this value to match your application's Internet-accessible URL for its`/callback`` route. - This value can be a comma-separated list of URLs. diff --git a/docs/Cookies.md b/docs/Cookies.md new file mode 100644 index 00000000..eeee3898 --- /dev/null +++ b/docs/Cookies.md @@ -0,0 +1,47 @@ +# Cookies + +We strongly recommend using the `database` or `redis` session drivers, but realize this is not always a viable option for all developers or use cases. The Auth0 Laravel SDK supports cookies for storing authentication state, but there are notable drawbacks to be aware of. + +## Laravel's Cookie Session Driver + +As noted in our [sessions documentation](./Sessions.md), Laravel's `cookie` session driver is not a reliable option for production applications as it suffers from a number of notable drawbacks: + +- Browsers impose a size limit of 4 KB on individual cookies, which can quickly be exceeded by storing session data. +- Laravel's cookie driver unfortunately does not "chunk" (split up) larger cookies into multiple cookies, so it is impossible to store more than the noted 4 KB of total session data. +- Most web servers and load balancers require additional configuration to accept and deliver larger cookie headers. + +## Auth0 PHP SDK's Custom Cookie Session Handler + +The underlying [Auth0 PHP SDK](https://github.com/auth0/auth0-PHP) (which the Auth0 Laravel SDK is built upon) includes a powerful custom cookie session handler that supports chunking of larger cookies. This approach will enable you to securely and reliably store larger authentication states for your users. + +It is important to note that this approach is incompatible with [Octane](./Octane.md) due to the way it delivers cookie headers. + +To enable this feature, assign a `cookie` string value to the `AUTH0_SESSION_STORAGE` and `AUTH0_TRANSIENT_STORAGE` environment variables (or your `.env` file.) + +```ini +# Persistent session data: +AUTH0_SESSION_STORAGE=cookie + +# Temporary session data (used only during authentication): +AUTH0_TRANSIENT_STORAGE=cookie +``` + +This will override the SDK's default behavior of using the Laravel Sessions API, and instead use the integrated Auth0 PHP SDK's custom cookie session handler. Please note: + +- When this feature is enabled, all properties of cookie storage (like `sameSite`, `secure`, and so forth) must be configured independently. This approach does not use Laravel's settings. Please refer to the [Auth0 PHP SDK's documentation](https://github.com/auth0/auth0-PHP) for guidance on how to configure these. +- By default your Laravel application's `APP_KEY` will be used to encrypt the cookie data. You can change this by assigning the `AUTH0_COOKIE_SECRET` environment variable (or your `.env` file) a string. If you do this, please ensure you are using an adequately long secure secret. +- Please ensure your server is configured to deliver and accept cookies prefixed with `auth0_session_` and `auth0_transient_` followed by a series of numbers (beginning with 0). These are the divided content body of the authenticated session data. + +### Increasing Server Cookies Header Sizes + +You may need to configure your web server or load balancer to accept and deliver larger cookie headers. For example, if you are using Nginx you will need to set the `large_client_header_buffers` directive to a value greater than the default of 4 KB. + +```nginx +large_client_header_buffers 4 16k; +``` + +Please refer to your web server or load balancer's documentation for more information. + +### Reminder on Octane Compatibility + +As noted above, the Auth0 PHP SDK's custom cookie session handler is incompatible with [Octane](./Octane.md) due to the way it delivers cookie headers. If you are using Octane, you must use the Laravel Sessions API with a `database` or `redis` driver. diff --git a/docs/Eloquent.md b/docs/Eloquent.md new file mode 100644 index 00000000..628fcb82 --- /dev/null +++ b/docs/Eloquent.md @@ -0,0 +1,269 @@ +# Laravel Eloquent + +By default, the SDK does not include any Eloquent models or database support. You can adapt the SDK to your application's needs by adding your own Eloquent models and database support. + +## Creating a User Model + +Begin by creating a new Eloquent model class. You can use the `make:model` Artisan command to do this. Laravel ships with default user model named `User`, so we'll use the `--force` flag to overwrite it with our custom one. + +Please ensure you have a backup of your existing `User` model before running this command, as it will overwrite your existing model. + +```bash +php artisan make:model User --force +``` + +Next, open your `app/Models/User.php` file and modify it match the following example. Notably, we'll add a support for a new `auth0` attribute. This attribute will be used to store the user's Auth0 ID, which is used to uniquely identify the user in Auth0. + +```php + 'datetime', + ]; +} +``` + +Next, create a migration to update your application's `users` table schema to support these changes. Create a new migration file: + +```bash +php artisan make:migration update_users_table --table=users +``` + +Openly the newly created migration file (found under `database/migrations` and ending in `update_users_table.php`) and update to match the following example: + +```php +string('auth0')->nullable(); + $table->boolean('email_verified')->default(false); + + $table->unique('auth0', 'users_auth0_unique'); + }); + } + + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropUnique('users_auth0_unique'); + + $table->dropColumn('auth0'); + $table->dropColumn('email_verified'); + }); + } +}; + +``` + +Now run the migration: + +```bash +php artisan migrate +``` + +## Creating a User Repository + +You'll need to create a new user repository class to handle the creation and retrieval of your Eloquent user models from your database table. + +Create a new repository class in your application at `app/Repositories/UserRepository.php`, and update it to match the following example: + +```php + "https://example.auth0.com/", + "aud" => "https://api.example.com/calendar/v1/", + "sub" => "auth0|123456", + "exp" => 1458872196, + "iat" => 1458785796, + "scope" => "read write", + ]; + */ + + $identifier = $user['sub'] ?? $user['auth0'] ?? null; + + if (null === $identifier) { + return null; + } + + return User::where('auth0', $identifier)->first(); + } + + public function fromSession(array $user): ?Authenticatable + { + /* + $user = [ // Example of a decoded ID token + "iss" => "http://example.auth0.com/", + "aud" => "client_id", + "sub" => "auth0|123456", + "exp" => 1458872196, + "iat" => 1458785796, + "name" => "Jane Doe", + "email" => "janedoe@example.com", + ]; + */ + + // Determine the Auth0 identifier for the user from the $user array. + $identifier = $user['sub'] ?? $user['auth0'] ?? null; + + // Collect relevant user profile information from the $user array for use later. + $profile = [ + 'auth0' => $identifier, + 'name' => $user['name'] ?? '', + 'email' => $user['email'] ?? '', + 'email_verified' => in_array($user['email_verified'], [1, true], true), + ]; + + // Check if a cache of the user exists in memory to avoid unnecessary database queries. + $cached = $this->withoutRecording(fn () => Cache::get('auth0_user_' . $identifier)); + + if ($cached) { + // Immediately return a cached user if one exists. + return $cached; + } + + $user = null; + + // Check if the user exists in the database by Auth0 identifier. + if (null !== $identifier) { + $user = User::where('auth0', $identifier)->first(); + } + + // Optional: if the user does not exist in the database by Auth0 identifier, you could fallback to matching by email. + if (null === $user && isset($user['email'])) { + $user = User::where('email', $user['email'])->first(); + } + + // If a user was found, check if any updates to the local record are required. + if (null !== $user) { + $updates = []; + + if ($user->auth0 !== $profile['auth0']) { + $updates['auth0'] = $profile['auth0']; + } + + if ($user->name !== $profile['name']) { + $updates['name'] = $profile['name']; + } + + if ($user->email !== $profile['email']) { + $updates['email'] = $profile['email']; + } + + $emailVerified = in_array($user->email_verified, [1, true], true); + + if ($emailVerified !== $profile['email_verified']) { + $updates['email_verified'] = $profile['email_verified']; + } + + if ([] !== $updates) { + $user->update($updates); + $user->save(); + } + + if ([] === $updates && null !== $cached) { + return $user; + } + } + + if (null === $user) { + // Local password column is not necessary or used by Auth0 authentication, but may be expected by some applications/packages. + $profile['password'] = Hash::make(Str::random(32)); + + // Create the user. + $user = User::create($profile); + } + + // Cache the user for 30 seconds. + $this->withoutRecording(fn () => Cache::put('auth0_user_' . $identifier, $user, 30)); + + return $user; + } + + /** + * Workaround for Laravel Telescope potentially causing an infinite loop. + * @link https://github.com/auth0/laravel-auth0/tree/main/docs/Telescope.md + * + * @param callable $callback + */ + private function withoutRecording($callback): mixed + { + $telescope = '\Laravel\Telescope\Telescope'; + + if (class_exists($telescope)) { + return "$telescope"::withoutRecording($callback); + } + + return call_user_func($callback); + } +} +``` + +Finally, update your application's `config/auth.php` file to configure the SDK to query your new user provider during authentication requests. + +```php +'providers' => [ + 'auth0-provider' => [ + 'driver' => 'auth0.provider', + 'repository' => \App\Repositories\UserRepository::class, + ], +], +``` diff --git a/docs/Installation.md b/docs/Installation.md index 38c5e40f..b0a9938d 100644 --- a/docs/Installation.md +++ b/docs/Installation.md @@ -7,7 +7,7 @@ - [Create a Laravel Application](#create-a-laravel-application) - [Install the SDK](#install-the-sdk-1) - [Install the CLI](#install-the-cli) - - [Authenticate the CLI](#authenticate-the-cli) + - [Authenticate the CLI](#authenticate-the-cli) - [Configure the SDK](#configure-the-sdk) - [Using JSON (Recommended)](#using-json-recommended) - [Using Environment Variables](#using-environment-variables) diff --git a/docs/Management.md b/docs/Management.md index 3ff45e0f..dae7f262 100644 --- a/docs/Management.md +++ b/docs/Management.md @@ -16,30 +16,30 @@ Before making Management API calls you must permit your application to communica ## Available endpoints -- [Actions](#actions) -- [Attack Protection](#attack-protection) -- [Blacklists](#blacklists) -- [ClientGrants](#client-grants) -- [Clients](#clients) -- [Connections](#connections) -- [Device Credentials](#device-credentials) -- [Emails](#emails) -- [Email Templates](#email-templates) -- [Grants](#grants) -- [Guardian](#guardian) -- [Jobs](#jobs) -- [Logs](#logs) -- [Log Streams](#log-streams) -- [Organizations](#organizations) -- [Resource Servers](#resource-servers) -- [Roles](#roles) -- [Rules](#rules) -- [Stats](#stats) -- [Tenants](#tenants) -- [Tickets](#tickets) -- [User Blocks](#user-blocks) -- [Users](#users) -- [Users by Email](#users-by-email) +- [Actions](#actions) +- [Attack Protection](#attack-protection) +- [Blacklists](#blacklists) +- [ClientGrants](#client-grants) +- [Clients](#clients) +- [Connections](#connections) +- [Device Credentials](#device-credentials) +- [Emails](#emails) +- [Email Templates](#email-templates) +- [Grants](#grants) +- [Guardian](#guardian) +- [Jobs](#jobs) +- [Logs](#logs) +- [Log Streams](#log-streams) +- [Organizations](#organizations) +- [Resource Servers](#resource-servers) +- [Roles](#roles) +- [Rules](#rules) +- [Stats](#stats) +- [Tenants](#tenants) +- [Tickets](#tickets) +- [User Blocks](#user-blocks) +- [Users](#users) +- [Users by Email](#users-by-email) ### Actions diff --git a/docs/Sessions.md b/docs/Sessions.md new file mode 100644 index 00000000..ef43f89e --- /dev/null +++ b/docs/Sessions.md @@ -0,0 +1,41 @@ +# Sessions + +In order to persist users' authentication states between HTTP requests, the Auth0 Laravel SDK uses Laravel's Session API to store and retrieve necessary data about the user. Applications can configure Laravel's Session API by modifying their `config/session.php` file. By default, sessions use the `file` driver, which stores the serialized user information in a file on the application server. However, you can configure the session store to use any of the other session drivers, such as `cookie`, `database`, `apc`, `memcached` and `redis`. + +It's important to note that all session drivers, except for `cookie`, require server-side storage of the session data. If you are using a load balancer or other server cluster, you must use a session driver that is shared across all of the servers. + +We strongly recommend using the `database` or `redis` session drivers for applications that use Auth0. These drivers are the most reliable and scalable options for storing session data. + +## Files + +The default session driver is `file`, which stores the session data in files on the server. It works well for simple applications, but it does not scale reliably beyond a single server. + +## Cookies + +The `cookie` session driver stores the session data in secure, encrypted cookies on the client device. Although convenient, this approach is not a reliable option for production applications as it suffers from a number of notable drawbacks: + +- Browsers impose a size limit of 4 KB on individual cookies, which can quickly be exceeded by storing session data. +- Laravel's cookie driver unfortunately does not "chunk" (split up) larger cookies into multiple cookies, so it is impossible to store more than the noted 4 KB of total session data. +- Most web servers and load balancers require additional configuration to accept and deliver larger cookie headers. + +If your application requires the use of cookies, please use the Auth0 PHP SDK's custom cookie session handler instead. This approach supports chunking of larger cookies, but is notably incompatible with [Octane](./Octane.md). Please refer to [Cookies.md](./Cookies.md) for more information. + +## Database + +The `database` session driver stores the session data in a database table. This is a very reliable option for applications of any size, but it does require a database connection to be configured for your application. + +## Redis + +The `redis` session driver stores the session data in a Redis database. This is an equally reliable option to the `database` driver. + +## APC + +The `apc` session driver stores the session data in the APC cache. This is a very fast and reliable option for applications of any size, but it does require the APC PHP extension to be installed on your server. + +## Memcached + +The `memcached` session driver stores the session data in a Memcached database. This is an equally reliable option to the `apc` driver, but it does require the Memcached PHP extension to be installed on your server. + +## Array (Testing) + +The `array` session driver stores the session data in a PHP array. This option is generally used for running tests on your application as it does not persist session data between requests. diff --git a/docs/Telescope.md b/docs/Telescope.md new file mode 100644 index 00000000..2c51ea71 --- /dev/null +++ b/docs/Telescope.md @@ -0,0 +1,50 @@ +# Laravel Telescope + +As of 7.11.0, the Auth0 Laravel SDK is compatible with Laravel's Telescope debugging package. However, there are some caveats to be aware of when using the two together. + +## Cause of Potential Issues + +Issues stem from the fact that Telescope attempts to attribute events it's recording to the authenticated user. While this is useful information to log, it presents a problem. Because Telescope hooks into a number number of events (including the cache, queries, and events system) that the SDK raises during its authentication resolution process, this can cause an infinite loop. + +When a request to your application occurs, the SDK works to determine if the end user is authenticated. It executes a number of authenticated related events that Telescope happens to record by default. When these events are recorded by Telescope it asks the authentication API to determine if the end user is authenticated, which in turn calls the SDK to determine if the end user is authenticated, and thus the loop begins. + +7.11.0 introduced special checks for when Telescope is installed to prevent this from occurring, but it may not cover all cases. + +If you are encountering Telescope causing infinite loops, you may need to disable the offending watchers in your `config/telescope.php` file. Alternatively, you can try wrapping any problematic code in Telescope's `withoutRecording()` method to prevent it from being recorded by Telescope. For example: + +```php +\Laravel\Telescope\Telescope::withoutRecording(function () { + // Your code here... +}); +``` + +## Missing Authentication Information from Telescope + +A side effect of the workarounds introduced in 7.11.0 that prevent Telescope from causing infinite loops is that Telescope may be unable to attribute recorded events triggered by the SDK to the authenticated user. This is intentional and necessary, and not a bug. + +## SDK <7.11.0 Workarounds + +In versions prior to 7.11.0, you may encounter a compatibility issue with the SDK and Telescope when installed and enabled together. You may need to disable offending watchers in your `config/telescope.php` file to resolve this. + +For example, if you are encountering issues with Telescope's `EventWatcher`, you can disable it in your `config/telescope.php` file, or ignore specific SDK events that are causing the issue. For example: + +```php + [ + Watchers\EventWatcher::class => [ + 'enabled' => env('TELESCOPE_EVENT_WATCHER', true), + 'ignore' => [ + \Auth0\Laravel\Events\Configuration\BuiltConfigurationEvent::class, + \Auth0\Laravel\Events\Configuration\BuildingConfigurationEvent::class, + ], + ], + ], + + // Other configuration options left out for brevity... +]; +``` diff --git a/docs/Users.md b/docs/Users.md index edfad40e..b441e8f3 100644 --- a/docs/Users.md +++ b/docs/Users.md @@ -1,9 +1,30 @@ # Users -- [Retrieving User Information](#retrieving-user-information) -- [Updating User Information](#updating-user-information) -- [Custom User Repositories](#custom-user-repositories) -- [Custom User Models](#custom-user-models) +- [User Persistenece](#user-persistenece) +- [Best Practices](#best-practices) +- [Retrieving User Information](#retrieving-user-information) +- [Updating User Information](#updating-user-information) +- [Extending the SDK](#extending-the-sdk) + - [User Repositories](#user-repositories) + - [Eloquent User Models](#eloquent-user-models) + +## User Persistence + +By default the SDK does not persist user information to a database. + +- When a user authenticates with your application, the SDK retrieves their profile data from Auth0 and stores it within their session. +- During each subsequent request, the SDK retrieves the stored profile data from the session and constructs a model representing the authenticated user from it. +- This user model is available to your application via the `Auth` facade or `auth()` helper for the duration of the current request. + +Later in this guide we'll demonstrate how you can extend this default behavior to persist that profile data to your application's database, if desired. + +## Best Practices + +Auth0 provides a number of features that can simplify your application's authentication and authorization workflows. It may be helpful to keep the following best practices in mind as you integrate the SDK into your application: + +- Treat Auth0 as the single source of truth about your users. +- If you must store user information in a database, store as little as possible. Treat any stored data as a cache, and sync it regularly using [the Management API](./Management.md). +- Always use the [the Management API](./Management.md) to update user information. If you're storing user information in a database, sync those changes to your database as needed, not the other way around. ## Retrieving User Information @@ -13,7 +34,7 @@ To retrieve information about the currently authenticated user, use the `user()` auth()->user(); ``` -You can also retrieve information on any user using [the Management API](./Management.md). This also returns extended information not usually contained in the authentication state such as user metadata. +You can also retrieve information on any user using [the Management API](./Management.md). This also returns extended information not usually contained in the session state, such as user metadata. ```php use Auth0\Laravel\Facade\Auth0; @@ -50,18 +71,24 @@ Route::get('/update', function () { })->middleware('auth'); ``` -## Custom User Repositories +## Extending the SDK + +### User Repositories + +By default the SDK does not store user information in your application's database. Instead, it uses the session to store the user's ID token, and retrieves user information from the token when needed. This is a good default behavior, but it may not be suitable for all applications. -The Auth0 Laravel SDK uses the repository pattern to allow the abstraction of potential database operations. This pattern is useful for building completely custom integrations that fit your application's needs. +The SDK uses a repository pattern to allow you to customize how user information is stored and retrieved. This allows you to use your own database to cache user information between authentication requests, or to use a different storage mechanism entirely. -### Creating a User Repository +#### Creating a User Repository -Creating a repository is simple: it must implement the `Auth0\Laravel\UserRepositoryContract` interface, and include two methods: +You can create your own user repository by extending the SDK's `Auth0\Laravel\UserRepositoryAbstract` class implementing the `Auth0\Laravel\UserRepositoryContract` interface. Your repository class need only implement two public methods, both of which should accept a `user` array parameter. -- `fromSession()` to construct a model for an authenticated user. -- `fromAccessToken` to construct a model representing an access token request. +- `fromSession()` to construct a model for an authenticated user. When called, the `user` array will contain the decoded ID token for the authenticated user. +- `fromAccessToken` to construct a model representing an access token request. When called, the `user` array will contain the decoded access token provided with the request. -The default implementation looks like this: +When these methods are called by the SDK, the `user` array will include all the information your application needs to construct an `Authenticatable` user model. + +The default `UserRepository` implementation looks like this: ```php $user['sub'], - ], [ - 'name' => $user['name'], - 'email' => $user['email'], - 'email_verified' => $user['email_verified'], - ]); - - return $user; + /* + $user = [ // Example of a decoded access token + "iss" => "https://example.auth0.com/", + "aud" => "https://api.example.com/calendar/v1/", + "sub" => "auth0|123456", + "exp" => 1458872196, + "iat" => 1458785796, + "scope" => "read write", + ]; + */ + + return User::where('auth0', $user['sub'])->first(); } public function fromSession(array $user): ?Authenticatable { - return User::where('auth0_id', $user['sub'])->first(); + /* + $user = [ // Example of a decoded ID token + "iss" => "http://example.auth0.com/", + "aud" => "client_id", + "sub" => "auth0|123456", + "exp" => 1458872196, + "iat" => 1458785796, + "name" => "Jane Doe", + "email" => "janedoe@example.com", + ]; + */ + + $user = User::updateOrCreate( + attributes: [ + 'auth0' => $user['sub'], + ], + values: [ + 'name' => $user['name'] ?? '', + 'email' => $user['email'] ?? '', + 'email_verified' => $user['email_verified'] ?? false, + ] + ); + + return $user; } } ``` -### Registering the Repository +Note that this example returns a custom user model, `App\Models\User`. You can find an example of this model in the [User Models](#user-models) section below. -The SDK uses it's own repository implementation by default, but you can override this with your own by updating your application's `config/auth.php` file. Simply point the value of the `repository` key to your repository class. +#### Registering a Repository + +You can override the SDK's default user repository by updating your application's `config/auth.php` file. Simply point the value of the `repository` key to your repository class. ```php 'providers' => [ @@ -135,43 +190,6 @@ The SDK uses it's own repository implementation by default, but you can override ], ``` -## Custom User Models - -The repository is responsible for retrieving and storing users, but does not itself define the models representing those users. To customize these, the SDK provides an abstract class that can be extended, `Auth0\Laravel\Users\UserAbstract`. +### Eloquent User Models -User models must implement the following interfaces: - -- `Illuminate\Contracts\Auth\Authenticatable` required by Laravel's authentication APIs. -- `Auth0\Laravel\Users\UserContract` required by the SDK. - -The abstract model already fulfills the requirements of these interfaces, so you can use it as-is if you do not require any additional functionality. - -Here's an example customer user model that extends the SDK's abstract user model class to support Eloquent: - -```php - diff --git a/rector.php b/rector.php index bfe928ea..4ee383cb 100644 --- a/rector.php +++ b/rector.php @@ -412,7 +412,6 @@ RemoveJustPropertyFetchForAssignRector::class, RemoveJustVariableAssignRector::class, RemoveLastReturnRector::class, - RemoveNonExistingVarAnnotationRector::class, RemoveNullPropertyInitializationRector::class, RemoveParentCallWithoutParentRector::class, RemoveParentCallWithoutParentRector::class, diff --git a/src/Bridges/SessionBridgeAbstract.php b/src/Bridges/SessionBridgeAbstract.php index 84572769..0403f558 100644 --- a/src/Bridges/SessionBridgeAbstract.php +++ b/src/Bridges/SessionBridgeAbstract.php @@ -8,6 +8,10 @@ use Illuminate\Session\Store; use InvalidArgumentException; +use function array_key_exists; +use function is_array; +use function is_string; + /** * @api */ @@ -37,7 +41,12 @@ final public function defer(bool $deferring): void */ final public function delete(string $key): void { - $this->getStore()->forget($this->getPrefixedKey($key)); + $payload = $this->getPayload() ?? []; + + if (array_key_exists($key, $payload)) { + unset($payload[$key]); + $this->getStore()->put($this->getPrefix(), json_encode(array_filter($payload), JSON_THROW_ON_ERROR)); + } } /** @@ -50,7 +59,9 @@ final public function delete(string $key): void */ final public function get(string $key, $default = null): mixed { - return $this->getStore()->get($this->getPrefixedKey($key), $default); + $payload = $this->getPayload() ?? []; + + return $payload[$key] ?? $default; } /** @@ -60,17 +71,7 @@ final public function get(string $key, $default = null): mixed */ final public function getAll(): array { - $pairs = $this->getStore()->all(); - $prefix = $this->prefix . '_'; - $response = []; - - foreach (array_keys($pairs) as $key) { - if (str_starts_with($key, $prefix)) { - $response[$key] = $pairs[$key]; - } - } - - return $response; + return $this->getPayload() ?? []; } /** @@ -90,11 +91,7 @@ final public function getPrefix(): string */ final public function purge(): void { - $entities = $this->getAll(); - - foreach (array_keys($entities) as $entity) { - $this->getStore()->forget($entity); - } + $this->getStore()->forget($this->getPrefix()); } /** @@ -107,7 +104,10 @@ final public function purge(): void */ final public function set(string $key, $value): void { - $this->getStore()->put($this->getPrefixedKey($key), $value); + $payload = $this->getPayload() ?? []; + $payload[$key] = $value; + + $this->getStore()->put($this->getPrefix(), json_encode($payload, JSON_THROW_ON_ERROR)); } /** @@ -131,14 +131,19 @@ final public function setPrefix( return $this; } - /** - * Prefixes a key with the SDK's configured namespace. - * - * @param string $key - */ - protected function getPrefixedKey(string $key): string + protected function getPayload(): ?array { - return $this->getPrefix() . '_' . trim($key); + $encoded = $this->getStore()->get($this->getPrefix()); + + if (is_string($encoded)) { + $decoded = json_decode($encoded, true, 512); + + if (is_array($decoded)) { + return $decoded; + } + } + + return null; } /** diff --git a/src/Controllers/CallbackControllerAbstract.php b/src/Controllers/CallbackControllerAbstract.php index c23ea955..4670a6a3 100644 --- a/src/Controllers/CallbackControllerAbstract.php +++ b/src/Controllers/CallbackControllerAbstract.php @@ -5,7 +5,8 @@ namespace Auth0\Laravel\Controllers; use Auth0\Laravel\Auth\Guard; -use Auth0\Laravel\Entities\{CredentialEntityContract, InstanceEntityContract}; +use Auth0\Laravel\Entities\CredentialEntityContract; +use Auth0\Laravel\Events; use Auth0\Laravel\Events\{AuthenticationFailed, AuthenticationSucceeded}; use Auth0\Laravel\Exceptions\ControllerException; use Auth0\Laravel\Exceptions\Controllers\CallbackControllerException; @@ -59,7 +60,7 @@ public function __invoke( */ try { if (null !== $code && null !== $state) { - event(new Attempting($guard::class, ['code' => $code, 'state' => $state], true)); + Events::framework(new Attempting($guard::class, ['code' => $code, 'state' => $state], true)); $success = $guard->sdk()->exchange( code: $code, @@ -72,16 +73,13 @@ public function __invoke( $credentials['state'] = $state; $credentials['error'] = ['description' => $throwable->getMessage()]; - event(new Failed($guard::class, $guard->user(), $credentials)); + Events::framework(new Failed($guard::class, $guard->user(), $credentials)); - $this->clearSession($guard); + session()->invalidate(); - // Throw hookable $event to allow custom error handling scenarios. - $event = new AuthenticationFailed($throwable, true); - event($event); + Events::dispatch($event = new AuthenticationFailed($throwable, true)); - // If the event was not hooked by the application, throw an exception: - if ($event->getThrowException()) { + if ($event->throwException) { throw $throwable; } } @@ -93,15 +91,15 @@ public function __invoke( $error = is_string($error) ? $error : ''; $errorDescription = is_string($errorDescription) ? $errorDescription : ''; - event(new Attempting($guard::class, ['code' => $code, 'state' => $state], true)); + Events::framework(new Attempting($guard::class, ['code' => $code, 'state' => $state], true)); - event(new Failed($guard::class, $guard->user(), [ + Events::framework(new Failed($guard::class, $guard->user(), [ 'code' => $code, 'state' => $state, 'error' => ['error' => $error, 'description' => $errorDescription], ])); - $this->clearSession($guard); + session()->invalidate(); // Create a dynamic exception to report the API error response $exception = new CallbackControllerException(sprintf(CallbackControllerException::MSG_API_RESPONSE, $error, $errorDescription)); @@ -109,12 +107,9 @@ public function __invoke( // Store the API exception in the session as a flash variable, in case the application wants to access it. session()->flash('auth0.callback.error', sprintf(CallbackControllerException::MSG_API_RESPONSE, $error, $errorDescription)); - // Throw hookable $event to allow custom error handling scenarios: - $event = new AuthenticationFailed($exception, true); - event($event); + Events::dispatch($event = new AuthenticationFailed($exception, true)); - // If the event was not hooked by the application, throw an exception: - if ($event->getThrowException()) { + if ($event->throwException) { throw $exception; } } @@ -128,50 +123,23 @@ public function __invoke( $user = $credential?->getUser(); if ($credential instanceof CredentialEntityContract && $user instanceof Authenticatable) { - event(new Validated($guard::class, $user)); + Events::framework(new Validated($guard::class, $user)); - $this->clearSession($guard); + session()->regenerate(true); /** * @var Guard $guard */ $guard->login($credential, Guard::SOURCE_SESSION); - $request->session()->invalidate(); - $request->session()->regenerate(); - - $event = new AuthenticationSucceeded($user); - event($event); - $user = $event->getUser(); - $guard->setUser($user); + Events::dispatch(new AuthenticationSucceeded($user)); // @phpstan-ignore-next-line if ($user instanceof Authenticatable) { - event(new Authenticated($guard::class, $user)); + Events::framework(new Authenticated($guard::class, $user)); } } return redirect()->intended('/'); } - - private function clearSession( - GuardAbstract $guard, - bool $clearTransientStorage = true, - bool $clearPersistentStorage = true, - bool $clearSdkStorage = true, - ): void { - $service = $guard->service() ?? null; - - if ($clearTransientStorage && $service instanceof InstanceEntityContract) { - $service->getConfiguration()->getTransientStorage()?->purge(); - } - - if ($clearPersistentStorage && $service instanceof InstanceEntityContract) { - $service->getConfiguration()->getSessionStorage()?->purge(); - } - - if ($clearSdkStorage) { - $guard->sdk()->clear(); - } - } } diff --git a/src/Controllers/LoginControllerAbstract.php b/src/Controllers/LoginControllerAbstract.php index a7438a91..3d3c5da1 100644 --- a/src/Controllers/LoginControllerAbstract.php +++ b/src/Controllers/LoginControllerAbstract.php @@ -6,6 +6,7 @@ use Auth0\Laravel\Auth\Guard; use Auth0\Laravel\Entities\CredentialEntityContract; +use Auth0\Laravel\Events; use Auth0\Laravel\Events\LoginAttempting; use Auth0\Laravel\Exceptions\ControllerException; use Auth0\Laravel\Guards\GuardAbstract; @@ -42,12 +43,11 @@ public function __invoke( return redirect()->intended('/'); } - $event = new LoginAttempting(); - event($event); + session()->regenerate(true); - $url = $guard->sdk()->login( - params: $event->getParameters(), - ); + Events::dispatch($event = new LoginAttempting()); + + $url = $guard->sdk()->login(params: $event->parameters); return redirect()->away($url); } diff --git a/src/Controllers/LogoutControllerAbstract.php b/src/Controllers/LogoutControllerAbstract.php index 342d508c..4acb0966 100644 --- a/src/Controllers/LogoutControllerAbstract.php +++ b/src/Controllers/LogoutControllerAbstract.php @@ -39,6 +39,7 @@ public function __invoke( if ($loggedIn) { session()->invalidate(); + $guard->logout(); /** @phpstan-ignore-line */ $route = (string) url('http://github.com/'); /** @phpstan-ignore-line */ $url = $guard->sdk()->authentication()->getLogoutLink($route); diff --git a/src/Entities/InstanceEntityAbstract.php b/src/Entities/InstanceEntityAbstract.php index deed06ba..e1f54f2c 100644 --- a/src/Entities/InstanceEntityAbstract.php +++ b/src/Entities/InstanceEntityAbstract.php @@ -6,7 +6,7 @@ use Auth0\Laravel\Bridges\{CacheBridge, SessionBridge}; use Auth0\Laravel\Events\Configuration\{BuildingConfigurationEvent, BuiltConfigurationEvent}; -use Auth0\Laravel\{Configuration, Service}; +use Auth0\Laravel\{Configuration, Events, Service}; use Auth0\SDK\Auth0; use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\SDK\Contract\API\ManagementInterface; @@ -148,7 +148,7 @@ protected function bootSessionStorage(array $config): array $sessionStorage = $config['sessionStorage'] ?? null; $sessionStorageId = $config['sessionStorageId'] ?? 'auth0_session'; - if (false === $sessionStorage) { + if (false === $sessionStorage || 'cookie' === $sessionStorage) { unset($config['sessionStorage']); return $config; @@ -212,7 +212,7 @@ protected function bootTransientStorage(array $config): array $transientStorage = $config['transientStorage'] ?? null; $transientStorageId = $config['transientStorageId'] ?? 'auth0_transient'; - if (false === $transientStorage) { + if (false === $transientStorage || 'cookie' === $transientStorage) { unset($config['transientStorage']); return $config; @@ -238,10 +238,7 @@ protected function bootTransientStorage(array $config): array protected function createConfiguration( array $configuration, ): SdkConfiguration { - // Give host application an opportunity to update the configuration before building configuration. - $event = new BuildingConfigurationEvent($configuration); - event($event); - $configuration = $event->getConfiguration(); + Events::dispatch(new BuildingConfigurationEvent($configuration)); $configuration = $this->bootStrategy($configuration); $configuration = $this->bootTokenCache($configuration); @@ -252,13 +249,11 @@ protected function createConfiguration( $configuration = $this->bootTransientStorage($configuration); } - $configuration = new SdkConfiguration($configuration); + $sdkConfiguration = new SdkConfiguration($configuration); - // Give host application an opportunity to update the configuration before applying it. - $event = new BuiltConfigurationEvent($configuration); - event($event); + Events::dispatch(new BuiltConfigurationEvent($sdkConfiguration)); - return $event->getConfiguration(); + return $sdkConfiguration; } protected function getManagementTokenCachePool(): CacheItemPoolInterface diff --git a/src/Events.php b/src/Events.php new file mode 100644 index 00000000..df25d6c0 --- /dev/null +++ b/src/Events.php @@ -0,0 +1,100 @@ + event(self::getName($event), $event)); + + return; + } + + event(self::getName($event), $event); + } + } + + public static function framework(object $event): void + { + if (self::$enabled) { + if (self::withoutTelescopeRecording($event::class)) { + self::TELESCOPE::withoutRecording(static fn (): mixed => event($event)); + + return; + } + + event($event); + } + } + + private static function getName(EventContract $event): string + { + return match ($event::class) { + AuthenticationFailed::class => self::AUTHENTICATION_FAILED, + AuthenticationSucceeded::class => self::AUTHENTICATION_SUCCEEDED, + BuildingConfigurationEvent::class => self::CONFIGURATION_BUILDING, + BuiltConfigurationEvent::class => self::CONFIGURATION_BUILT, + LoginAttempting::class => self::LOGIN_ATTEMPTING, + StatefulMiddlewareRequest::class => self::MIDDLEWARE_STATEFUL_REQUEST, + StatelessMiddlewareRequest::class => self::MIDDLEWARE_STATELESS_REQUEST, + TokenExpired::class => self::TOKEN_EXPIRED, + TokenRefreshFailed::class => self::TOKEN_REFRESH_FAILED, + TokenRefreshSucceeded::class => self::TOKEN_REFRESH_SUCCEEDED, + TokenVerificationAttempting::class => self::TOKEN_VERIFICATION_ATTEMPTING, + TokenVerificationFailed::class => self::TOKEN_VERIFICATION_FAILED, + TokenVerificationSucceeded::class => self::TOKEN_VERIFICATION_SUCCEEDED, + default => $event::class, + }; + } + + private static function withoutTelescopeRecording(string $event): bool + { + if (! class_exists(self::TELESCOPE)) { + return false; + } + + return match ($event) { + self::CONFIGURATION_BUILDING => true, + self::CONFIGURATION_BUILT => true, + default => false, + }; + } +} diff --git a/src/Events/Auth0EventContract.php b/src/Events/Auth0EventContract.php index 2cbb72ce..cb4e6950 100644 --- a/src/Events/Auth0EventContract.php +++ b/src/Events/Auth0EventContract.php @@ -9,8 +9,4 @@ */ interface Auth0EventContract extends EventContract { - /** - * Returns whether an event payload has been overwritten. - */ - public function wasMutated(): bool; } diff --git a/src/Events/AuthenticationFailed.php b/src/Events/AuthenticationFailed.php index ac116aa0..a59e30c9 100644 --- a/src/Events/AuthenticationFailed.php +++ b/src/Events/AuthenticationFailed.php @@ -5,7 +5,7 @@ namespace Auth0\Laravel\Events; /** - * Raised when an authentication attempt fails. + * Dispatched when user authentication fails. * * @api */ diff --git a/src/Events/AuthenticationFailedAbstract.php b/src/Events/AuthenticationFailedAbstract.php index 0ff4a8e2..2c865e7a 100644 --- a/src/Events/AuthenticationFailedAbstract.php +++ b/src/Events/AuthenticationFailedAbstract.php @@ -13,30 +13,24 @@ */ abstract class AuthenticationFailedAbstract extends EventAbstract { + /** + * @param Throwable $exception Exception to be thrown following this event. + * @param bool $throwException Whether or not $exception will be thrown + */ public function __construct( - protected Throwable $exception, - protected bool $throwException = true, + public Throwable &$exception, + public bool $throwException = true, ) { } - final public function getException(): Throwable + /** + * @psalm-suppress LessSpecificImplementedReturnType + */ + final public function jsonSerialize(): array { - return $this->exception; - } - - final public function getThrowException(): bool - { - return $this->throwException; - } - - final public function setException(Throwable $exception): void - { - $this->exception = $exception; - $this->mutated = true; - } - - final public function setThrowException(bool $throwException): void - { - $this->throwException = $throwException; + return [ + 'exception' => json_decode(json_encode($this->exception, JSON_THROW_ON_ERROR), true), + 'throwException' => $this->throwException, + ]; } } diff --git a/src/Events/AuthenticationFailedContract.php b/src/Events/AuthenticationFailedContract.php index 9eb231d2..04e6ee2d 100644 --- a/src/Events/AuthenticationFailedContract.php +++ b/src/Events/AuthenticationFailedContract.php @@ -4,42 +4,13 @@ namespace Auth0\Laravel\Events; -use Throwable; - /** * @api */ interface AuthenticationFailedContract extends EventContract { /** - * AuthenticationFailed constructor. - * - * @param Throwable $exception an exception instance in which to throw for the authentication failure - * @param bool $throwException whether or not $exception will be thrown - */ - public function __construct(Throwable $exception, bool $throwException = true); - - /** - * Returns the exception to be thrown. - */ - public function getException(): Throwable; - - /** - * Returns whether the provided exception will be thrown by the SDK. - */ - public function getThrowException(): bool; - - /** - * Overwrite the exception to be thrown. - * - * @param Throwable $exception an exception instance in which to throw for the authentication failure - */ - public function setException(Throwable $exception): void; - - /** - * Determine whether the provided exception will be thrown by the SDK. - * - * @param bool $throwException whether or not $exception will be thrown + * @return array{exception: array, throwException: bool} */ - public function setThrowException(bool $throwException): void; + public function jsonSerialize(): array; } diff --git a/src/Events/AuthenticationSucceeded.php b/src/Events/AuthenticationSucceeded.php index 301e304b..98228de1 100644 --- a/src/Events/AuthenticationSucceeded.php +++ b/src/Events/AuthenticationSucceeded.php @@ -5,7 +5,7 @@ namespace Auth0\Laravel\Events; /** - * Raised after a user has been successfully authenticated. + * Dispatched when a user successfully authenticates. * * @api */ diff --git a/src/Events/AuthenticationSucceededAbstract.php b/src/Events/AuthenticationSucceededAbstract.php index 0302cb84..b6c4e4e8 100644 --- a/src/Events/AuthenticationSucceededAbstract.php +++ b/src/Events/AuthenticationSucceededAbstract.php @@ -13,18 +13,23 @@ */ abstract class AuthenticationSucceededAbstract extends EventAbstract { - public function __construct(protected Authenticatable $user) - { - } - - final public function getUser(): Authenticatable - { - return $this->user; + /** + * @param Authenticatable $user The user that successfully authenticated. + */ + public function __construct( + public Authenticatable &$user, + ) { } - final public function setUser(Authenticatable $user): void + /** + * @psalm-suppress LessSpecificImplementedReturnType + * + * @return array{user: mixed} + */ + final public function jsonSerialize(): array { - $this->user = $user; - $this->mutated = true; + return [ + 'user' => json_decode(json_encode($this->user, JSON_THROW_ON_ERROR), true), + ]; } } diff --git a/src/Events/AuthenticationSucceededContract.php b/src/Events/AuthenticationSucceededContract.php index 098484a9..8c9b82b3 100644 --- a/src/Events/AuthenticationSucceededContract.php +++ b/src/Events/AuthenticationSucceededContract.php @@ -4,29 +4,13 @@ namespace Auth0\Laravel\Events; -use Illuminate\Contracts\Auth\Authenticatable; - /** * @api */ interface AuthenticationSucceededContract extends EventContract { /** - * AuthenticationSucceeded constructor. - * - * @param Authenticatable $user an instance of Authenticatable representing the authenticated user - */ - public function __construct(Authenticatable $user); - - /** - * Return the authenticated user. - */ - public function getUser(): Authenticatable; - - /** - * Overwrite the authenticated user. - * - * @param Authenticatable $user an instance of Authenticatable representing the authenticated user + * @return array{user: array} */ - public function setUser(Authenticatable $user): void; + public function jsonSerialize(): array; } diff --git a/src/Events/Configuration/BuildingConfigurationEvent.php b/src/Events/Configuration/BuildingConfigurationEvent.php index e3b0a1df..79a70b0c 100644 --- a/src/Events/Configuration/BuildingConfigurationEvent.php +++ b/src/Events/Configuration/BuildingConfigurationEvent.php @@ -5,7 +5,7 @@ namespace Auth0\Laravel\Events\Configuration; /** - * Event fired when the configuration array is being built. + * Dispatched immediately before the Auth0 SDK configuration object is built, allowing for modification of the configuration array. * * @api */ diff --git a/src/Events/Configuration/BuildingConfigurationEventAbstract.php b/src/Events/Configuration/BuildingConfigurationEventAbstract.php index 3b33147e..b8ab6d64 100644 --- a/src/Events/Configuration/BuildingConfigurationEventAbstract.php +++ b/src/Events/Configuration/BuildingConfigurationEventAbstract.php @@ -13,18 +13,23 @@ */ abstract class BuildingConfigurationEventAbstract extends EventAbstract { + /** + * @param array $configuration a configuration array for use with the Auth0-PHP SDK + */ public function __construct( - protected array $configuration, + public array &$configuration, ) { } - final public function getConfiguration(): array + /** + * @psalm-suppress LessSpecificImplementedReturnType + * + * @return array{configuration: mixed} + */ + final public function jsonSerialize(): array { - return $this->configuration; - } - - final public function setConfiguration(array $configuration): void - { - $this->configuration = $configuration; + return [ + 'configuration' => json_decode(json_encode($this->configuration, JSON_THROW_ON_ERROR), true), + ]; } } diff --git a/src/Events/Configuration/BuildingConfigurationEventContract.php b/src/Events/Configuration/BuildingConfigurationEventContract.php index 42f7ac38..ef907390 100644 --- a/src/Events/Configuration/BuildingConfigurationEventContract.php +++ b/src/Events/Configuration/BuildingConfigurationEventContract.php @@ -12,21 +12,7 @@ interface BuildingConfigurationEventContract extends EventContract { /** - * AuthenticationFailed constructor. - * - * @param array $configuration a configuration array for use with the Auth0-PHP SDK + * @return array{configuration: array} */ - public function __construct(array $configuration); - - /** - * Returns the exception to be thrown. - */ - public function getConfiguration(): array; - - /** - * Determine whether the provided exception will be thrown by the SDK. - * - * @param array $configuration an configuration array for use with the Auth0-PHP SDK - */ - public function setConfiguration(array $configuration): void; + public function jsonSerialize(): array; } diff --git a/src/Events/Configuration/BuiltConfigurationEvent.php b/src/Events/Configuration/BuiltConfigurationEvent.php index 92e68c29..8fd9db4a 100644 --- a/src/Events/Configuration/BuiltConfigurationEvent.php +++ b/src/Events/Configuration/BuiltConfigurationEvent.php @@ -5,7 +5,7 @@ namespace Auth0\Laravel\Events\Configuration; /** - * Event fired when the configuration array has been built. + * Dispatched after the Auth0 SDK configuration has been built and initialized. * * @api */ diff --git a/src/Events/Configuration/BuiltConfigurationEventAbstract.php b/src/Events/Configuration/BuiltConfigurationEventAbstract.php index 4d9472ad..4b5010f9 100644 --- a/src/Events/Configuration/BuiltConfigurationEventAbstract.php +++ b/src/Events/Configuration/BuiltConfigurationEventAbstract.php @@ -8,24 +8,29 @@ use Auth0\SDK\Configuration\SdkConfiguration; /** - * Event fired when the configuration array has been built. + * @internal * * @api */ abstract class BuiltConfigurationEventAbstract extends EventAbstract { + /** + * @param SdkConfiguration $configuration an instance of SdkConfiguration for use with the Auth0-PHP SDK + */ public function __construct( - protected SdkConfiguration $configuration, + public SdkConfiguration &$configuration, ) { } - final public function getConfiguration(): SdkConfiguration + /** + * @psalm-suppress LessSpecificImplementedReturnType + * + * @return array{configuration: mixed} + */ + final public function jsonSerialize(): array { - return $this->configuration; - } - - final public function setConfiguration(SdkConfiguration $configuration): void - { - $this->configuration = $configuration; + return [ + 'configuration' => json_decode(json_encode($this->configuration, JSON_THROW_ON_ERROR), true), + ]; } } diff --git a/src/Events/Configuration/BuiltConfigurationEventContract.php b/src/Events/Configuration/BuiltConfigurationEventContract.php index 0bb3bac7..45044467 100644 --- a/src/Events/Configuration/BuiltConfigurationEventContract.php +++ b/src/Events/Configuration/BuiltConfigurationEventContract.php @@ -5,7 +5,6 @@ namespace Auth0\Laravel\Events\Configuration; use Auth0\Laravel\Events\EventContract; -use Auth0\SDK\Configuration\SdkConfiguration; /** * @api @@ -13,21 +12,7 @@ interface BuiltConfigurationEventContract extends EventContract { /** - * AuthenticationFailed constructor. - * - * @param SdkConfiguration $configuration an instance of SdkConfiguration for use with the Auth0-PHP SDK + * @return array{configuration: array} */ - public function __construct(SdkConfiguration $configuration); - - /** - * Returns the exception to be thrown. - */ - public function getConfiguration(): SdkConfiguration; - - /** - * Determine whether the provided exception will be thrown by the SDK. - * - * @param SdkConfiguration $configuration an instance of SdkConfiguration for use with the Auth0-PHP SDK - */ - public function setConfiguration(SdkConfiguration $configuration): void; + public function jsonSerialize(): array; } diff --git a/src/Events/EventAbstract.php b/src/Events/EventAbstract.php index 6aec1603..847be779 100644 --- a/src/Events/EventAbstract.php +++ b/src/Events/EventAbstract.php @@ -4,23 +4,13 @@ namespace Auth0\Laravel\Events; +use JsonSerializable; + /** - * Base event class. + * @psalm-suppress UnsafeInstantiation,InvalidReturnType * * @api */ -abstract class EventAbstract +abstract class EventAbstract implements JsonSerializable { - /** - * Tracks whether an event payload has been overwritten. - */ - protected bool $mutated = false; - - /** - * Returns whether an event payload has been overwritten. - */ - final public function wasMutated(): bool - { - return $this->mutated; - } } diff --git a/src/Events/EventContract.php b/src/Events/EventContract.php index 16e3a1c8..0e3fdc87 100644 --- a/src/Events/EventContract.php +++ b/src/Events/EventContract.php @@ -10,7 +10,9 @@ interface EventContract { /** - * Returns whether an event payload has been overwritten. + * A representation of the event context which can be serialized by json_encode(). + * + * @psalm-suppress LessSpecificImplementedReturnType */ - public function wasMutated(): bool; + public function jsonSerialize(): mixed; } diff --git a/src/Events/LoginAttempting.php b/src/Events/LoginAttempting.php index b211e4db..7dd8fdad 100644 --- a/src/Events/LoginAttempting.php +++ b/src/Events/LoginAttempting.php @@ -5,7 +5,7 @@ namespace Auth0\Laravel\Events; /** - * Raised when a login attempt is made. + * Dispatched when a user tries to login. * * @api */ diff --git a/src/Events/LoginAttemptingAbstract.php b/src/Events/LoginAttemptingAbstract.php index aa5e43a7..ac031b54 100644 --- a/src/Events/LoginAttemptingAbstract.php +++ b/src/Events/LoginAttemptingAbstract.php @@ -11,18 +11,23 @@ */ abstract class LoginAttemptingAbstract extends EventAbstract { + /** + * @param array $parameters Additional API parameters to be sent with the authentication request. + */ public function __construct( - protected array $parameters = [], + public array $parameters = [], ) { } - final public function getParameters(): array + /** + * @psalm-suppress LessSpecificImplementedReturnType + * + * @return array{parameters: mixed} + */ + final public function jsonSerialize(): array { - return $this->parameters; - } - - final public function setParameters(array $parameters): void - { - $this->parameters = $parameters; + return [ + 'parameters' => json_decode(json_encode($this->parameters, JSON_THROW_ON_ERROR), true), + ]; } } diff --git a/src/Events/LoginAttemptingContract.php b/src/Events/LoginAttemptingContract.php index 163f6a74..83ed5305 100644 --- a/src/Events/LoginAttemptingContract.php +++ b/src/Events/LoginAttemptingContract.php @@ -10,21 +10,7 @@ interface LoginAttemptingContract extends EventContract { /** - * @param array $parameters The login parameters array. + * @return array{parameters: array} */ - public function __construct( - array $parameters = [], - ); - - /** - * Returns the login parameters array. - */ - public function getParameters(): array; - - /** - * Replace the login parameters array. - * - * @param array $parameters - */ - public function setParameters(array $parameters): void; + public function jsonSerialize(): array; } diff --git a/src/Events/Middleware/StatefulMiddlewareRequest.php b/src/Events/Middleware/StatefulMiddlewareRequest.php index 8a8987f8..62499a8e 100644 --- a/src/Events/Middleware/StatefulMiddlewareRequest.php +++ b/src/Events/Middleware/StatefulMiddlewareRequest.php @@ -4,6 +4,11 @@ namespace Auth0\Laravel\Events\Middleware; +/** + * Dispatched when an incoming request is being processed by the stateful middleware. + * + * @api + */ final class StatefulMiddlewareRequest extends StatefulMiddlewareRequestAbstract implements StatefulMiddlewareRequestContract { } diff --git a/src/Events/Middleware/StatefulMiddlewareRequestAbstract.php b/src/Events/Middleware/StatefulMiddlewareRequestAbstract.php index ab0ac6fa..fd390293 100644 --- a/src/Events/Middleware/StatefulMiddlewareRequestAbstract.php +++ b/src/Events/Middleware/StatefulMiddlewareRequestAbstract.php @@ -5,14 +5,36 @@ namespace Auth0\Laravel\Events\Middleware; use Auth0\Laravel\Events\EventAbstract; -use Auth0\Laravel\Guards\GuardContract; +use Illuminate\Contracts\Auth\Guard; use Illuminate\Http\Request; +/** + * @internal + * + * @api + */ abstract class StatefulMiddlewareRequestAbstract extends EventAbstract { + /** + * @param Request $request Incoming request. + * @param Guard $guard The guard being used to authenticate the request. + */ public function __construct( - public Request $request, - public GuardContract $guard, + public Request &$request, + public Guard &$guard, ) { } + + /** + * @psalm-suppress LessSpecificImplementedReturnType + * + * @return array{request: mixed, guard: mixed} + */ + final public function jsonSerialize(): array + { + return [ + 'request' => json_decode(json_encode($this->request, JSON_THROW_ON_ERROR), true), + 'guard' => json_decode(json_encode($this->guard, JSON_THROW_ON_ERROR), true), + ]; + } } diff --git a/src/Events/Middleware/StatefulMiddlewareRequestContract.php b/src/Events/Middleware/StatefulMiddlewareRequestContract.php index 7c15c2cc..26bbc83a 100644 --- a/src/Events/Middleware/StatefulMiddlewareRequestContract.php +++ b/src/Events/Middleware/StatefulMiddlewareRequestContract.php @@ -5,10 +5,16 @@ namespace Auth0\Laravel\Events\Middleware; use Auth0\Laravel\Events\EventContract; +use Illuminate\Contracts\Auth\Guard; +use Illuminate\Http\Request; /** * @api */ interface StatefulMiddlewareRequestContract extends EventContract { + /** + * @return array{request: array, guard: array} + */ + public function jsonSerialize(): array; } diff --git a/src/Events/Middleware/StatelessMiddlewareRequest.php b/src/Events/Middleware/StatelessMiddlewareRequest.php index fc02d40b..48940d38 100644 --- a/src/Events/Middleware/StatelessMiddlewareRequest.php +++ b/src/Events/Middleware/StatelessMiddlewareRequest.php @@ -4,6 +4,11 @@ namespace Auth0\Laravel\Events\Middleware; +/** + * Dispatched when an incoming request is being processed by the stateless middleware. + * + * @api + */ final class StatelessMiddlewareRequest extends StatelessMiddlewareRequestAbstract implements StatelessMiddlewareRequestContract { } diff --git a/src/Events/Middleware/StatelessMiddlewareRequestAbstract.php b/src/Events/Middleware/StatelessMiddlewareRequestAbstract.php index 83852917..18778333 100644 --- a/src/Events/Middleware/StatelessMiddlewareRequestAbstract.php +++ b/src/Events/Middleware/StatelessMiddlewareRequestAbstract.php @@ -5,14 +5,36 @@ namespace Auth0\Laravel\Events\Middleware; use Auth0\Laravel\Events\EventAbstract; -use Auth0\Laravel\Guards\GuardContract; +use Illuminate\Contracts\Auth\Guard; use Illuminate\Http\Request; +/** + * @internal + * + * @api + */ abstract class StatelessMiddlewareRequestAbstract extends EventAbstract { + /** + * @param Request $request Incoming request. + * @param Guard $guard The guard being used to authenticate the request. + */ public function __construct( - public Request $request, - public GuardContract $guard, + public Request &$request, + public Guard &$guard, ) { } + + /** + * @psalm-suppress LessSpecificImplementedReturnType + * + * @return array{request: mixed, guard: mixed} + */ + final public function jsonSerialize(): array + { + return [ + 'request' => json_decode(json_encode($this->request, JSON_THROW_ON_ERROR), true), + 'guard' => json_decode(json_encode($this->guard, JSON_THROW_ON_ERROR), true), + ]; + } } diff --git a/src/Events/Middleware/StatelessMiddlewareRequestContract.php b/src/Events/Middleware/StatelessMiddlewareRequestContract.php index 0de4a5ab..413eca75 100644 --- a/src/Events/Middleware/StatelessMiddlewareRequestContract.php +++ b/src/Events/Middleware/StatelessMiddlewareRequestContract.php @@ -5,10 +5,16 @@ namespace Auth0\Laravel\Events\Middleware; use Auth0\Laravel\Events\EventContract; +use Illuminate\Contracts\Auth\Guard; +use Illuminate\Http\Request; /** * @api */ interface StatelessMiddlewareRequestContract extends EventContract { + /** + * @return array{request: array, guard: array} + */ + public function jsonSerialize(): array; } diff --git a/src/Events/TokenExpired.php b/src/Events/TokenExpired.php index fa300037..65cbd14f 100644 --- a/src/Events/TokenExpired.php +++ b/src/Events/TokenExpired.php @@ -5,7 +5,7 @@ namespace Auth0\Laravel\Events; /** - * Raised when a token has expired. + * Dispatched when an access token has expired. * * @api */ diff --git a/src/Events/TokenExpiredAbstract.php b/src/Events/TokenExpiredAbstract.php index 28f58ec1..9d149e18 100644 --- a/src/Events/TokenExpiredAbstract.php +++ b/src/Events/TokenExpiredAbstract.php @@ -11,4 +11,8 @@ */ abstract class TokenExpiredAbstract extends EventAbstract { + final public function jsonSerialize(): null + { + return null; + } } diff --git a/src/Events/TokenExpiredContract.php b/src/Events/TokenExpiredContract.php index d95b9928..877eae00 100644 --- a/src/Events/TokenExpiredContract.php +++ b/src/Events/TokenExpiredContract.php @@ -9,4 +9,5 @@ */ interface TokenExpiredContract extends EventContract { + public function jsonSerialize(): null; } diff --git a/src/Events/TokenRefreshFailed.php b/src/Events/TokenRefreshFailed.php index e6329468..9c6aa50a 100644 --- a/src/Events/TokenRefreshFailed.php +++ b/src/Events/TokenRefreshFailed.php @@ -5,7 +5,7 @@ namespace Auth0\Laravel\Events; /** - * Raised when a token refresh attempt fails. + * Dispatched when a token refresh fails. * * @api */ diff --git a/src/Events/TokenRefreshFailedAbstract.php b/src/Events/TokenRefreshFailedAbstract.php index 0feccef8..e952412e 100644 --- a/src/Events/TokenRefreshFailedAbstract.php +++ b/src/Events/TokenRefreshFailedAbstract.php @@ -11,4 +11,8 @@ */ abstract class TokenRefreshFailedAbstract extends EventAbstract { + final public function jsonSerialize(): null + { + return null; + } } diff --git a/src/Events/TokenRefreshFailedContract.php b/src/Events/TokenRefreshFailedContract.php index 54e0948c..56738578 100644 --- a/src/Events/TokenRefreshFailedContract.php +++ b/src/Events/TokenRefreshFailedContract.php @@ -9,4 +9,5 @@ */ interface TokenRefreshFailedContract extends EventContract { + public function jsonSerialize(): null; } diff --git a/src/Events/TokenRefreshSucceeded.php b/src/Events/TokenRefreshSucceeded.php index 0d4c498f..6f03b634 100644 --- a/src/Events/TokenRefreshSucceeded.php +++ b/src/Events/TokenRefreshSucceeded.php @@ -5,7 +5,7 @@ namespace Auth0\Laravel\Events; /** - * Raised after a token has been successfully refreshed. + * Dispatched when an access token is successfully refreshed. * * @api */ diff --git a/src/Events/TokenRefreshSucceededAbstract.php b/src/Events/TokenRefreshSucceededAbstract.php index 168d40ff..40c6284b 100644 --- a/src/Events/TokenRefreshSucceededAbstract.php +++ b/src/Events/TokenRefreshSucceededAbstract.php @@ -11,4 +11,8 @@ */ abstract class TokenRefreshSucceededAbstract extends EventAbstract { + final public function jsonSerialize(): null + { + return null; + } } diff --git a/src/Events/TokenRefreshSucceededContract.php b/src/Events/TokenRefreshSucceededContract.php index d0b5ec54..b7a54be1 100644 --- a/src/Events/TokenRefreshSucceededContract.php +++ b/src/Events/TokenRefreshSucceededContract.php @@ -9,4 +9,5 @@ */ interface TokenRefreshSucceededContract extends EventContract { + public function jsonSerialize(): null; } diff --git a/src/Events/TokenVerificationAttempting.php b/src/Events/TokenVerificationAttempting.php index 614f039a..3be433de 100644 --- a/src/Events/TokenVerificationAttempting.php +++ b/src/Events/TokenVerificationAttempting.php @@ -5,7 +5,7 @@ namespace Auth0\Laravel\Events; /** - * Raised when a token verification attempt is made. + * Dispatched before a token verification is performed. * * @api */ diff --git a/src/Events/TokenVerificationAttemptingAbstract.php b/src/Events/TokenVerificationAttemptingAbstract.php index 3809cd53..053f791b 100644 --- a/src/Events/TokenVerificationAttemptingAbstract.php +++ b/src/Events/TokenVerificationAttemptingAbstract.php @@ -11,19 +11,23 @@ */ abstract class TokenVerificationAttemptingAbstract extends EventAbstract { + /** + * @param string $token Encoded JSON Web Token that will be verification. + */ public function __construct( - protected string $token, + public string $token, ) { } - final public function getToken(): string + /** + * @psalm-suppress LessSpecificImplementedReturnType + * + * @return array{token: string} + */ + final public function jsonSerialize(): array { - return $this->token; - } - - final public function setToken(string $token): void - { - $this->token = $token; - $this->mutated = true; + return [ + 'token' => $this->token, + ]; } } diff --git a/src/Events/TokenVerificationAttemptingContract.php b/src/Events/TokenVerificationAttemptingContract.php index 1a61f755..cd2fd325 100644 --- a/src/Events/TokenVerificationAttemptingContract.php +++ b/src/Events/TokenVerificationAttemptingContract.php @@ -10,21 +10,7 @@ interface TokenVerificationAttemptingContract extends EventContract { /** - * AuthenticationSucceeded constructor. - * - * @param string $token a bearer JSON web token + * @return array{token: string} */ - public function __construct(string $token); - - /** - * Return the bearer JSON web token. - */ - public function getToken(): string; - - /** - * Overwrite the bearer JSON web token. - * - * @param string $token a bearer JSON web token - */ - public function setToken(string $token): void; + public function jsonSerialize(): array; } diff --git a/src/Events/TokenVerificationFailed.php b/src/Events/TokenVerificationFailed.php index c332978c..d6e5f895 100644 --- a/src/Events/TokenVerificationFailed.php +++ b/src/Events/TokenVerificationFailed.php @@ -5,7 +5,7 @@ namespace Auth0\Laravel\Events; /** - * Raised when a token has failed verification. + * Dispatched when a token fails verification. * * @api */ diff --git a/src/Events/TokenVerificationFailedAbstract.php b/src/Events/TokenVerificationFailedAbstract.php index 8c7ae9c1..7f6f4854 100644 --- a/src/Events/TokenVerificationFailedAbstract.php +++ b/src/Events/TokenVerificationFailedAbstract.php @@ -13,19 +13,27 @@ */ abstract class TokenVerificationFailedAbstract extends EventAbstract { + /** + * @param string $token Encoded JSON Web Token that failed verification. + * @param Throwable $exception Exception to be thrown following this event. + * @param bool $throwException Whether or not $exception will be thrown + */ public function __construct( - protected string $token, - protected Throwable $exception, + public string $token, + public Throwable &$exception, + public bool $throwException = false, ) { } - final public function getException(): Throwable + /** + * @psalm-suppress LessSpecificImplementedReturnType + */ + final public function jsonSerialize(): array { - return $this->exception; - } - - final public function getToken(): string - { - return $this->token; + return [ + 'token' => $this->token, + 'exception' => json_decode(json_encode($this->exception, JSON_THROW_ON_ERROR), true), + 'throwException' => $this->throwException, + ]; } } diff --git a/src/Events/TokenVerificationFailedContract.php b/src/Events/TokenVerificationFailedContract.php index 0b88514a..9574a7fa 100644 --- a/src/Events/TokenVerificationFailedContract.php +++ b/src/Events/TokenVerificationFailedContract.php @@ -4,31 +4,13 @@ namespace Auth0\Laravel\Events; -use Throwable; - /** * @api */ interface TokenVerificationFailedContract extends EventContract { /** - * AuthenticationFailed constructor. - * - * @param string $token an encoded bearer JSON web token - * @param Throwable $exception an exception instance in which to throw for the token verification failure - */ - public function __construct( - string $token, - Throwable $exception, - ); - - /** - * Returns the exception to be thrown. - */ - public function getException(): Throwable; - - /** - * Return the bearer JSON web token. + * @return array{token: string, exception: array, throwException: bool} */ - public function getToken(): string; + public function jsonSerialize(): array; } diff --git a/src/Events/TokenVerificationSucceeded.php b/src/Events/TokenVerificationSucceeded.php index 284242e7..48aafc82 100644 --- a/src/Events/TokenVerificationSucceeded.php +++ b/src/Events/TokenVerificationSucceeded.php @@ -5,7 +5,7 @@ namespace Auth0\Laravel\Events; /** - * Raised when a token has been successfully verified. + * Dispatched when a token is successfully verified. * * @api */ diff --git a/src/Events/TokenVerificationSucceededAbstract.php b/src/Events/TokenVerificationSucceededAbstract.php index aa7c25ed..44a486b8 100644 --- a/src/Events/TokenVerificationSucceededAbstract.php +++ b/src/Events/TokenVerificationSucceededAbstract.php @@ -11,19 +11,26 @@ */ abstract class TokenVerificationSucceededAbstract extends EventAbstract { + /** + * @param string $token JSON Web Token that was verified. + * @param array $payload The decoded contents of the verified JSON Web Token. + */ public function __construct( - protected string $token, - protected array $payload, + public string $token, + public array $payload, ) { } - final public function getPayload(): array + /** + * @psalm-suppress LessSpecificImplementedReturnType + * + * @return array{token: string, payload: mixed[]} + */ + final public function jsonSerialize(): array { - return $this->payload; - } - - final public function getToken(): string - { - return $this->token; + return [ + 'token' => $this->token, + 'payload' => $this->payload, + ]; } } diff --git a/src/Events/TokenVerificationSucceededContract.php b/src/Events/TokenVerificationSucceededContract.php index f2a2c493..f98f14f7 100644 --- a/src/Events/TokenVerificationSucceededContract.php +++ b/src/Events/TokenVerificationSucceededContract.php @@ -10,23 +10,7 @@ interface TokenVerificationSucceededContract extends EventContract { /** - * AuthenticationSucceeded constructor. - * - * @param string $token a bearer JSON web token - * @param array $payload the bearer JSON web token's decoded payload + * @return array{token: string, payload: array} */ - public function __construct( - string $token, - array $payload, - ); - - /** - * Return the bearer JSON web token's decoded payload. - */ - public function getPayload(): array; - - /** - * Return the bearer JSON web token. - */ - public function getToken(): string; + public function jsonSerialize(): array; } diff --git a/src/EventsContract.php b/src/EventsContract.php new file mode 100644 index 00000000..5ad8b9c9 --- /dev/null +++ b/src/EventsContract.php @@ -0,0 +1,118 @@ + + */ + public const AUTHENTICATION_FAILED = AuthenticationFailed::class; + + /** + * @var class-string<\Auth0\Laravel\Events\AuthenticationSucceeded> + */ + public const AUTHENTICATION_SUCCEEDED = AuthenticationSucceeded::class; + + /** + * @var class-string<\Auth0\Laravel\Events\Configuration\BuildingConfigurationEvent> + */ + public const CONFIGURATION_BUILDING = BuildingConfigurationEvent::class; + + /** + * @var class-string<\Auth0\Laravel\Events\Configuration\BuiltConfigurationEvent> + */ + public const CONFIGURATION_BUILT = BuiltConfigurationEvent::class; + + /** + * @var class-string<\Auth0\Laravel\Events\LoginAttempting> + */ + public const LOGIN_ATTEMPTING = LoginAttempting::class; + + /** + * @var class-string<\Auth0\Laravel\Events\Middleware\StatefulMiddlewareRequest> + */ + public const MIDDLEWARE_STATEFUL_REQUEST = StatefulMiddlewareRequest::class; + + /** + * @var class-string<\Auth0\Laravel\Events\Middleware\StatelessMiddlewareRequest> + */ + public const MIDDLEWARE_STATELESS_REQUEST = StatelessMiddlewareRequest::class; + + /** + * @var class-string<\Auth0\Laravel\Events\TokenExpired> + */ + public const TOKEN_EXPIRED = TokenExpired::class; + + /** + * @var class-string<\Auth0\Laravel\Events\TokenRefreshFailed> + */ + public const TOKEN_REFRESH_FAILED = TokenRefreshFailed::class; + + /** + * @var class-string<\Auth0\Laravel\Events\TokenRefreshSucceeded> + */ + public const TOKEN_REFRESH_SUCCEEDED = TokenRefreshSucceeded::class; + + /** + * @var class-string<\Auth0\Laravel\Events\TokenVerificationAttempting> + */ + public const TOKEN_VERIFICATION_ATTEMPTING = TokenVerificationAttempting::class; + + /** + * @var class-string<\Auth0\Laravel\Events\TokenVerificationFailed> + */ + public const TOKEN_VERIFICATION_FAILED = TokenVerificationFailed::class; + + /** + * @var class-string<\Auth0\Laravel\Events\TokenVerificationSucceeded> + */ + public const TOKEN_VERIFICATION_SUCCEEDED = TokenVerificationSucceeded::class; + + /** + * Dispatch an SDK event. + * + * @param EventContract $event The event to dispatch. + */ + public static function dispatch( + EventContract $event, + ): void; + + /** + * Dispatch a Laravel framework event. + * + * @param object $event The event to dispatch. + */ + public static function framework( + object $event, + ): void; +} diff --git a/src/Guards/AuthenticationGuard.php b/src/Guards/AuthenticationGuard.php index 11fdc6d0..1f992962 100644 --- a/src/Guards/AuthenticationGuard.php +++ b/src/Guards/AuthenticationGuard.php @@ -5,6 +5,7 @@ namespace Auth0\Laravel\Guards; use Auth0\Laravel\Entities\{CredentialEntity, CredentialEntityContract}; +use Auth0\Laravel\Events; use Auth0\Laravel\Events\{TokenRefreshFailed, TokenRefreshSucceeded}; use Auth0\Laravel\Users\StatefulUser; use Auth0\SDK\Configuration\SdkConfiguration; @@ -105,7 +106,7 @@ public function login( $user = $credential->getUser(); if ($user instanceof Authenticatable) { - event(new Login(self::class, $user, true)); + Events::framework(new Login(self::class, $user, true)); } } @@ -117,7 +118,7 @@ public function logout(): self $user = $this->user(); if ($user instanceof Authenticatable) { - event(new Logout(self::class, $user)); + Events::framework(new Logout(self::class, $user)); } $this->stopImpersonating(); @@ -272,10 +273,40 @@ public function user(): ?Authenticatable return $this->getImposter()?->getUser(); } + static $lastResponse = null; + + /** + * @var ?Authenticatable $lastResponse + */ + if (class_exists('\Laravel\Telescope\Telescope')) { + static $depth = 0; + static $lastCalled = null; + + /** + * @var int $depth + * @var ?int $lastCalled + */ + if (null === $lastCalled) { + $lastCalled = time(); + } + + if (time() - $lastCalled > 10) { + $lastResponse = null; + $depth = 0; + } + + if ($depth >= 1) { + return $lastResponse; + } + + ++$depth; + $lastCalled = time(); + } + $currentUser = $this->getCredential()?->getUser(); if ($currentUser instanceof Authenticatable) { - return $currentUser; + return $lastResponse = $currentUser; } $session = $this->find(); @@ -283,10 +314,10 @@ public function user(): ?Authenticatable if ($session instanceof CredentialEntityContract) { $this->login($session); - return $this->getCredential()?->getUser(); + return $lastResponse = $this->getCredential()?->getUser(); } - return null; + return $lastResponse = null; } private function pullState(): ?CredentialEntityContract @@ -337,12 +368,12 @@ private function refreshSession( $this->sdk()->renew(); $session = $this->pullState(); } catch (\Throwable) { - event(new TokenRefreshFailed()); + Events::dispatch(new TokenRefreshFailed()); $session = null; } if ($session instanceof CredentialEntityContract) { - event(new TokenRefreshSucceeded()); + Events::dispatch(new TokenRefreshSucceeded()); $user = $session->getUser(); // @codeCoverageIgnoreStart diff --git a/src/Guards/GuardAbstract.php b/src/Guards/GuardAbstract.php index 4e71107f..2eb9b90a 100644 --- a/src/Guards/GuardAbstract.php +++ b/src/Guards/GuardAbstract.php @@ -5,6 +5,7 @@ namespace Auth0\Laravel\Guards; use Auth0\Laravel\Entities\{CredentialEntityContract, InstanceEntity, InstanceEntityContract}; +use Auth0\Laravel\Events; use Auth0\Laravel\Events\{TokenVerificationAttempting, TokenVerificationFailed, TokenVerificationSucceeded}; use Auth0\Laravel\Exceptions\{AuthenticationException, GuardException, GuardExceptionContract}; use Auth0\SDK\Contract\API\ManagementInterface; @@ -206,20 +207,23 @@ final public function management(): ManagementInterface final public function processToken( string $token, ): ?array { - $event = new TokenVerificationAttempting($token); - event($event); - $token = $event->getToken(); + Events::dispatch($event = new TokenVerificationAttempting($token)); + $token = $event->token; $decoded = null; try { $decoded = $this->sdk()->decode(token: $token, tokenType: Token::TYPE_ACCESS_TOKEN)->toArray(); } catch (InvalidTokenException $invalidTokenException) { - event(new TokenVerificationFailed($token, $invalidTokenException)); + Events::dispatch($event = new TokenVerificationFailed($token, $invalidTokenException)); + + if ($event->throwException) { + throw $invalidTokenException; + } return null; } - event(new TokenVerificationSucceeded($token, $decoded)); + Events::dispatch(new TokenVerificationSucceeded($token, $decoded)); return $decoded; } diff --git a/src/Middleware/AuthenticateMiddlewareAbstract.php b/src/Middleware/AuthenticateMiddlewareAbstract.php index e27df366..fd5ae826 100644 --- a/src/Middleware/AuthenticateMiddlewareAbstract.php +++ b/src/Middleware/AuthenticateMiddlewareAbstract.php @@ -4,10 +4,10 @@ namespace Auth0\Laravel\Middleware; -use Auth0\Laravel\Auth\Guard; use Auth0\Laravel\Entities\CredentialEntityContract; +use Auth0\Laravel\Events; use Auth0\Laravel\Events\Middleware\StatefulMiddlewareRequest; -use Auth0\Laravel\Guards\GuardContract; +use Auth0\Laravel\Guards\{AuthenticationGuardContract, GuardContract}; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; @@ -19,6 +19,13 @@ */ abstract class AuthenticateMiddlewareAbstract extends MiddlewareAbstract { + /** + * @psalm-suppress UndefinedInterfaceMethod + * + * @param Request $request + * @param Closure $next + * @param string $scope + */ final public function handle( Request $request, Closure $next, @@ -28,11 +35,11 @@ final public function handle( $scope = trim($scope); if (! $guard instanceof GuardContract) { + ray($guard, config()); abort(Response::HTTP_INTERNAL_SERVER_ERROR, 'Internal Server Error'); } - /** @var Guard $guard */ - event(new StatefulMiddlewareRequest($request, $guard)); + Events::dispatch(new StatefulMiddlewareRequest($request, $guard)); $credential = $guard->find(GuardContract::SOURCE_SESSION); diff --git a/src/Middleware/AuthenticateOptionalMiddlewareAbstract.php b/src/Middleware/AuthenticateOptionalMiddlewareAbstract.php index 83623c67..15585cfd 100644 --- a/src/Middleware/AuthenticateOptionalMiddlewareAbstract.php +++ b/src/Middleware/AuthenticateOptionalMiddlewareAbstract.php @@ -4,10 +4,10 @@ namespace Auth0\Laravel\Middleware; -use Auth0\Laravel\Auth\Guard; use Auth0\Laravel\Entities\CredentialEntityContract; +use Auth0\Laravel\Events; use Auth0\Laravel\Events\Middleware\StatefulMiddlewareRequest; -use Auth0\Laravel\Guards\GuardContract; +use Auth0\Laravel\Guards\{AuthenticationGuardContract, GuardContract}; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; @@ -19,6 +19,13 @@ */ abstract class AuthenticateOptionalMiddlewareAbstract extends MiddlewareAbstract { + /** + * @psalm-suppress UndefinedInterfaceMethod + * + * @param Request $request + * @param Closure $next + * @param string $scope + */ final public function handle( Request $request, Closure $next, @@ -30,8 +37,7 @@ final public function handle( abort(Response::HTTP_INTERNAL_SERVER_ERROR, 'Internal Server Error'); } - /** @var Guard $guard */ - event(new StatefulMiddlewareRequest($request, $guard)); + Events::dispatch(new StatefulMiddlewareRequest($request, $guard)); $credential = $guard->find(GuardContract::SOURCE_SESSION); diff --git a/src/Middleware/AuthorizeMiddlewareAbstract.php b/src/Middleware/AuthorizeMiddlewareAbstract.php index d7081636..c23b6d4d 100644 --- a/src/Middleware/AuthorizeMiddlewareAbstract.php +++ b/src/Middleware/AuthorizeMiddlewareAbstract.php @@ -4,10 +4,10 @@ namespace Auth0\Laravel\Middleware; -use Auth0\Laravel\Auth\Guard; use Auth0\Laravel\Entities\CredentialEntityContract; +use Auth0\Laravel\Events; use Auth0\Laravel\Events\Middleware\StatelessMiddlewareRequest; -use Auth0\Laravel\Guards\GuardContract; +use Auth0\Laravel\Guards\{AuthorizationGuardContract, GuardContract}; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; @@ -19,6 +19,13 @@ */ abstract class AuthorizeMiddlewareAbstract extends MiddlewareAbstract { + /** + * @psalm-suppress UndefinedInterfaceMethod + * + * @param Request $request + * @param Closure $next + * @param string $scope + */ final public function handle( Request $request, Closure $next, @@ -30,8 +37,7 @@ final public function handle( return $next($request); } - /** @var Guard $guard */ - event(new StatelessMiddlewareRequest($request, $guard)); + Events::dispatch(new StatelessMiddlewareRequest($request, $guard)); $credential = $guard->find(GuardContract::SOURCE_TOKEN); diff --git a/src/Middleware/AuthorizeOptionalMiddlewareAbstract.php b/src/Middleware/AuthorizeOptionalMiddlewareAbstract.php index f1a3f49b..091d270b 100644 --- a/src/Middleware/AuthorizeOptionalMiddlewareAbstract.php +++ b/src/Middleware/AuthorizeOptionalMiddlewareAbstract.php @@ -4,10 +4,10 @@ namespace Auth0\Laravel\Middleware; -use Auth0\Laravel\Auth\Guard; use Auth0\Laravel\Entities\CredentialEntityContract; +use Auth0\Laravel\Events; use Auth0\Laravel\Events\Middleware\StatelessMiddlewareRequest; -use Auth0\Laravel\Guards\GuardContract; +use Auth0\Laravel\Guards\{AuthenticationGuardContract, GuardContract}; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; @@ -19,6 +19,13 @@ */ abstract class AuthorizeOptionalMiddlewareAbstract extends MiddlewareAbstract { + /** + * @psalm-suppress UndefinedInterfaceMethod + * + * @param Request $request + * @param Closure $next + * @param string $scope + */ final public function handle( Request $request, Closure $next, @@ -30,8 +37,7 @@ final public function handle( return $next($request); } - /** @var Guard $guard */ - event(new StatelessMiddlewareRequest($request, $guard)); + Events::dispatch(new StatelessMiddlewareRequest($request, $guard)); $credential = $guard->find(GuardContract::SOURCE_TOKEN); diff --git a/src/ServiceAbstract.php b/src/ServiceAbstract.php index 1fd9fceb..4bc9e0ac 100644 --- a/src/ServiceAbstract.php +++ b/src/ServiceAbstract.php @@ -22,7 +22,7 @@ abstract class ServiceAbstract extends InstanceEntityAbstract * * @var string */ - public const VERSION = '7.10.1'; + public const VERSION = '7.11.0'; /** * Decode a PSR-7 HTTP Response Message containing a JSON content body to a PHP array. Returns null if the response was not successful, or the response body was not JSON. diff --git a/src/UserProviderAbstract.php b/src/UserProviderAbstract.php index f0f2b47b..b88cc11e 100644 --- a/src/UserProviderAbstract.php +++ b/src/UserProviderAbstract.php @@ -9,6 +9,7 @@ use Auth0\Laravel\{UserRepository, UserRepositoryContract}; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Container\BindingResolutionException; +use Illuminate\Support\Facades\Cache; use function is_string; @@ -19,6 +20,11 @@ */ abstract class UserProviderAbstract { + /** + * @var string + */ + protected const TELESCOPE = '\Laravel\Telescope\Telescope'; + protected ?UserRepositoryContract $repository = null; protected string $repositoryName = ''; @@ -40,7 +46,59 @@ final public function getRepository(): UserRepositoryContract */ final public function retrieveByCredentials(array $credentials): ?Authenticatable { - return $this->getRepository()->fromSession($credentials); + if ([] === $credentials) { + return null; + } + + $hash = hash('sha256', json_encode($credentials, JSON_THROW_ON_ERROR) ?: ''); /** @phpstan-ignore-line */ + $cached = $this->withoutRecording(static fn (): mixed => Cache::get('auth0_sdk_credential_lookup_' . $hash)); + + if ($cached instanceof Authenticatable) { + return $cached; + } + + static $lastResponse = null; + static $lastCredentials = null; + + /** + * @var ?Authenticatable $lastResponse + * @var array $lastCredentials + */ + if ($lastCredentials === $credentials) { + return $lastResponse; + } + + if (class_exists('\Laravel\Telescope\Telescope')) { + static $depth = 0; + static $lastCalled = null; + + /** + * @var int $depth + * @var ?int $lastCalled + */ + if (null === $lastCalled) { + $lastCalled = time(); + } + + if ($lastCredentials !== $credentials || time() - $lastCalled > 10) { + $lastResponse = null; + $depth = 0; + } + + if ($depth >= 1) { + return $lastResponse; + } + + ++$depth; + $lastCalled = time(); + $lastCredentials = $credentials; + } + + $lastResponse = $this->getRepository()->fromSession($credentials); + + $this->withoutRecording(static fn (): bool => Cache::put('auth0_sdk_credential_lookup_' . $hash, $lastResponse, 5)); + + return $lastResponse; } /** @@ -163,4 +221,13 @@ protected function setRepositoryName(string $repositoryName): void $this->setConfiguration('model', $repositoryName); $this->repositoryName = $repositoryName; } + + protected function withoutRecording(callable $callback): mixed + { + if (class_exists(self::TELESCOPE)) { + return self::TELESCOPE::withoutRecording($callback); + } + + return $callback(); + } } diff --git a/tests/Pest.php b/tests/Pest.php index e17ff371..c6e5e76f 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -5,6 +5,7 @@ use Auth0\SDK\Token\Generator; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Artisan; +use Illuminate\Support\Facades\Cache; /* |-------------------------------------------------------------------------- @@ -31,6 +32,46 @@ Event::listen('*', function ($event) { $this->events[] = $event; }); + + Cache::flush(); + + config()->set('auth', [ + 'defaults' => [ + 'guard' => 'legacyGuard', + 'passwords' => 'users', + ], + 'guards' => [ + 'web' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + 'legacyGuard' => [ + 'driver' => 'auth0.guard', + 'configuration' => 'web', + 'provider' => 'auth0-provider', + ], + 'auth0-session' => [ + 'driver' => 'auth0.authenticator', + 'configuration' => 'web', + 'provider' => 'auth0-provider', + ], + 'auth0-api' => [ + 'driver' => 'auth0.authorizer', + 'configuration' => 'api', + 'provider' => 'auth0-provider', + ], + ], + 'providers' => [ + 'users' => [ + 'driver' => 'eloquent', + 'model' => App\Models\User::class, + ], + 'auth0-provider' => [ + 'driver' => 'auth0.provider', + 'repository' => 'auth0.repository', + ], + ], + ]); })->in(__DIR__); // uses()->afterEach(function (): void { diff --git a/tests/TestCase.php b/tests/TestCase.php index b1ee391f..0ce025f0 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -26,44 +26,6 @@ protected function getPackageProviders($app) protected function getEnvironmentSetUp($app): void { - $app['config']->set('auth', [ - 'defaults' => [ - 'guard' => 'legacyGuard', - 'passwords' => 'users', - ], - 'guards' => [ - 'web' => [ - 'driver' => 'session', - 'provider' => 'users', - ], - 'legacyGuard' => [ - 'driver' => 'auth0.guard', - 'configuration' => 'web', - 'provider' => 'auth0-provider', - ], - 'auth0-session' => [ - 'driver' => 'auth0.authenticator', - 'configuration' => 'web', - 'provider' => 'auth0-provider', - ], - 'auth0-api' => [ - 'driver' => 'auth0.authorizer', - 'configuration' => 'api', - 'provider' => 'auth0-provider', - ], - ], - 'providers' => [ - 'users' => [ - 'driver' => 'eloquent', - 'model' => App\Models\User::class, - ], - 'auth0-provider' => [ - 'driver' => 'auth0.provider', - 'repository' => 'auth0.repository', - ], - ], - ]); - // Set a random key for testing $_ENV['APP_KEY'] = 'base64:' . base64_encode(random_bytes(32)); diff --git a/tests/Unit/Bridges/SessionBridgeTest.php b/tests/Unit/Bridges/SessionBridgeTest.php index 438918f5..2426d351 100644 --- a/tests/Unit/Bridges/SessionBridgeTest.php +++ b/tests/Unit/Bridges/SessionBridgeTest.php @@ -54,13 +54,13 @@ ->get('test')->toBeNull() ->set('test', 'value')->toBeNull() ->get('test')->toBe('value') - ->getAll()->toBe([$prefix . '_test' => 'value']) + ->getAll()->toBe(['test' => 'value']) ->set('test2', 'value2')->toBeNull() - ->getAll()->toBe([$prefix . '_test' => 'value', $prefix . '_test2' => 'value2']) + ->getAll()->toBe(['test' => 'value', 'test2' => 'value2']) ->delete('test')->toBeNull() - ->getAll()->toBe([$prefix . '_test2' => 'value2']) + ->getAll()->toBe(['test2' => 'value2']) ->set('test3', 'value3')->toBeNull() - ->getAll()->toBe([$prefix . '_test2' => 'value2', $prefix . '_test3' => 'value3']) + ->getAll()->toBe(['test2' => 'value2', 'test3' => 'value3']) ->purge()->toBeNull() ->getAll()->toBe([]); }); diff --git a/tests/Unit/Controllers/CallbackControllerTest.php b/tests/Unit/Controllers/CallbackControllerTest.php index 96c63a5a..99a2ca48 100644 --- a/tests/Unit/Controllers/CallbackControllerTest.php +++ b/tests/Unit/Controllers/CallbackControllerTest.php @@ -130,10 +130,12 @@ $client->addResponse('POST', 'https://' . config('auth0.guards.default.domain') . '/oauth/token', $response); $this->withSession([ - 'auth0_transient_state' => $state, - 'auth0_transient_pkce' => $pkce, - 'auth0_transient_nonce' => $nonce, - 'auth0_transient_code_verifier' => $verifier + 'auth0_transient' => json_encode([ + 'state' => $state, + 'pkce' => $pkce, + 'nonce' => $nonce, + 'code_verifier' => $verifier + ]) ])->getJson('/auth0/callback?code=code&state=' . $state) ->assertFound() ->assertLocation('/'); diff --git a/tests/Unit/Controllers/LoginControllerTest.php b/tests/Unit/Controllers/LoginControllerTest.php index 15035a0b..2a188c05 100644 --- a/tests/Unit/Controllers/LoginControllerTest.php +++ b/tests/Unit/Controllers/LoginControllerTest.php @@ -29,11 +29,13 @@ $this->sdk = $this->laravel->getSdk(); $this->validSession = [ - 'auth0_session_user' => ['sub' => 'hello|world'], - 'auth0_session_idToken' => (string) Generator::create((createRsaKeys())->private), - 'auth0_session_accessToken' => (string) Generator::create((createRsaKeys())->private), - 'auth0_session_accessTokenScope' => [uniqid()], - 'auth0_session_accessTokenExpiration' => time() + 60, + 'auth0_session' => json_encode([ + 'user' => ['sub' => 'hello|world'], + 'idToken' => (string) Generator::create((createRsaKeys())->private), + 'accessToken' => (string) Generator::create((createRsaKeys())->private), + 'accessTokenScope' => [uniqid()], + 'accessTokenExpiration' => time() + 60, + ]) ]; Route::get('/login', LoginController::class); diff --git a/tests/Unit/Controllers/LogoutControllerTest.php b/tests/Unit/Controllers/LogoutControllerTest.php index a9e1e296..5225f37a 100644 --- a/tests/Unit/Controllers/LogoutControllerTest.php +++ b/tests/Unit/Controllers/LogoutControllerTest.php @@ -28,11 +28,13 @@ $this->sdk = $this->laravel->getSdk(); $this->validSession = [ - 'auth0_session_user' => ['sub' => 'hello|world'], - 'auth0_session_idToken' => (string) Generator::create((createRsaKeys())->private), - 'auth0_session_accessToken' => (string) Generator::create((createRsaKeys())->private), - 'auth0_session_accessTokenScope' => [uniqid()], - 'auth0_session_accessTokenExpiration' => time() + 60, + 'auth0_session' => json_encode([ + 'user' => ['sub' => 'hello|world'], + 'idToken' => (string) Generator::create((createRsaKeys())->private), + 'accessToken' => (string) Generator::create((createRsaKeys())->private), + 'accessTokenScope' => [uniqid()], + 'accessTokenExpiration' => time() + 60, + ]) ]; Route::get('/logout', LogoutController::class); diff --git a/tests/Unit/Middleware/AuthenticateMiddlewareTest.php b/tests/Unit/Middleware/AuthenticateMiddlewareTest.php index 36b7a21e..7cfab85f 100644 --- a/tests/Unit/Middleware/AuthenticateMiddlewareTest.php +++ b/tests/Unit/Middleware/AuthenticateMiddlewareTest.php @@ -27,33 +27,16 @@ $this->sdk = $this->laravel->getSdk(); $this->validSession = [ - 'auth0_session_user' => ['sub' => 'hello|world'], - 'auth0_session_idToken' => (string) Generator::create((createRsaKeys())->private), - 'auth0_session_accessToken' => (string) Generator::create((createRsaKeys())->private), - 'auth0_session_accessTokenScope' => [uniqid(), 'read:admin'], - 'auth0_session_accessTokenExpiration' => time() + 60, + 'auth0_session' => json_encode([ + 'user' => ['sub' => 'hello|world'], + 'idToken' => (string) Generator::create((createRsaKeys())->private), + 'accessToken' => (string) Generator::create((createRsaKeys())->private), + 'accessTokenScope' => [uniqid(), 'read:admin'], + 'accessTokenExpiration' => time() + 60, + ]) ]; }); -it('does not assign a user when an incompatible guard is used', function (): void { - $route = '/' . uniqid(); - - Route::middleware('auth0.authenticate')->get($route, function () use ($route): string { - return $route; - }); - - config($config = [ - 'auth.defaults.guard' => 'web', - 'auth.guards.legacyGuard' => null - ]); - - $this->get($route) - ->assertStatus(Response::HTTP_INTERNAL_SERVER_ERROR); - - expect($this->guard) - ->user()->toBeNull(); -}); - it('redirects to login route if a visitor does not have a session', function (): void { $route = '/' . uniqid(); @@ -61,7 +44,8 @@ return $route; }); - $this->get($route) + $this->withoutExceptionHandling() + ->get($route) ->assertRedirect('/login'); expect(redirect()->getIntendedUrl()) @@ -117,3 +101,22 @@ expect($this->guard) ->user()->toBeNull(); }); + +it('does not assign a user when an incompatible guard is used', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate')->get($route, function () use ($route): string { + return $route; + }); + + config($config = [ + 'auth.defaults.guard' => 'web', + 'auth.guards.legacyGuard' => null + ]); + + $this->get($route) + ->assertStatus(Response::HTTP_INTERNAL_SERVER_ERROR); + + expect($this->guard) + ->user()->toBeNull(); +}); diff --git a/tests/Unit/Middleware/AuthenticateOptionalMiddlewareTest.php b/tests/Unit/Middleware/AuthenticateOptionalMiddlewareTest.php index 5f7bbbe6..ea0393b0 100644 --- a/tests/Unit/Middleware/AuthenticateOptionalMiddlewareTest.php +++ b/tests/Unit/Middleware/AuthenticateOptionalMiddlewareTest.php @@ -27,33 +27,16 @@ $this->sdk = $this->laravel->getSdk(); $this->validSession = [ - 'auth0_session_user' => ['sub' => 'hello|world'], - 'auth0_session_idToken' => (string) Generator::create((createRsaKeys())->private), - 'auth0_session_accessToken' => (string) Generator::create((createRsaKeys())->private), - 'auth0_session_accessTokenScope' => [uniqid(), 'read:admin'], - 'auth0_session_accessTokenExpiration' => time() + 60, + 'auth0_session' => json_encode([ + 'user' => ['sub' => 'hello|world'], + 'idToken' => (string) Generator::create((createRsaKeys())->private), + 'accessToken' => (string) Generator::create((createRsaKeys())->private), + 'accessTokenScope' => [uniqid(), 'read:admin'], + 'accessTokenExpiration' => time() + 60, + ]), ]; }); -it('does not assign a user when an incompatible guard is used', function (): void { - $route = '/' . uniqid(); - - Route::middleware('auth0.authenticate.optional')->get($route, function () use ($route): string { - return $route; - }); - - config($config = [ - 'auth.defaults.guard' => 'web', - 'auth.guards.legacyGuard' => null - ]); - - $this->get($route) - ->assertStatus(Response::HTTP_INTERNAL_SERVER_ERROR); - - expect($this->guard) - ->user()->toBeNull(); -}); - it('continues if a visitor does not have a session', function (): void { $route = '/' . uniqid(); @@ -116,3 +99,22 @@ expect($this->guard) ->user()->toBeNull(); }); + +it('does not assign a user when an incompatible guard is used', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authenticate.optional')->get($route, function () use ($route): string { + return $route; + }); + + config($config = [ + 'auth.defaults.guard' => 'web', + 'auth.guards.legacyGuard' => null + ]); + + $this->get($route) + ->assertStatus(Response::HTTP_INTERNAL_SERVER_ERROR); + + expect($this->guard) + ->user()->toBeNull(); +}); diff --git a/tests/Unit/Middleware/AuthorizeOptionalMiddlewareTest.php b/tests/Unit/Middleware/AuthorizeOptionalMiddlewareTest.php index fa1327f7..445901e3 100644 --- a/tests/Unit/Middleware/AuthorizeOptionalMiddlewareTest.php +++ b/tests/Unit/Middleware/AuthorizeOptionalMiddlewareTest.php @@ -30,26 +30,6 @@ $this->sdk = $this->laravel->getSdk(); }); -it('does not assign a user when an incompatible guard is used', function (): void { - $route = '/' . uniqid(); - - Route::middleware('auth0.authorize.optional')->get($route, function () use ($route): string { - return json_encode(['status' => $route]); - }); - - config([ - 'auth.defaults.guard' => 'web', - 'auth.guards.legacyGuard' => null - ]); - - $this->getJson($route, ['Authorization' => 'Bearer ' . uniqid()]) - ->assertStatus(Response::HTTP_OK) - ->assertJson(['status' => $route]); - - expect($this->guard) - ->user()->toBeNull(); -}); - it('does not assign a user when an invalid bearer token is provided', function (): void { $route = '/' . uniqid(); @@ -151,3 +131,23 @@ expect($this->guard) ->user()->toBeNull(); }); + +it('does not assign a user when an incompatible guard is used', function (): void { + $route = '/' . uniqid(); + + Route::middleware('auth0.authorize.optional')->get($route, function () use ($route): string { + return json_encode(['status' => $route]); + }); + + config([ + 'auth.defaults.guard' => 'web', + 'auth.guards.legacyGuard' => null + ]); + + $this->getJson($route, ['Authorization' => 'Bearer ' . uniqid()]) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]); + + expect($this->guard) + ->user()->toBeNull(); +}); diff --git a/tests/Unit/Traits/ActingAsAuth0UserTest.php b/tests/Unit/Traits/ActingAsAuth0UserTest.php index 78e0b27d..c7c516f9 100644 --- a/tests/Unit/Traits/ActingAsAuth0UserTest.php +++ b/tests/Unit/Traits/ActingAsAuth0UserTest.php @@ -70,10 +70,11 @@ }); $this->actingAsAuth0User(attributes: $this->user, source: Guard::SOURCE_SESSION) - ->getJson($route) - ->assertStatus(Response::HTTP_OK) - ->assertJson(['status' => $route]) - ->assertJsonFragment(['sub' => $this->user['sub']]); + ->withoutExceptionHandling() + ->getJson($route) + ->assertStatus(Response::HTTP_OK) + ->assertJson(['status' => $route]) + ->assertJsonFragment(['sub' => $this->user['sub']]); expect($this->guard) ->user()->toBeInstanceOf(UserContract::class); From 5d6f21888c862fd5aa6696efc277414b50a7a791 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Wed, 9 Aug 2023 00:28:49 -0500 Subject: [PATCH 476/525] Bump to 7.11.0 --- src/Events/TokenExpiredAbstract.php | 2 +- src/Events/TokenExpiredContract.php | 2 +- src/Events/TokenRefreshFailedAbstract.php | 2 +- src/Events/TokenRefreshFailedContract.php | 2 +- src/Events/TokenRefreshSucceededAbstract.php | 2 +- src/Events/TokenRefreshSucceededContract.php | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Events/TokenExpiredAbstract.php b/src/Events/TokenExpiredAbstract.php index 9d149e18..bfe5643a 100644 --- a/src/Events/TokenExpiredAbstract.php +++ b/src/Events/TokenExpiredAbstract.php @@ -11,7 +11,7 @@ */ abstract class TokenExpiredAbstract extends EventAbstract { - final public function jsonSerialize(): null + final public function jsonSerialize(): ?array { return null; } diff --git a/src/Events/TokenExpiredContract.php b/src/Events/TokenExpiredContract.php index 877eae00..59c7b920 100644 --- a/src/Events/TokenExpiredContract.php +++ b/src/Events/TokenExpiredContract.php @@ -9,5 +9,5 @@ */ interface TokenExpiredContract extends EventContract { - public function jsonSerialize(): null; + public function jsonSerialize(): ?array; } diff --git a/src/Events/TokenRefreshFailedAbstract.php b/src/Events/TokenRefreshFailedAbstract.php index e952412e..2cc0990f 100644 --- a/src/Events/TokenRefreshFailedAbstract.php +++ b/src/Events/TokenRefreshFailedAbstract.php @@ -11,7 +11,7 @@ */ abstract class TokenRefreshFailedAbstract extends EventAbstract { - final public function jsonSerialize(): null + final public function jsonSerialize(): ?array { return null; } diff --git a/src/Events/TokenRefreshFailedContract.php b/src/Events/TokenRefreshFailedContract.php index 56738578..4ae4ce42 100644 --- a/src/Events/TokenRefreshFailedContract.php +++ b/src/Events/TokenRefreshFailedContract.php @@ -9,5 +9,5 @@ */ interface TokenRefreshFailedContract extends EventContract { - public function jsonSerialize(): null; + public function jsonSerialize(): ?array; } diff --git a/src/Events/TokenRefreshSucceededAbstract.php b/src/Events/TokenRefreshSucceededAbstract.php index 40c6284b..acac7a01 100644 --- a/src/Events/TokenRefreshSucceededAbstract.php +++ b/src/Events/TokenRefreshSucceededAbstract.php @@ -11,7 +11,7 @@ */ abstract class TokenRefreshSucceededAbstract extends EventAbstract { - final public function jsonSerialize(): null + final public function jsonSerialize(): ?array { return null; } diff --git a/src/Events/TokenRefreshSucceededContract.php b/src/Events/TokenRefreshSucceededContract.php index b7a54be1..163351bc 100644 --- a/src/Events/TokenRefreshSucceededContract.php +++ b/src/Events/TokenRefreshSucceededContract.php @@ -9,5 +9,5 @@ */ interface TokenRefreshSucceededContract extends EventContract { - public function jsonSerialize(): null; + public function jsonSerialize(): ?array; } From ea2d1e2c69c63bf3043ba720958b508e01cc5191 Mon Sep 17 00:00:00 2001 From: Pavol T <134384094+pavol-revive@users.noreply.github.com> Date: Thu, 17 Aug 2023 05:14:58 +0200 Subject: [PATCH 477/525] Add missing square bracket in route registration example (#430) --- docs/Configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 8ecdb293..f8d7c799 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -223,7 +223,7 @@ If you've disabled the automatic registration of routes, you must register the r ```php use Auth0\Laravel\Controllers\{LoginController, LogoutController, CallbackController}; -Route::group(['middleware' => ['guard:auth0-session'], static function (): void { +Route::group(['middleware' => ['guard:auth0-session']], static function (): void { Route::get('/login', LoginController::class)->name('login'); Route::get('/logout', LogoutController::class)->name('logout'); Route::get('/callback', CallbackController::class)->name('callback'); From 5e40e7f134c8c2a9c443c44a70f5a9c12d5480c2 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 25 Aug 2023 02:38:28 -0500 Subject: [PATCH 478/525] Update workflows --- .github/actions/setup/action.yml | 48 +++++++ .github/dependabot.yml | 6 + .github/workflows/cron_semgrep.yml | 26 ---- .github/workflows/cron_snyk.yml | 32 ----- .github/workflows/matrix.json | 6 + .github/workflows/pr_await_changes.yml | 17 --- .github/workflows/pr_composer.yml | 32 ----- .github/workflows/pr_pest.yml | 31 ---- .github/workflows/pr_phpcsf.yml | 25 ---- .github/workflows/pr_phpstan.yml | 25 ---- .github/workflows/pr_psalm.yml | 25 ---- .github/workflows/pr_rector.yml | 25 ---- .github/workflows/pr_semgrep.yml | 27 ---- .github/workflows/pr_snyk.yml | 35 ----- .github/workflows/semgrep.yml | 44 ++++++ .github/workflows/snyk.yml | 45 ++++++ .github/workflows/tests.yml | 190 +++++++++++++++++++++++++ composer.json | 16 ++- 18 files changed, 348 insertions(+), 307 deletions(-) create mode 100644 .github/actions/setup/action.yml create mode 100644 .github/dependabot.yml delete mode 100644 .github/workflows/cron_semgrep.yml delete mode 100644 .github/workflows/cron_snyk.yml create mode 100644 .github/workflows/matrix.json delete mode 100644 .github/workflows/pr_await_changes.yml delete mode 100644 .github/workflows/pr_composer.yml delete mode 100644 .github/workflows/pr_pest.yml delete mode 100644 .github/workflows/pr_phpcsf.yml delete mode 100644 .github/workflows/pr_phpstan.yml delete mode 100644 .github/workflows/pr_psalm.yml delete mode 100644 .github/workflows/pr_rector.yml delete mode 100644 .github/workflows/pr_semgrep.yml delete mode 100644 .github/workflows/pr_snyk.yml create mode 100644 .github/workflows/semgrep.yml create mode 100644 .github/workflows/snyk.yml create mode 100644 .github/workflows/tests.yml diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml new file mode 100644 index 00000000..c01cfab4 --- /dev/null +++ b/.github/actions/setup/action.yml @@ -0,0 +1,48 @@ +name: Prepare PHP +description: Prepare the PHP environment + +inputs: + php: + description: The PHP version to use + required: true + coverage: + description: The coverage extension to use + required: false + default: 'none' + extensions: + description: The PHP extensions to use + required: false + default: 'none, mbstring, curl, simplexml, dom, xmlwriter, xml, tokenizer' + runner: + description: The runner OS + required: false + default: 'ubuntu-latest' + +runs: + using: composite + + steps: + - name: Setup PHP + uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # pin@2.25.4 + with: + php-version: ${{ inputs.php }} + extensions: ${{ inputs.extensions }} + coverage: ${{ inputs.coverage }} + env: + runner: ${{ inputs.runner }} + + - name: Get Composer cache directory + id: composer-cache + shell: bash + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ inputs.php }}-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer-${{ inputs.php }}- + + - name: Install dependencies + shell: bash + run: composer install --prefer-dist diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..12301490 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/cron_semgrep.yml b/.github/workflows/cron_semgrep.yml deleted file mode 100644 index e448560f..00000000 --- a/.github/workflows/cron_semgrep.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: "Semgrep (Scheduled)" - -# This workflow will run after a push to the main branch and as a scheduled job. - -on: - push: - branches: ["master", "main"] - schedule: - - cron: "30 0 1,15 * *" - -permissions: {} - -jobs: - semgrep: - name: "Scan" - runs-on: ubuntu-latest - - container: - image: returntocorp/semgrep - - steps: - - uses: actions/checkout@v3 - - - run: semgrep ci - env: - SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} diff --git a/.github/workflows/cron_snyk.yml b/.github/workflows/cron_snyk.yml deleted file mode 100644 index fdf3f658..00000000 --- a/.github/workflows/cron_snyk.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: "Snyk (Scheduled)" - -# This workflow will run after a push to the main branch and as a scheduled job. - -on: - push: - branches: ["master", "main"] - -permissions: {} - -jobs: - snyk: - name: "Scan" - runs-on: ubuntu-latest - - steps: - - uses: shivammathur/setup-php@v2 - with: - php-version: "8.1" - coverage: none - extensions: mbstring - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - uses: actions/checkout@v3 - - - run: composer install --no-progress - - - uses: snyk/actions/php@master - continue-on-error: true - env: - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} diff --git a/.github/workflows/matrix.json b/.github/workflows/matrix.json new file mode 100644 index 00000000..a38b5ef5 --- /dev/null +++ b/.github/workflows/matrix.json @@ -0,0 +1,6 @@ +{ + "include": [ + { "php": "8.1" }, + { "php": "8.2" } + ] +} diff --git a/.github/workflows/pr_await_changes.yml b/.github/workflows/pr_await_changes.yml deleted file mode 100644 index 4c650b23..00000000 --- a/.github/workflows/pr_await_changes.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: "Pull Request Changes" - -# Monitor for changes to pull requests. - -on: - pull_request: - types: [opened, synchronize, reopened, closed] - -permissions: {} - -jobs: - wait: - name: "Watching" - runs-on: ubuntu-latest - - steps: - - run: echo "Child workflows triggered." diff --git a/.github/workflows/pr_composer.yml b/.github/workflows/pr_composer.yml deleted file mode 100644 index d24abb7c..00000000 --- a/.github/workflows/pr_composer.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: "Composer" - -on: - pull_request: - merge_group: - push: - branches: ["master", "main"] - -permissions: {} - -jobs: - validate: - name: "Validate" - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - run: composer validate - - normalize: - name: "Normalize" - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - run: composer require --dev ergebnis/composer-normalize - - - run: composer config allow-plugins.ergebnis/composer-normalize true - - - run: composer normalize diff --git a/.github/workflows/pr_pest.yml b/.github/workflows/pr_pest.yml deleted file mode 100644 index f76d1ce8..00000000 --- a/.github/workflows/pr_pest.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: "PEST" - -on: - pull_request: - merge_group: - push: - branches: ["master", "main"] - -permissions: {} - -jobs: - pest: - name: "Scan" - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - uses: shivammathur/setup-php@v2 - with: - php-version: "8.1" - coverage: pcov - - - run: composer install --no-progress - - - run: vendor/bin/pest --order-by random --fail-on-risky --stop-on-defect --coverage --parallel --min=95 - - - uses: codecov/codecov-action@v3 - with: - directory: ./coverage/ - flags: unittests diff --git a/.github/workflows/pr_phpcsf.yml b/.github/workflows/pr_phpcsf.yml deleted file mode 100644 index 753cce81..00000000 --- a/.github/workflows/pr_phpcsf.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: "PHP CS Fixer" - -on: - pull_request: - merge_group: - push: - branches: ["master", "main"] - -permissions: {} - -jobs: - phpcsf: - name: "Scan" - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - uses: shivammathur/setup-php@v2 - with: - php-version: "8.1" - - - run: composer install --no-progress - - - run: vendor/bin/php-cs-fixer fix src --dry-run --diff diff --git a/.github/workflows/pr_phpstan.yml b/.github/workflows/pr_phpstan.yml deleted file mode 100644 index 75f17b89..00000000 --- a/.github/workflows/pr_phpstan.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: "PHPStan" - -on: - pull_request: - merge_group: - push: - branches: ["master", "main"] - -permissions: {} - -jobs: - phpstan: - name: "Scan" - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - uses: shivammathur/setup-php@v2 - with: - php-version: "8.1" - - - run: composer install --no-progress - - - run: vendor/bin/phpstan analyze --no-ansi --no-progress --debug diff --git a/.github/workflows/pr_psalm.yml b/.github/workflows/pr_psalm.yml deleted file mode 100644 index 46689b13..00000000 --- a/.github/workflows/pr_psalm.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: "Psalm" - -on: - pull_request: - merge_group: - push: - branches: ["master", "main"] - -permissions: {} - -jobs: - psalm: - name: "Scan" - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - uses: shivammathur/setup-php@v2 - with: - php-version: "8.1" - - - run: composer install --no-progress - - - run: vendor/bin/psalm diff --git a/.github/workflows/pr_rector.yml b/.github/workflows/pr_rector.yml deleted file mode 100644 index 594ca491..00000000 --- a/.github/workflows/pr_rector.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: "Rector" - -on: - pull_request: - merge_group: - push: - branches: ["master", "main"] - -permissions: {} - -jobs: - rector: - name: "Scan" - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - uses: shivammathur/setup-php@v2 - with: - php-version: "8.1" - - - run: composer install --no-progress - - - run: vendor/bin/rector process --dry-run diff --git a/.github/workflows/pr_semgrep.yml b/.github/workflows/pr_semgrep.yml deleted file mode 100644 index e8949f5b..00000000 --- a/.github/workflows/pr_semgrep.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: "Semgrep" - -on: - workflow_run: - workflows: ["Pull Request Changes"] - types: - - completed - -permissions: {} - -jobs: - wait: - name: "Scan" - runs-on: ubuntu-latest - - container: - image: returntocorp/semgrep - - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.sha }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - - run: semgrep ci - env: - SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} diff --git a/.github/workflows/pr_snyk.yml b/.github/workflows/pr_snyk.yml deleted file mode 100644 index 74852bdf..00000000 --- a/.github/workflows/pr_snyk.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: "Snyk" - -on: - workflow_run: - workflows: ["Pull Request Changes"] - types: - - completed - -permissions: {} - -jobs: - snyk: - name: "Scan" - runs-on: ubuntu-latest - - steps: - - uses: shivammathur/setup-php@v2 - with: - php-version: "8.1" - coverage: none - extensions: mbstring - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.sha }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - - run: composer install --no-progress - - - uses: snyk/actions/php@master - continue-on-error: true - env: - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml new file mode 100644 index 00000000..faab2b1e --- /dev/null +++ b/.github/workflows/semgrep.yml @@ -0,0 +1,44 @@ +name: Semgrep + +on: + merge_group: + workflow_dispatch: + pull_request_target: + types: + - opened + - synchronize + push: + branches: + - main + schedule: + - cron: "30 0 1,15 * *" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + authorize: + name: Authorize + environment: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository && 'external' || 'internal' }} + runs-on: ubuntu-latest + steps: + - run: true + + check: + needs: authorize + name: Check for Vulnerabilities + runs-on: ubuntu-latest + + container: + image: returntocorp/semgrep + + steps: + - uses: actions/checkout@v3 + + - run: semgrep ci + env: + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} diff --git a/.github/workflows/snyk.yml b/.github/workflows/snyk.yml new file mode 100644 index 00000000..0d234bf2 --- /dev/null +++ b/.github/workflows/snyk.yml @@ -0,0 +1,45 @@ +name: Snyk + +on: + merge_group: + workflow_dispatch: + pull_request_target: + types: + - opened + - synchronize + push: + branches: + - main + schedule: + - cron: "30 0 1,15 * *" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + authorize: + name: Authorize + environment: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository && 'external' || 'internal' }} + runs-on: ubuntu-latest + steps: + - run: true + + check: + needs: authorize + name: Check for Vulnerabilities + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/actions/setup + with: + php: 8.1 + + - uses: snyk/actions/php@b98d498629f1c368650224d6d212bf7dfa89e4bf # pin@0.4.0 + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..556493eb --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,190 @@ +name: Build and Test + +on: + merge_group: + workflow_dispatch: + pull_request_target: + types: + - opened + - synchronize + push: + branches: + - main + +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + authorize: + name: Authorize + environment: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository && 'external' || 'internal' }} + runs-on: ubuntu-latest + steps: + - run: true + + configure: + name: Configure + needs: [authorize] + runs-on: ubuntu-latest + + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + + steps: + - uses: actions/checkout@v3 + + - id: set-matrix + run: echo "matrix=$(jq -c . < ./.github/workflows/matrix.json)" >> $GITHUB_OUTPUT + + prepare: + name: Prepare Dependencies + needs: [configure] + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.configure.outputs.matrix) }} + + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/actions/setup + with: + php: ${{ matrix.php }} + + composer-normalize: + name: Composer Normalize + needs: [configure, prepare] + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.configure.outputs.matrix) }} + + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/actions/setup + with: + php: ${{ matrix.php }} + + - run: composer normalize --dry-run --diff + + composer-validate: + name: Composer Validate + needs: [configure, prepare] + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.configure.outputs.matrix) }} + + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/actions/setup + with: + php: ${{ matrix.php }} + + - run: composer validate --strict --with-dependencies + + pest: + name: PEST + needs: [configure, prepare] + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.configure.outputs.matrix) }} + + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/actions/setup + with: + php: ${{ matrix.php }} + coverage: pcov + + - if: matrix.php == '8.1' + run: composer pest:coverage + + - if: matrix.php == '8.1' + uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # pin@3.1.4 + with: + directory: ./coverage/ + flags: unittestsvalidate + + phpstan: + name: PHPStan + needs: [configure, prepare] + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.configure.outputs.matrix) }} + + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/actions/setup + with: + php: ${{ matrix.php }} + + - run: composer phpstan + + psalm: + name: Psalm + needs: [configure, prepare] + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.configure.outputs.matrix) }} + + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/actions/setup + with: + php: ${{ matrix.php }} + + - run: composer psalm + + rector: + name: Rector + needs: [configure, prepare] + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.configure.outputs.matrix) }} + + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/actions/setup + with: + php: ${{ matrix.php }} + + - run: composer rector + + php-cs-fixer: + name: PHP CS Fixer + needs: [configure, prepare] + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.configure.outputs.matrix) }} + + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/actions/setup + with: + php: ${{ matrix.php }} + + - run: composer phpcs diff --git a/composer.json b/composer.json index ea0e84be..3c552a8c 100644 --- a/composer.json +++ b/composer.json @@ -45,6 +45,7 @@ "psr/cache": "^2 || ^3" }, "require-dev": { + "ergebnis/composer-normalize": "^2", "friendsofphp/php-cs-fixer": "^3", "mockery/mockery": "^1", "nunomaduro/larastan": "^2", @@ -81,7 +82,8 @@ "allow-plugins": { "pestphp/pest-plugin": true, "wikimedia/composer-merge-plugin": true, - "php-http/discovery": false + "php-http/discovery": false, + "ergebnis/composer-normalize": true }, "optimize-autoloader": true, "preferred-install": "dist", @@ -111,17 +113,17 @@ } }, "scripts": { - "pest:coverage": "@php vendor/bin/pest --coverage --parallel --no-progress", - "pest:debug": "@php vendor/bin/pest --fail-on-risky --stop-on-defect", + "pest": "@php vendor/bin/pest --order-by random --fail-on-risky --parallel --no-progress", + "pest:coverage": "@php vendor/bin/pest --order-by random --fail-on-risky --coverage --parallel --no-progress", + "pest:debug": "@php vendor/bin/pest --log-events-verbose-text pest.log --display-errors --fail-on-risky --no-progress", "pest:profile": "@php vendor/bin/pest --profile", - "pest": "@php vendor/bin/pest --order-by random --fail-on-risky --stop-on-defect --parallel", - "phpcs:fix": "@php vendor/bin/php-cs-fixer fix", "phpcs": "@php vendor/bin/php-cs-fixer fix --dry-run --diff", + "phpcs:fix": "@php vendor/bin/php-cs-fixer fix", "phpstan": "@php vendor/bin/phpstan analyze", - "psalm:fix": "@php vendor/bin/psalter --issues=all", "psalm": "@php vendor/bin/psalm", - "rector:fix": "@php vendor/bin/rector process src", + "psalm:fix": "@php vendor/bin/psalter --issues=all", "rector": "@php vendor/bin/rector process src --dry-run", + "rector:fix": "@php vendor/bin/rector process src", "test": [ "@pest", "@phpstan", From 7e54468fb558f206a0c6c44f37a04b4fc7871489 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 25 Aug 2023 02:40:42 -0500 Subject: [PATCH 479/525] Update action.yml --- .github/actions/setup/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index c01cfab4..486b51d2 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -12,7 +12,7 @@ inputs: extensions: description: The PHP extensions to use required: false - default: 'none, mbstring, curl, simplexml, dom, xmlwriter, xml, tokenizer' + default: 'none, mbstring, curl, simplexml, dom, xmlwriter, xml, tokenizer, fileinfo' runner: description: The runner OS required: false From 76bbc77b5a9e988d8b46d7b48630d58d11f7c819 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 25 Aug 2023 02:44:54 -0500 Subject: [PATCH 480/525] Update action.yml --- .github/actions/setup/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 486b51d2..31ad37c5 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -12,7 +12,7 @@ inputs: extensions: description: The PHP extensions to use required: false - default: 'none, mbstring, curl, simplexml, dom, xmlwriter, xml, tokenizer, fileinfo' + default: 'none, mbstring, curl, simplexml, dom, xmlwriter, xml, tokenizer, fileinfo, pdo' runner: description: The runner OS required: false From b47fb6048e16eba11269f0f9136121c2a9beeed7 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 25 Aug 2023 02:48:05 -0500 Subject: [PATCH 481/525] Update tests.yml --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 556493eb..36563512 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -89,7 +89,7 @@ jobs: with: php: ${{ matrix.php }} - - run: composer validate --strict --with-dependencies + - run: composer validate --strict pest: name: PEST From 0558c67eb715308e3857efb134214189914d1b83 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 25 Aug 2023 02:48:40 -0500 Subject: [PATCH 482/525] Resolve linter warning --- src/Guards/AuthenticationGuard.php | 4 +++- src/Guards/GuardAbstract.php | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Guards/AuthenticationGuard.php b/src/Guards/AuthenticationGuard.php index 1f992962..292c8475 100644 --- a/src/Guards/AuthenticationGuard.php +++ b/src/Guards/AuthenticationGuard.php @@ -14,6 +14,8 @@ use Illuminate\Auth\Events\{Login, Logout}; use Illuminate\Contracts\Auth\Authenticatable; +use Throwable; + use function count; use function is_array; use function is_object; @@ -367,7 +369,7 @@ private function refreshSession( try { $this->sdk()->renew(); $session = $this->pullState(); - } catch (\Throwable) { + } catch (Throwable) { Events::dispatch(new TokenRefreshFailed()); $session = null; } diff --git a/src/Guards/GuardAbstract.php b/src/Guards/GuardAbstract.php index 2eb9b90a..ac3a41d4 100644 --- a/src/Guards/GuardAbstract.php +++ b/src/Guards/GuardAbstract.php @@ -338,7 +338,7 @@ protected function normalizeUserArray( */ try { $response = json_encode($user->toArray(), JSON_THROW_ON_ERROR); - } catch (\Exception) { + } catch (Exception) { } } @@ -360,7 +360,7 @@ protected function normalizeUserArray( */ return $response; } - } catch (\Exception) { + } catch (Exception) { } } From 28a5cef5774f58d67e46f5798a42739a3448693b Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 25 Aug 2023 03:12:14 -0500 Subject: [PATCH 483/525] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2dd1a499..efcd578e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

Substitute %IDENTIFIER% with the identifier of the API you created in step 3 above.

+

Substitute %IDENTIFIER% with the identifier of the API you created in step 3 above.

- Now you can send requests to the `/api` endpoints of the application, including the token as a header. + Now you can send requests to the `/api` endpoints of the application, including the token as a header. ```shell curl --request GET \ @@ -193,18 +192,18 @@ Direct your browser to [http://localhost:8000](http://localhost:8000) to experim --header 'Authorization: Bearer %TOKEN%' ``` -

Substitute %TOKEN% with the test token returned in the previous step.

+

Substitute %TOKEN% with the test token returned in the previous step.

-
- Using Windows PowerShell -   +
+ Using Windows PowerShell +   ```powershell Invoke-WebRequest http://localhost:8000/api/example ` -Headers @{'Accept' = 'application/json'; 'Authorization' = 'Bearer %TOKEN%'} ``` -
+
When you're ready to deploy your application to production, review [our deployment guide](./docs/Deployment.md) for best practices and advice on securing Laravel. @@ -354,33 +353,33 @@ All the SDK's Management API methods are [documented here](./docs/Management.md) ## Documentation -- [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. -- [Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. -- [Sessions](./docs/Sessions.md) — Guidance on deciding which Laravel Session API driver to use. -- [Cookies](./docs/Cookies.md) — Important notes about using Laravel's Cookie session driver, and alternative options. -- [Management API](./docs/Management.md) — Using the SDK to work with the [Auth0 Management API](https://auth0.com/docs/api/management/v2). -- [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent) models. -- [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. -- [Deployment](./docs/Deployment.md) — Deploying your application to production. +- [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files. +- [Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables. +- [Sessions](./docs/Sessions.md) — Guidance on deciding which Laravel Session API driver to use. +- [Cookies](./docs/Cookies.md) — Important notes about using Laravel's Cookie session driver, and alternative options. +- [Management API](./docs/Management.md) — Using the SDK to work with the [Auth0 Management API](https://auth0.com/docs/api/management/v2). +- [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent) models. +- [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions. +- [Deployment](./docs/Deployment.md) — Deploying your application to production. You may find the following integration guidance useful: -- [Laravel Eloquent](./docs/Eloquent.md) — [Eloquent ORM](https://laravel.com/docs/eloquent) is supported. -- [Laravel Octane](./docs/Octane.md) — [Octane](https://laravel.com/docs/octane) is not supported at this time. -- [Laravel Telescope](./docs/Telescope.md) — [Telescope](https://laravel.com/docs/telescope) is compatible as of SDK v7.11.0. +- [Laravel Eloquent](./docs/Eloquent.md) — [Eloquent ORM](https://laravel.com/docs/eloquent) is supported. +- [Laravel Octane](./docs/Octane.md) — [Octane](https://laravel.com/docs/octane) is not supported at this time. +- [Laravel Telescope](./docs/Telescope.md) — [Telescope](https://laravel.com/docs/telescope) is compatible as of SDK v7.11.0. You may also find the following resources helpful: -- [Auth0 Documentation Hub](https://www.auth0.com/docs) -- [Auth0 Management API Explorer](https://auth0.com/docs/api/management/v2) -- [Auth0 Authentication API Explorer](https://auth0.com/docs/api/authentication) +- [Auth0 Documentation Hub](https://www.auth0.com/docs) +- [Auth0 Management API Explorer](https://auth0.com/docs/api/management/v2) +- [Auth0 Authentication API Explorer](https://auth0.com/docs/api/authentication) Contributions to improve our documentation [are welcomed](https://github.com/auth0/laravel-auth0/pull). ## QuickStarts -- [Session-based Authentication](https://auth0.com/docs/quickstart/webapp/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) -- [Token-based Authorization](https://auth0.com/docs/quickstart/backend/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) +- [Session-based Authentication](https://auth0.com/docs/quickstart/webapp/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) +- [Token-based Authorization](https://auth0.com/docs/quickstart/backend/laravel) ([GitHub](https://github.com/auth0-samples/laravel)) ## Community diff --git a/composer.json b/composer.json index 98a4f4d1..cba51bd6 100644 --- a/composer.json +++ b/composer.json @@ -34,31 +34,37 @@ "forum": "https://community.auth0.com/", "source": "https://github.com/auth0/laravel-auth0" }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/asbiin/psalm-plugin-laravel.git" + } + ], "require": { - "php": "^8.1", + "php": "^8.2", "ext-json": "*", "auth0/auth0-php": "^8.10", - "illuminate/contracts": "^9 || ^10", - "illuminate/http": "^9 || ^10", - "illuminate/support": "^9 || ^10", + "illuminate/contracts": "^11", + "illuminate/http": "^11", + "illuminate/support": "^11", "psr-discovery/all": "^1", "psr/cache": "^2 || ^3" }, "require-dev": { "ergebnis/composer-normalize": "^2", "friendsofphp/php-cs-fixer": "^3", + "larastan/larastan": "^2", "mockery/mockery": "^1", - "nunomaduro/larastan": "^2", - "orchestra/testbench": "^7 || ^8", - "pestphp/pest": "^2", + "orchestra/testbench": "^9.x-dev", "pestphp/pest-plugin-laravel": "^2", - "phpstan/phpstan": "^1", + "pestphp/pest": "^2", "phpstan/phpstan-strict-rules": "^1", - "psalm/plugin-laravel": "^2", + "phpstan/phpstan": "^1", + "psalm/plugin-laravel": "dev-laravel11#b93c8f21c18e3355dcdae797c6af266f7aab93f6", "psr-mock/http": "^1", - "rector/rector": "0.17.0", + "rector/rector": "^1", "squizlabs/php_codesniffer": "^3", - "symfony/cache": "^6", + "symfony/cache": "^6 || ^7", "vimeo/psalm": "^5", "wikimedia/composer-merge-plugin": "^2" }, diff --git a/deprecated/Model/User.php b/deprecated/Model/User.php index fc56cdfc..6851a8bb 100644 --- a/deprecated/Model/User.php +++ b/deprecated/Model/User.php @@ -4,7 +4,7 @@ namespace Auth0\Laravel\Model; -use Auth0\Laravel\Users\{UserAbstract, UserContract}; +use Auth0\Laravel\Users\UserAbstract; /** * @deprecated 7.8.0 Use Auth0\Laravel\Users\UserAbstract instead. diff --git a/docs/Deployment.md b/docs/Deployment.md index 9dd6160a..66ebdaee 100644 --- a/docs/Deployment.md +++ b/docs/Deployment.md @@ -2,28 +2,28 @@ When you're preparing to deploy your application to production, there are some basic steps you can take to make sure your application is running as smoothly and securely as possible. In this guide, we'll cover some starting points for making sure your application is deployed properly. -- [Auth0 Configuration](#auth0-configuration) -- [TLS / HTTPS](#tls--https) -- [Cookies](#cookies) -- [Server Configuration](#server-configuration) - - [Caddy](#caddy) - - [Nginx](#nginx) - - [Apache](#apache) -- [Optimization](#optimization) - - [Autoloader](#autoloader) - - [Dependencies](#dependencies) - - [Caching Configuration](#caching-configuration) - - [Caching Events](#caching-events) - - [Caching Routes](#caching-routes) - - [Caching Views](#caching-views) - - [Debug Mode](#debug-mode) +- [Auth0 Configuration](#auth0-configuration) +- [TLS / HTTPS](#tls--https) +- [Cookies](#cookies) +- [Server Configuration](#server-configuration) + - [Caddy](#caddy) + - [Nginx](#nginx) + - [Apache](#apache) +- [Optimization](#optimization) + - [Autoloader](#autoloader) + - [Dependencies](#dependencies) + - [Caching Configuration](#caching-configuration) + - [Caching Events](#caching-events) + - [Caching Routes](#caching-routes) + - [Caching Views](#caching-views) + - [Debug Mode](#debug-mode) ## Auth0 Configuration When migrating your Laravel application from local development to production, you will need to update your Auth0 application's configuration to reflect the new URLs for your application. You can do this by logging into the [Auth0 Dashboard](https://manage.auth0.com/) and updating the following fields: -- **Allowed Callback URLs**: The URL that Auth0 will redirect to after the user authenticates. This should be set to the Internet-accessible URL of your application's `/callback` route. -- **Allowed Logout URLs**: The URL that Auth0 will redirect to after the user logs out. This should be set to an appropriate Internet-accessible URL of your application. +- **Allowed Callback URLs**: The URL that Auth0 will redirect to after the user authenticates. This should be set to the Internet-accessible URL of your application's `/callback` route. +- **Allowed Logout URLs**: The URL that Auth0 will redirect to after the user logs out. This should be set to an appropriate Internet-accessible URL of your application. Note that you can include multiple URLs in these fields by separating them with commas, for example `https://example.com/callback,http://localhost:8000/callback`. @@ -64,7 +64,7 @@ example.com { X-Frame-Options "SAMEORIGIN" } - php_fastcgi unix//var/run/php/php8.1-fpm.sock + php_fastcgi unix//var/run/php/php8.2-fpm.sock } ``` @@ -76,32 +76,32 @@ server { listen [::]:80; server_name example.com; root /var/www/example.com/public; - + add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options "nosniff"; add_header X-Frame-Options "SAMEORIGIN"; large_client_header_buffers 4 32k; - + index index.php; - + charset utf-8; - + location / { try_files $uri $uri/ /index.php?$query_string; } - + location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } - + error_page 404 /index.php; - + location ~ \.php$ { - fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; + fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } - + location ~ /\.(?!well-known).* { deny all; } diff --git a/docs/Installation.md b/docs/Installation.md index 4cabac86..7b537ed9 100644 --- a/docs/Installation.md +++ b/docs/Installation.md @@ -1,28 +1,27 @@ # Installation -- [Prerequisites](#prerequisites) -- [Install the SDK](#install-the-sdk) - - [Using Quickstart (Recommended)](#using-quickstart-recommended) - - [Installation with Composer](#installation-with-composer) - - [Create a Laravel Application](#create-a-laravel-application) - - [Install the SDK](#install-the-sdk-1) -- [Install the CLI](#install-the-cli) - - [Authenticate the CLI](#authenticate-the-cli) -- [Configure the SDK](#configure-the-sdk) - - [Using JSON (Recommended)](#using-json-recommended) - - [Using Environment Variables](#using-environment-variables) +- [Prerequisites](#prerequisites) +- [Install the SDK](#install-the-sdk) + - [Using Quickstart (Recommended)](#using-quickstart-recommended) + - [Installation with Composer](#installation-with-composer) + - [Create a Laravel Application](#create-a-laravel-application) + - [Install the SDK](#install-the-sdk-1) +- [Install the CLI](#install-the-cli) + - [Authenticate the CLI](#authenticate-the-cli) +- [Configure the SDK](#configure-the-sdk) + - [Using JSON (Recommended)](#using-json-recommended) + - [Using Environment Variables](#using-environment-variables) ## Prerequisites -To integrate our SDK, your application must use a [supported Laravel version](https://laravelversions.com/en), and your environment must run a [supported PHP version](https://www.php.net/supported-versions.php). We do not support versions of either that are no longer supported by their maintainers. Please review [our support policy](./Support.md) for more information. +Your application must use the [latest supported Laravel version](https://endoflife.date/laravel), and your host environment must be running a [supported PHP version](https://www.php.net/supported-versions.php). Please review [our support policy](./docs/Support.md) for more information. -| SDK | Laravel | PHP | Supported Until | -| ---- | ------- | --- | --------------- | -| 7.5+ | 10 | 8.3 | Feb 2025 | -| | | 8.2 | Feb 2025 | -| | | 8.1 | Nov 2024 | -| 7.0+ | 9 | 8.2 | Feb 2024 | -| | | 8.1 | Feb 2024 | +| SDK | Laravel | PHP | Supported Until | +| ----- | ---------------------------------------------- | ---------------------------------------------- | --------------- | +| 7.13+ | [11.x](https://laravel.com/docs/11.x/releases) | [8.3](https://www.php.net/releases/8.3/en.php) | ~Sep 2025 | +| | | [8.2](https://www.php.net/releases/8.2/en.php) | ~Sep 2025 | + +Due to breaking changes in Laravel 11, SDK 7.12 was the last version to support Laravel 9 and 10. You will also need [Composer 2.0+](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). @@ -32,7 +31,7 @@ Ensure that your development environment has [supported versions](#prerequisites ### Using Quickstart (Recommended) -- Create a new Laravel 9 project pre-configured with the SDK: +- Create a new Laravel 9 project pre-configured with the SDK: ```shell composer create-project auth0-samples/laravel auth0-laravel-app @@ -42,7 +41,7 @@ Ensure that your development environment has [supported versions](#prerequisites #### Create a Laravel Application -- If you do not already have one, you can Create a new Laravel 9 application with the following command: +- If you do not already have one, you can Create a new Laravel 9 application with the following command: ```shell composer create-project laravel/laravel:^9.0 auth0-laravel-app @@ -66,20 +65,20 @@ Ensure that your development environment has [supported versions](#prerequisites Install the [Auth0 CLI](https://github.com/auth0/auth0-cli) to create and manage Auth0 resources from the command line. -- macOS with [Homebrew](https://brew.sh/): +- macOS with [Homebrew](https://brew.sh/): ```shell brew tap auth0/auth0-cli && brew install auth0 ``` -- Linux or macOS: +- Linux or macOS: ```shell curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b . sudo mv ./auth0 /usr/local/bin ``` -- Windows with [Scoop](https://scoop.sh/): +- Windows with [Scoop](https://scoop.sh/): ```cmd scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git @@ -88,7 +87,7 @@ Install the [Auth0 CLI](https://github.com/auth0/auth0-cli) to create and manage ### Authenticate the CLI -- Authenticate the CLI with your Auth0 account. Choose "as a user," and follow the prompts. +- Authenticate the CLI with your Auth0 account. Choose "as a user," and follow the prompts. ```shell auth0 login diff --git a/docs/Support.md b/docs/Support.md index 92a3607d..97352be1 100644 --- a/docs/Support.md +++ b/docs/Support.md @@ -1,14 +1,13 @@ # Support -To integrate our SDK, your application must use a [supported Laravel version](https://laravelversions.com/en), and your environment must run a [supported PHP version](https://www.php.net/supported-versions.php). We do not support versions of either that are no longer supported by their maintainers. +To integrate our SDK, your application must use the [latest supported Laravel version](https://endoflife.date/laravel), and your environment must run a [supported PHP version](https://www.php.net/supported-versions.php). We do not support versions of either that are no longer supported by their maintainers. -| SDK | Laravel | PHP | Supported Until | -| ---- | ------- | ---- | --------------- | -| 7.5+ | 10 | 8.2+ | Feb 2025 | -| | | 8.1+ | Nov 2024 | -| 7.0+ | 9 | 8.2+ | Feb 2024 | -| | | 8.1+ | Feb 2024 | -| | | 8.0+ | Nov 2023 | +| SDK | Laravel | PHP | Supported Until | +| ----- | ---------------------------------------------- | ---------------------------------------------- | --------------- | +| 7.13+ | [11.x](https://laravel.com/docs/11.x/releases) | [8.3](https://www.php.net/releases/8.3/en.php) | ~Sep 2025 | +| | | [8.2](https://www.php.net/releases/8.2/en.php) | ~Sep 2025 | + +Due to breaking changes in Laravel 11, SDK 7.12 was the last version to support Laravel 9 and 10. You will also need [Composer 2.0+](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). @@ -18,7 +17,7 @@ The SDK follows the [Laravel support policy](https://laravel.com/docs/master/rel ## Getting Support -- If you believe you've found a bug, please [create an issue on GitHub](https://github.com/auth0/laravel-auth0). -- For questions and community support, please [join the Auth0 Community](https://community.auth0.com/). -- For paid support plans, please [contact us directly](https://auth0.com/contact-us). -- For more information about Auth0 Support, please visit our [Support Center](https://support.auth0.com/). +- If you believe you've found a bug, please [create an issue on GitHub](https://github.com/auth0/laravel-auth0). +- For questions and community support, please [join the Auth0 Community](https://community.auth0.com/). +- For paid support plans, please [contact us directly](https://auth0.com/contact-us). +- For more information about Auth0 Support, please visit our [Support Center](https://support.auth0.com/). diff --git a/phpstan.neon.dist b/phpstan.neon.dist index e12af232..4b604cc9 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,6 +1,6 @@ includes: - ./vendor/phpstan/phpstan-strict-rules/rules.neon - - ./vendor/nunomaduro/larastan/extension.neon + - ./vendor/larastan/larastan/extension.neon parameters: level: max diff --git a/rector.php b/rector.php index 7c84d382..0ce41546 100644 --- a/rector.php +++ b/rector.php @@ -96,7 +96,6 @@ use Rector\CodingStyle\Rector\Plus\UseIncrementAssignRector; use Rector\CodingStyle\Rector\PostInc\PostIncDecToPreIncDecRector; use Rector\CodingStyle\Rector\Property\{AddFalseDefaultToBoolPropertyRector, SplitGroupedPropertiesRector}; -use Rector\CodingStyle\Rector\Stmt\NewlineAfterStatementRector; use Rector\CodingStyle\Rector\String_\{SymplifyQuoteEscapeRector, UseClassKeywordForClassNameResolutionRector}; use Rector\CodingStyle\Rector\Switch_\BinarySwitchToIfElseRector; use Rector\CodingStyle\Rector\Ternary\TernaryConditionVariableAssignmentRector; @@ -107,18 +106,14 @@ RemoveUnusedVariableAssignRector}; use Rector\DeadCode\Rector\BinaryOp\RemoveDuplicatedInstanceOfRector; use Rector\DeadCode\Rector\BooleanAnd\RemoveAndTrueRector; -use Rector\DeadCode\Rector\Cast\RecastingRemovalRector; use Rector\DeadCode\Rector\ClassConst\RemoveUnusedPrivateClassConstantRector; use Rector\DeadCode\Rector\ClassMethod\{RemoveDelegatingParentCallRector, RemoveEmptyClassMethodRector, RemoveLastReturnRector, RemoveUnusedConstructorParamRector, RemoveUnusedPrivateMethodParameterRector, - RemoveUnusedPrivateMethodRector, RemoveUnusedPromotedPropertyRector, - RemoveUselessParamTagRector, RemoveUselessReturnTagRector}; -use Rector\DeadCode\Rector\Concat\RemoveConcatAutocastRector; use Rector\DeadCode\Rector\Expression\{RemoveDeadStmtRector, SimplifyMirrorAssignRector}; use Rector\DeadCode\Rector\For_\{RemoveDeadContinueRector, @@ -127,8 +122,7 @@ use Rector\DeadCode\Rector\Foreach_\RemoveUnusedForeachKeyRector; use Rector\DeadCode\Rector\FunctionLike\{RemoveDeadReturnRector, RemoveDuplicatedIfReturnRector}; -use Rector\DeadCode\Rector\If_\{RemoveAlwaysTrueIfConditionRector, - RemoveDeadInstanceOfRector, +use Rector\DeadCode\Rector\If_\{ RemoveUnusedNonEmptyArrayBeforeForeachRector, SimplifyIfElseWithSameContentRector, UnwrapFutureCompatibleIfPhpVersionRector}; @@ -148,24 +142,19 @@ use Rector\DeadCode\Rector\TryCatch\RemoveDeadTryCatchRector; use Rector\DependencyInjection\Rector\Class_\ActionInjectionToConstructorInjectionRector; use Rector\EarlyReturn\Rector\Foreach_\ChangeNestedForeachIfsToEarlyContinueRector; -use Rector\EarlyReturn\Rector\If_\{ChangeAndIfToEarlyReturnRector, +use Rector\EarlyReturn\Rector\If_\{ ChangeIfElseValueAssignToEarlyReturnRector, ChangeNestedIfsToEarlyReturnRector, ChangeOrIfContinueToMultiContinueRector, - ChangeOrIfReturnToEarlyReturnRector, RemoveAlwaysElseRector}; -use Rector\EarlyReturn\Rector\Return_\{PreparedValueToEarlyReturnRector, +use Rector\EarlyReturn\Rector\Return_\{ ReturnBinaryAndToEarlyReturnRector, ReturnBinaryOrToEarlyReturnRector}; use Rector\EarlyReturn\Rector\StmtsAwareInterface\ReturnEarlyIfVariableRector; -use Rector\Naming\Rector\Assign\RenameVariableToMatchMethodCallReturnTypeRector; -use Rector\Naming\Rector\Class_\RenamePropertyToMatchTypeRector; -use Rector\Naming\Rector\ClassMethod\{RenameParamToMatchTypeRector, - RenameVariableToMatchNewTypeRector}; + use Rector\Naming\Rector\Foreach_\{RenameForeachValueVariableToMatchExprVariableRector, RenameForeachValueVariableToMatchMethodCallReturnTypeRector}; use Rector\Php52\Rector\Property\VarToPublicPropertyRector; -use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; use Rector\Php71\Rector\FuncCall\RemoveExtraParametersRector; use Rector\Php80\Rector\Catch_\RemoveUnusedVariableInCatchRector; use Rector\Php80\Rector\Class_\{ClassPropertyAssignToConstructorPromotionRector, @@ -177,8 +166,7 @@ use Rector\Php80\Rector\FuncCall\{ClassOnObjectRector, Php8ResourceReturnToObjectRector, TokenGetAllToObjectRector}; -use Rector\Php80\Rector\FunctionLike\{MixedTypeRector, - UnionTypesRector}; + use Rector\Php80\Rector\Identical\{StrEndsWithRector, StrStartsWithRector}; use Rector\Php80\Rector\NotIdentical\StrContainsRector; @@ -189,7 +177,6 @@ ChangeReadOnlyVariableWithDefaultValueToConstantRector, FinalizeClassesWithoutChildrenRector}; use Rector\Privatization\Rector\ClassMethod\PrivatizeFinalClassMethodRector; -use Rector\Privatization\Rector\MethodCall\PrivatizeLocalGetterToPropertyRector; use Rector\Privatization\Rector\Property\{ChangeReadOnlyPropertyWithDefaultValueToConstantRector, PrivatizeFinalClassPropertyRector}; use Rector\PSR4\Rector\FileWithoutNamespace\NormalizeNamespaceByPSR4ComposerAutoloadRector; @@ -203,7 +190,6 @@ ReturnTypeFromStrictTernaryRector}; use Rector\TypeDeclaration\Rector\ClassMethod\{AddMethodCallBasedStrictParamTypeRector, AddParamTypeBasedOnPHPUnitDataProviderRector, - AddParamTypeFromPropertyTypeRector, AddReturnTypeDeclarationBasedOnParentClassMethodRector, AddVoidReturnTypeWhereNoReturnRector, ArrayShapeFromConstantArrayReturnRector, @@ -240,27 +226,27 @@ $rectorConfig->ruleWithConfiguration( RenameFunctionRector::class, [ - 'chop' => 'rtrim', - 'doubleval' => 'floatval', - 'fputs' => 'fwrite', - 'gzputs' => 'gzwrites', - 'ini_alter' => 'ini_set', - 'is_double' => 'is_float', - 'is_integer' => 'is_int', - 'is_long' => 'is_int', - 'is_real' => 'is_float', + 'chop' => 'rtrim', + 'doubleval' => 'floatval', + 'fputs' => 'fwrite', + 'gzputs' => 'gzwrites', + 'ini_alter' => 'ini_set', + 'is_double' => 'is_float', + 'is_integer' => 'is_int', + 'is_long' => 'is_int', + 'is_real' => 'is_float', 'is_writeable' => 'is_writable', - 'join' => 'implode', - 'key_exists' => 'array_key_exists', - 'mbstrcut' => 'mb_strcut', - 'mbstrlen' => 'mb_strlen', - 'mbstrpos' => 'mb_strpos', - 'mbstrrpos' => 'mb_strrpos', - 'mbsubstr' => 'mb_substr', - 'pos' => 'current', - 'sizeof' => 'count', - 'split' => 'explode', - 'strchr' => 'strstr', + 'join' => 'implode', + 'key_exists' => 'array_key_exists', + 'mbstrcut' => 'mb_strcut', + 'mbstrlen' => 'mb_strlen', + 'mbstrpos' => 'mb_strpos', + 'mbstrrpos' => 'mb_strrpos', + 'mbsubstr' => 'mb_substr', + 'pos' => 'current', + 'sizeof' => 'count', + 'split' => 'explode', + 'strchr' => 'strstr', ], ); @@ -281,30 +267,30 @@ $rectorConfig->ruleWithConfiguration( RenameFunctionRector::class, [ - 'pg_clientencoding' => 'pg_client_encoding', - 'pg_cmdtuples' => 'pg_affected_rows', - 'pg_errormessage' => 'pg_last_error', - 'pg_fieldisnull' => 'pg_field_is_null', - 'pg_fieldname' => 'pg_field_name', - 'pg_fieldnum' => 'pg_field_num', - 'pg_fieldprtlen' => 'pg_field_prtlen', - 'pg_fieldsize' => 'pg_field_size', - 'pg_fieldtype' => 'pg_field_type', - 'pg_freeresult' => 'pg_free_result', - 'pg_getlastoid' => 'pg_last_oid', - 'pg_loclose' => 'pg_lo_close', - 'pg_locreate' => 'pg_lo_create', - 'pg_loexport' => 'pg_lo_export', - 'pg_loimport' => 'pg_lo_import', - 'pg_loopen' => 'pg_lo_open', - 'pg_loread' => 'pg_lo_read', - 'pg_loreadall' => 'pg_lo_read_all', - 'pg_lounlink' => 'pg_lo_unlink', - 'pg_lowrite' => 'pg_lo_write', - 'pg_numfields' => 'pg_num_fields', - 'pg_numrows' => 'pg_num_rows', - 'pg_result' => 'pg_fetch_result', - 'pg_setclientencoding' => 'pg_set_client_encoding' + 'pg_clientencoding' => 'pg_client_encoding', + 'pg_cmdtuples' => 'pg_affected_rows', + 'pg_errormessage' => 'pg_last_error', + 'pg_fieldisnull' => 'pg_field_is_null', + 'pg_fieldname' => 'pg_field_name', + 'pg_fieldnum' => 'pg_field_num', + 'pg_fieldprtlen' => 'pg_field_prtlen', + 'pg_fieldsize' => 'pg_field_size', + 'pg_fieldtype' => 'pg_field_type', + 'pg_freeresult' => 'pg_free_result', + 'pg_getlastoid' => 'pg_last_oid', + 'pg_loclose' => 'pg_lo_close', + 'pg_locreate' => 'pg_lo_create', + 'pg_loexport' => 'pg_lo_export', + 'pg_loimport' => 'pg_lo_import', + 'pg_loopen' => 'pg_lo_open', + 'pg_loread' => 'pg_lo_read', + 'pg_loreadall' => 'pg_lo_read_all', + 'pg_lounlink' => 'pg_lo_unlink', + 'pg_lowrite' => 'pg_lo_write', + 'pg_numfields' => 'pg_num_fields', + 'pg_numrows' => 'pg_num_rows', + 'pg_result' => 'pg_fetch_result', + 'pg_setclientencoding' => 'pg_set_client_encoding', ], ); @@ -319,7 +305,7 @@ new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'l', 'lt'), new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'gte', 'ge'), new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'lte', 'le'), - new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'n', 'ne') + new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'n', 'ne'), ], ); @@ -327,16 +313,16 @@ FuncCallToConstFetchRector::class, [ 'php_sapi_name' => 'PHP_SAPI', - 'pi' => 'M_PI' + 'pi' => 'M_PI', ], ); $rectorConfig->rules([ AbsolutizeRequireAndIncludePathRector::class, // ActionInjectionToConstructorInjectionRector::class, - AddArrayDefaultToArrayPropertyRector::class, + // AddArrayDefaultToArrayPropertyRector::class, AddArrowFunctionReturnTypeRector::class, - AddClosureReturnTypeRector::class, + // AddClosureReturnTypeRector::class, // AddFalseDefaultToBoolPropertyRector::class, AddMethodCallBasedStrictParamTypeRector::class, AddParamBasedOnParentClassMethodRector::class, @@ -351,7 +337,7 @@ // ArrayKeysAndInArrayToArrayKeyExistsRector::class, ArrayMergeOfNonArraysToSimpleArrayRector::class, // ArrayShapeFromConstantArrayReturnRector::class, - BinarySwitchToIfElseRector::class, + // BinarySwitchToIfElseRector::class, BooleanNotIdenticalToNotIdenticalRector::class, BoolvalToTypeCastRector::class, CallableThisArrayToAnonymousFunctionRector::class, @@ -384,7 +370,7 @@ EncapsedStringsToSprintfRector::class, ExplicitBoolCompareRector::class, // ExplicitMethodCallOverMagicGetSetRector::class, - FinalizeClassesWithoutChildrenRector::class, + // FinalizeClassesWithoutChildrenRector::class, FinalPrivateToPrivateVisibilityRector::class, FlipTypeControlToUseExclusiveTypeRector::class, FloatvalToTypeCastRector::class, @@ -415,7 +401,7 @@ // ParamAnnotationIncorrectNullableRector::class, ParamTypeByMethodCallTypeRector::class, ParamTypeByParentCallTypeRector::class, - ParamTypeFromStrictTypedPropertyRector::class, + // ParamTypeFromStrictTypedPropertyRector::class, // Php8ResourceReturnToObjectRector::class, PostIncDecToPreIncDecRector::class, PrivatizeFinalClassMethodRector::class, @@ -444,7 +430,7 @@ // RemoveEmptyTestMethodRector::class, RemoveExtraParametersRector::class, RemoveFinalFromConstRector::class, - RemoveJustPropertyFetchForAssignRector::class, + // RemoveJustPropertyFetchForAssignRector::class, // RemoveJustVariableAssignRector::class, // RemoveLastReturnRector::class, // RemoveNonExistingVarAnnotationRector::class, @@ -466,7 +452,7 @@ RenameForeachValueVariableToMatchExprVariableRector::class, RenameForeachValueVariableToMatchMethodCallReturnTypeRector::class, ReplaceMultipleBooleanNotRector::class, - ReturnAnnotationIncorrectNullableRector::class, + // ReturnAnnotationIncorrectNullableRector::class, // ReturnBinaryAndToEarlyReturnRector::class, ReturnBinaryOrToEarlyReturnRector::class, ReturnEarlyIfVariableRector::class, @@ -477,7 +463,7 @@ ReturnTypeFromStrictConstantReturnRector::class, ReturnTypeFromStrictNativeCallRector::class, ReturnTypeFromStrictNewArrayRector::class, - ReturnTypeFromStrictScalarReturnExprRector::class, + // ReturnTypeFromStrictScalarReturnExprRector::class, ReturnTypeFromStrictTernaryRector::class, ReturnTypeFromStrictTypedCallRector::class, ReturnTypeFromStrictTypedPropertyRector::class, @@ -532,10 +518,10 @@ // TokenGetAllToObjectRector::class, TypedPropertyFromAssignsRector::class, TypedPropertyFromStrictConstructorRector::class, - TypedPropertyFromStrictGetterMethodReturnTypeRector::class, + // TypedPropertyFromStrictGetterMethodReturnTypeRector::class, TypedPropertyFromStrictSetUpRector::class, UnnecessaryTernaryExpressionRector::class, - UnSpreadOperatorRector::class, + // UnSpreadOperatorRector::class, UnusedForeachValueToArrayKeysRector::class, UnwrapFutureCompatibleIfPhpVersionRector::class, UnwrapSprintfOneArgumentRector::class, diff --git a/src/Auth/Guard.php b/src/Auth/Guard.php index 0c8c0008..8469ee1d 100644 --- a/src/Auth/Guard.php +++ b/src/Auth/Guard.php @@ -171,10 +171,10 @@ public function setImpersonating( public function setUser( Authenticatable $user, - ): void { + ): self { if ($this->isImpersonating()) { if ($this->getImposter()?->getUser() === $user) { - return; + return $this; } $this->stopImpersonating(); @@ -189,6 +189,8 @@ public function setUser( if (null === $source || self::SOURCE_SESSION === $source) { $this->getAuthenticationGuard()->setUser($user); } + + return $this; } public function user(): ?Authenticatable diff --git a/src/Entities/InstanceEntityTrait.php b/src/Entities/InstanceEntityTrait.php index 43faa890..3c4de02a 100644 --- a/src/Entities/InstanceEntityTrait.php +++ b/src/Entities/InstanceEntityTrait.php @@ -36,7 +36,7 @@ public function setConfiguration( $this->configuration = $configuration; - if ($this->configuration instanceof \Auth0\SDK\Configuration\SdkConfiguration && $this->sdk instanceof Auth0Interface) { + if ($this->configuration instanceof SdkConfiguration && $this->sdk instanceof Auth0Interface) { $this->sdk->setConfiguration($this->configuration); } diff --git a/src/Guards/AuthenticationGuard.php b/src/Guards/AuthenticationGuard.php index 559e0c70..dc362f75 100644 --- a/src/Guards/AuthenticationGuard.php +++ b/src/Guards/AuthenticationGuard.php @@ -253,10 +253,10 @@ public function setImpersonating( public function setUser( Authenticatable $user, - ): void { + ): self { if ($this->isImpersonating()) { if ($this->getImposter()?->getUser() === $user) { - return; + return $this; } $this->stopImpersonating(); @@ -267,6 +267,8 @@ public function setUser( $this->setCredential($credential); $this->pushState($credential); + + return $this; } public function user(): ?Authenticatable diff --git a/src/Guards/AuthorizationGuard.php b/src/Guards/AuthorizationGuard.php index 55d43f98..0172038c 100644 --- a/src/Guards/AuthorizationGuard.php +++ b/src/Guards/AuthorizationGuard.php @@ -190,10 +190,10 @@ public function setImpersonating( public function setUser( Authenticatable $user, - ): void { + ): self { if ($this->isImpersonating()) { if ($this->getImposter()?->getUser() === $user) { - return; + return $this; } $this->stopImpersonating(); @@ -203,6 +203,8 @@ public function setUser( $credential->setUser($user); $this->setCredential($credential); + + return $this; } public function user(): ?Authenticatable diff --git a/src/Guards/GuardAbstract.php b/src/Guards/GuardAbstract.php index 096373f8..f5cf935b 100644 --- a/src/Guards/GuardAbstract.php +++ b/src/Guards/GuardAbstract.php @@ -299,7 +299,7 @@ abstract public function setImpersonating( abstract public function setUser( Authenticatable $user, - ): void; + ): self; abstract public function user(): ?Authenticatable; diff --git a/src/Guards/GuardContract.php b/src/Guards/GuardContract.php index 6b44fcf2..26030567 100644 --- a/src/Guards/GuardContract.php +++ b/src/Guards/GuardContract.php @@ -190,7 +190,7 @@ public function setImpersonating( */ public function setUser( Authenticatable $user, - ): void; + ): self; /** * Stop impersonating a user. diff --git a/src/Middleware/AuthenticateMiddlewareAbstract.php b/src/Middleware/AuthenticateMiddlewareAbstract.php index 555efc76..de1b64b7 100644 --- a/src/Middleware/AuthenticateMiddlewareAbstract.php +++ b/src/Middleware/AuthenticateMiddlewareAbstract.php @@ -7,7 +7,7 @@ use Auth0\Laravel\Entities\CredentialEntityContract; use Auth0\Laravel\Events; use Auth0\Laravel\Events\Middleware\StatefulMiddlewareRequest; -use Auth0\Laravel\Guards\{AuthenticationGuardContract, GuardContract}; +use Auth0\Laravel\Guards\GuardContract; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/src/Middleware/AuthenticateOptionalMiddlewareAbstract.php b/src/Middleware/AuthenticateOptionalMiddlewareAbstract.php index 15585cfd..7dd6345d 100644 --- a/src/Middleware/AuthenticateOptionalMiddlewareAbstract.php +++ b/src/Middleware/AuthenticateOptionalMiddlewareAbstract.php @@ -7,7 +7,7 @@ use Auth0\Laravel\Entities\CredentialEntityContract; use Auth0\Laravel\Events; use Auth0\Laravel\Events\Middleware\StatefulMiddlewareRequest; -use Auth0\Laravel\Guards\{AuthenticationGuardContract, GuardContract}; +use Auth0\Laravel\Guards\GuardContract; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/src/Middleware/AuthorizeMiddlewareAbstract.php b/src/Middleware/AuthorizeMiddlewareAbstract.php index c23b6d4d..2e8aec9b 100644 --- a/src/Middleware/AuthorizeMiddlewareAbstract.php +++ b/src/Middleware/AuthorizeMiddlewareAbstract.php @@ -7,7 +7,7 @@ use Auth0\Laravel\Entities\CredentialEntityContract; use Auth0\Laravel\Events; use Auth0\Laravel\Events\Middleware\StatelessMiddlewareRequest; -use Auth0\Laravel\Guards\{AuthorizationGuardContract, GuardContract}; +use Auth0\Laravel\Guards\GuardContract; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/src/Middleware/AuthorizeOptionalMiddlewareAbstract.php b/src/Middleware/AuthorizeOptionalMiddlewareAbstract.php index 091d270b..cca15c4e 100644 --- a/src/Middleware/AuthorizeOptionalMiddlewareAbstract.php +++ b/src/Middleware/AuthorizeOptionalMiddlewareAbstract.php @@ -7,7 +7,7 @@ use Auth0\Laravel\Entities\CredentialEntityContract; use Auth0\Laravel\Events; use Auth0\Laravel\Events\Middleware\StatelessMiddlewareRequest; -use Auth0\Laravel\Guards\{AuthenticationGuardContract, GuardContract}; +use Auth0\Laravel\Guards\GuardContract; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/src/UserProviderAbstract.php b/src/UserProviderAbstract.php index c2fd21be..5dcbb97d 100644 --- a/src/UserProviderAbstract.php +++ b/src/UserProviderAbstract.php @@ -4,9 +4,7 @@ namespace Auth0\Laravel; -use Auth0\Laravel\Events\{TokenVerificationAttempting, TokenVerificationFailed, TokenVerificationSucceeded}; -use Auth0\Laravel\Guards\{AuthorizationGuardContract, GuardContract}; -use Auth0\Laravel\{UserRepository, UserRepositoryContract}; +use Auth0\Laravel\Guards\GuardContract; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Support\Facades\Cache; @@ -39,6 +37,18 @@ final public function getRepository(): UserRepositoryContract return $this->repository ?? $this->resolveRepository(); } + /** + * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter + * + * @param Authenticatable $user + * @param array $credentials + * @param bool $force + */ + final public function rehashPasswordIfRequired(Authenticatable $user, array $credentials, bool $force = false): void + { + + } + /** * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter * diff --git a/src/Users/UserAbstract.php b/src/Users/UserAbstract.php index d07055b8..eb593f25 100644 --- a/src/Users/UserAbstract.php +++ b/src/Users/UserAbstract.php @@ -50,6 +50,11 @@ final public function getAuthPassword(): string return ''; } + final public function getAuthPasswordName(): string + { + return 'password'; + } + final public function getRememberToken(): string { return ''; From da11246cddd0698fa28c3deca4cd09af4142c3e5 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 11 Mar 2024 17:28:31 -0500 Subject: [PATCH 499/525] chore: normalize manifest to fix linter warning --- composer.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index cba51bd6..ef0b824f 100644 --- a/composer.json +++ b/composer.json @@ -34,12 +34,6 @@ "forum": "https://community.auth0.com/", "source": "https://github.com/auth0/laravel-auth0" }, - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/asbiin/psalm-plugin-laravel.git" - } - ], "require": { "php": "^8.2", "ext-json": "*", @@ -56,10 +50,10 @@ "larastan/larastan": "^2", "mockery/mockery": "^1", "orchestra/testbench": "^9.x-dev", - "pestphp/pest-plugin-laravel": "^2", "pestphp/pest": "^2", - "phpstan/phpstan-strict-rules": "^1", + "pestphp/pest-plugin-laravel": "^2", "phpstan/phpstan": "^1", + "phpstan/phpstan-strict-rules": "^1", "psalm/plugin-laravel": "dev-laravel11#b93c8f21c18e3355dcdae797c6af266f7aab93f6", "psr-mock/http": "^1", "rector/rector": "^1", @@ -68,6 +62,12 @@ "vimeo/psalm": "^5", "wikimedia/composer-merge-plugin": "^2" }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/asbiin/psalm-plugin-laravel.git" + } + ], "minimum-stability": "dev", "prefer-stable": true, "autoload": { From fbb708fd3be6e3b66c4cfaa2c977cddaf5cc1af6 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 11 Mar 2024 17:29:29 -0500 Subject: [PATCH 500/525] chore: fix linter warning --- src/UserProviderAbstract.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/UserProviderAbstract.php b/src/UserProviderAbstract.php index 5dcbb97d..0712c1ab 100644 --- a/src/UserProviderAbstract.php +++ b/src/UserProviderAbstract.php @@ -46,7 +46,6 @@ final public function getRepository(): UserRepositoryContract */ final public function rehashPasswordIfRequired(Authenticatable $user, array $credentials, bool $force = false): void { - } /** From 7b687f07bc64e88dd3cfc65d148434d9c8d909cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Fran=C3=A7a?= Date: Mon, 11 Mar 2024 19:34:51 -0300 Subject: [PATCH 501/525] Add verification if telescope is enabled using config helper (#444) --- src/Guards/AuthenticationGuard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Guards/AuthenticationGuard.php b/src/Guards/AuthenticationGuard.php index dc362f75..ceea8515 100644 --- a/src/Guards/AuthenticationGuard.php +++ b/src/Guards/AuthenticationGuard.php @@ -283,7 +283,7 @@ public function user(): ?Authenticatable * @var ?Authenticatable $lastResponse */ // @codeCoverageIgnoreStart - if (class_exists('\Laravel\Telescope\Telescope')) { + if (class_exists('\Laravel\Telescope\Telescope') && true === config('telescope.enabled')) { static $depth = 0; static $lastCalled = null; From 2756ac9bff16c15a422cde0d83612d61dfe10614 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 11 Mar 2024 17:35:16 -0500 Subject: [PATCH 502/525] chore(ci): temporarily remove `--strict` from validator --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3004afa4..f34167be 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -97,7 +97,7 @@ jobs: with: php: ${{ matrix.php }} - - run: composer validate --strict + - run: composer validate pest: name: PEST From 67ca8d9d3a2e66ac7145a0e50508c1692cbd8147 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 11 Mar 2024 18:15:14 -0500 Subject: [PATCH 503/525] Release 7.13.0 (#446) --- .version | 2 +- CHANGELOG.md | 191 ++++++++++++++++++++++------------------ src/ServiceAbstract.php | 2 +- 3 files changed, 105 insertions(+), 90 deletions(-) diff --git a/.version b/.version index 5f84a81d..eb1dc6a5 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -7.12.0 +7.13.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 58d0d1ae..eda944c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,60 +1,75 @@ # Changelog +## [7.13.0](https://github.com/auth0/laravel-auth0/tree/7.12.0) (2024-03-11) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.12.0...7.13.0) + +**Added** + +- Add support for Laravel 11 [\#445](https://github.com/auth0/laravel-auth0/pull/445) ([evansims](https://github.com/evansims)) + +**Changed** + +- Verify that Telescope is enabled via configuration helper [\#444](https://github.com/auth0/laravel-auth0/pull/444) ([samuelhgf](https://github.com/samuelhgf)) + ## [7.12.0](https://github.com/auth0/laravel-auth0/tree/7.12.0) (2023-12-07) + [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.11.0...7.12.0) **Added** -- Implement support for Back-Channel Logout [\#435](https://github.com/auth0/laravel-auth0/pull/435) ([evansims](https://github.com/evansims)) -- Restore configurable route paths [\#436](https://github.com/auth0/laravel-auth0/pull/436) ([evansims](https://github.com/evansims)) + +- Implement support for Back-Channel Logout [\#435](https://github.com/auth0/laravel-auth0/pull/435) ([evansims](https://github.com/evansims)) +- Restore configurable route paths [\#436](https://github.com/auth0/laravel-auth0/pull/436) ([evansims](https://github.com/evansims)) **Fixed** -- Resolve `CacheBridgeAbstract::save()` not storing values when cache misses [\#434](https://github.com/auth0/laravel-auth0/pull/434) ([seruymt](https://github.com/seruymt)) + +- Resolve `CacheBridgeAbstract::save()` not storing values when cache misses [\#434](https://github.com/auth0/laravel-auth0/pull/434) ([seruymt](https://github.com/seruymt)) ## [7.11.0](https://github.com/auth0/laravel-auth0/tree/7.11.0) (2023-08-08) **Added** -- Significant performance improvements by eliminating redundant user queries. -- Compatibility support for [Laravel Telescope](https://laravel.com/docs/telescope). See [docs/Telescope.md](./docs/Telescope.md) for more information. -- A refactored Events API has been introduced. See [docs/Events.md](./docs/Events.md) for more information. -- `AUTH0_SESSION_STORAGE` and `AUTH0_TRANSIENT_STORAGE` now support a `cookie` value to enable the native Auth0-PHP SDK cookie session handler. See [docs/Cookies.md](./docs/Cookies.md) for more information. +- Significant performance improvements by eliminating redundant user queries. +- Compatibility support for [Laravel Telescope](https://laravel.com/docs/telescope). See [docs/Telescope.md](./docs/Telescope.md) for more information. +- A refactored Events API has been introduced. See [docs/Events.md](./docs/Events.md) for more information. +- `AUTH0_SESSION_STORAGE` and `AUTH0_TRANSIENT_STORAGE` now support a `cookie` value to enable the native Auth0-PHP SDK cookie session handler. See [docs/Cookies.md](./docs/Cookies.md) for more information. **Fixed** -- Addressed an issue where, under certain circumstances, the first user authentication attempt after a session invalidation could fail. +- Addressed an issue where, under certain circumstances, the first user authentication attempt after a session invalidation could fail. **Changed** -- Session regeneration/invalidation has been refactored. -- Discarded sessions are now deleted when they are invalidated by the SDK, rather than wait for Laravel to garbage collect. -- Session storage has been refactored. Session data is now stored as a JSON array in a single `auth0_session` entry in the Laravel session store, rather than in multiple keys. +- Session regeneration/invalidation has been refactored. +- Discarded sessions are now deleted when they are invalidated by the SDK, rather than wait for Laravel to garbage collect. +- Session storage has been refactored. Session data is now stored as a JSON array in a single `auth0_session` entry in the Laravel session store, rather than in multiple keys. **Documentation** -- A demonstration Eloquent user model and repository implementation has been added to [docs/Eloquent.md](./docs/Eloquent.md). -- A new [docs/Sessions.md](./docs/Sessions.md) document has been added for guidance on the various session driver options available. +- A demonstration Eloquent user model and repository implementation has been added to [docs/Eloquent.md](./docs/Eloquent.md). +- A new [docs/Sessions.md](./docs/Sessions.md) document has been added for guidance on the various session driver options available. ## [7.10.1](https://github.com/auth0/laravel-auth0/tree/7.10.1) (2023-08-07) **Fixed** -- Addressed an issue where, under certain circumstances, permissions state could be lost after authenticating. +- Addressed an issue where, under certain circumstances, permissions state could be lost after authenticating. ## [7.10.0](https://github.com/auth0/laravel-auth0/tree/7.10.0) (2023-07-24) **Added** -- Organization Name support added for Authentication API and token handling ¹ +- Organization Name support added for Authentication API and token handling ¹ **Changed** -- Guards are now registered with the priority middleware list. -- Bumped `auth0-php` dependency version range to `^8.7`. -- Updated telemetry to indicate new `laravel` package name (previously `laravel-auth0`.) +- Guards are now registered with the priority middleware list. +- Bumped `auth0-php` dependency version range to `^8.7`. +- Updated telemetry to indicate new `laravel` package name (previously `laravel-auth0`.) **Fixed** -- Addressed issue where placeholder `AUTH0_` dotenv values could erroneously be interpreted as true configuration values. +- Addressed issue where placeholder `AUTH0_` dotenv values could erroneously be interpreted as true configuration values. > **Note** > ¹ To use this feature, an Auth0 tenant must have support for it enabled. This feature is not yet available to all tenants. @@ -63,98 +78,98 @@ **Fixed** -- Resolved an issue where, under certain circumstances, the AuthenticationGuard middleware could get erroneously added to the `api` middleware group, causing a session to be established in a stateless request. ([\#415](https://github.com/auth0/laravel-auth0/pull/415)) +- Resolved an issue where, under certain circumstances, the AuthenticationGuard middleware could get erroneously added to the `api` middleware group, causing a session to be established in a stateless request. ([\#415](https://github.com/auth0/laravel-auth0/pull/415)) ## [7.9.0](https://github.com/auth0/laravel-auth0/tree/7.9.0) (2023-06-15) **Added** -- SDK configuration (`config/auth0.php`) now supports a `configurationPath` property for specifying a custom search path for `.auth0.*.json` and `.env*` files. ([\#407](https://github.com/auth0/laravel-auth0/pull/407)) -- `Auth0\Laravel\Guards\GuardAbstract` now extends `Illuminate\Contracts\Auth\Guard`. ([\#410](https://github.com/auth0/laravel-auth0/pull/410)) +- SDK configuration (`config/auth0.php`) now supports a `configurationPath` property for specifying a custom search path for `.auth0.*.json` and `.env*` files. ([\#407](https://github.com/auth0/laravel-auth0/pull/407)) +- `Auth0\Laravel\Guards\GuardAbstract` now extends `Illuminate\Contracts\Auth\Guard`. ([\#410](https://github.com/auth0/laravel-auth0/pull/410)) **Fixed** -- Resolved host environment variables not being loaded as expected when a `.env` file is also used. ([\#408](https://github.com/auth0/laravel-auth0/pull/408)) -- Resolved surrounding quote characters not being trimmed from environment variables and `.env` files during processing. ([\#409](https://github.com/auth0/laravel-auth0/pull/409)) +- Resolved host environment variables not being loaded as expected when a `.env` file is also used. ([\#408](https://github.com/auth0/laravel-auth0/pull/408)) +- Resolved surrounding quote characters not being trimmed from environment variables and `.env` files during processing. ([\#409](https://github.com/auth0/laravel-auth0/pull/409)) ## [7.8.1](https://github.com/auth0/laravel-auth0/tree/7.8.1) (2023-05-19) **Fixed** -- Resolved an issue where parsing `.env` files could sometimes throw an exception when handling non-key-value pair strings. ([\#395](https://github.com/auth0/laravel-auth0/pull/395)) +- Resolved an issue where parsing `.env` files could sometimes throw an exception when handling non-key-value pair strings. ([\#395](https://github.com/auth0/laravel-auth0/pull/395)) ## [7.8.0](https://github.com/auth0/laravel-auth0/tree/7.8.0) (2023-05-18) **Added** -- This release adds support for authenticating using **[Pushed Authorization Requests](https://www.rfc-editor.org/rfc/rfc6749)**. +- This release adds support for authenticating using **[Pushed Authorization Requests](https://www.rfc-editor.org/rfc/rfc6749)**. -- This release introduces **two new Authentication Guards** which provide a streamlined integration experience for developers that need to simultaneously support both session-based authentication and token-based endpoint authorization in their Laravel applications. +- This release introduces **two new Authentication Guards** which provide a streamlined integration experience for developers that need to simultaneously support both session-based authentication and token-based endpoint authorization in their Laravel applications. | Guard | Class | Description | | --------------------- | ----------------------------------------------- | ----------------------------- | | `auth0.authenticator` | `Auth0\Laravel\Auth\Guards\AuthenticationGuard` | Session-based authentication. | | `auth0.authorizer` | `Auth0\Laravel\Auth\Guards\AuthorizationGuard` | Token-based authorization. | -- These guards are compatible with Laravel's Authentication API and support the standard `auth` middleware. +- These guards are compatible with Laravel's Authentication API and support the standard `auth` middleware. -- These guards are compatible with Laravel's Authorization API and support the standard `can` middleware, and the `Guard` facade, and work with the Policies API. +- These guards are compatible with Laravel's Authorization API and support the standard `can` middleware, and the `Guard` facade, and work with the Policies API. -- 3 new pre-built Guards are available: `scope` and `permission`, as well as a dynamic `*:*`. This enables you to verify whether the user's access token has a particular scope or (if RBAC is enabled on the Auth0 API) a particular permission. For example `Gate::check('scope', 'email')` or `Route::get(/*...*/)->can('read:messages')`. +- 3 new pre-built Guards are available: `scope` and `permission`, as well as a dynamic `*:*`. This enables you to verify whether the user's access token has a particular scope or (if RBAC is enabled on the Auth0 API) a particular permission. For example `Gate::check('scope', 'email')` or `Route::get(/*...*/)->can('read:messages')`. -- The SDK now automatically registers these guards to Laravel's standard `web` and `api` middleware groups, respectively. Manual Guard setup in `config/auth.php` is no longer necessary. +- The SDK now automatically registers these guards to Laravel's standard `web` and `api` middleware groups, respectively. Manual Guard setup in `config/auth.php` is no longer necessary. -- The SDK now automatically registers the Authentication routes. Manual route setup in `routes/web.php` is no longer necessary. +- The SDK now automatically registers the Authentication routes. Manual route setup in `routes/web.php` is no longer necessary. -- 2 new routing Middleware have been added: `Auth0\Laravel\Http\Middleware\AuthenticatorMiddleware` and `Auth0\Laravel\Http\Middleware\AuthorizerMiddleware`. These are automatically registered with your Laravel application, and ensure the Auth0 Guards are used for authentication for `web` routes and authorization for `api` routes, respectively. This replaces the need for the `guard` middleware or otherwise manual Guard assignment in your routes. +- 2 new routing Middleware have been added: `Auth0\Laravel\Http\Middleware\AuthenticatorMiddleware` and `Auth0\Laravel\Http\Middleware\AuthorizerMiddleware`. These are automatically registered with your Laravel application, and ensure the Auth0 Guards are used for authentication for `web` routes and authorization for `api` routes, respectively. This replaces the need for the `guard` middleware or otherwise manual Guard assignment in your routes. **Changed** -- We've introduced **a new configuration syntax**. This new syntax is more flexible and allows for more complex configuration scenarios, and introduces support for multiple guard instances. Developers using the previous syntax will have their existing configurations applied to all guards uniformly. +- We've introduced **a new configuration syntax**. This new syntax is more flexible and allows for more complex configuration scenarios, and introduces support for multiple guard instances. Developers using the previous syntax will have their existing configurations applied to all guards uniformly. -- The SDK can now **configure itself using a `.auth0.json` file in the project root directory**. This file can be generated [using the Auth0 CLI](./docs/Configuration.md), and provides a significantly simpler configuration experience for developers. +- The SDK can now **configure itself using a `.auth0.json` file in the project root directory**. This file can be generated [using the Auth0 CLI](./docs/Configuration.md), and provides a significantly simpler configuration experience for developers. -- The previous `auth0.guard` Guard (`Auth0\Laravel\Auth\Guard`) has been **refactored** as a lightweight wrapper around the new `AuthenticationGuard` and `AuthorizationGuard` guards. +- The previous `auth0.guard` Guard (`Auth0\Laravel\Auth\Guard`) has been **refactored** as a lightweight wrapper around the new `AuthenticationGuard` and `AuthorizationGuard` guards. ## [7.7.0](https://github.com/auth0/laravel-auth0/tree/7.7.0) (2023-04-26) **Added** -- `Auth0\Laravel\Auth0` now has a `management()` shortcut method for issuing Management API calls. ([\#376](https://github.com/auth0/laravel-auth0/pull/376)) +- `Auth0\Laravel\Auth0` now has a `management()` shortcut method for issuing Management API calls. ([\#376](https://github.com/auth0/laravel-auth0/pull/376)) -- `Auth0\Laravel\Auth0\Guard` now has a `refreshUser()` method for querying `/userinfo` endpoint and refreshing the authenticated user's cached profile data. ([\#375](https://github.com/auth0/laravel-auth0/pull/375)) +- `Auth0\Laravel\Auth0\Guard` now has a `refreshUser()` method for querying `/userinfo` endpoint and refreshing the authenticated user's cached profile data. ([\#375](https://github.com/auth0/laravel-auth0/pull/375)) -- `Auth0\Laravel\Http\Controller\Stateful\Login` now raises a `LoginAttempting` event, offering an opportunity to customize the authorization parameters before the login redirect is issued. ([\#382](https://github.com/auth0/laravel-auth0/pull/382)) +- `Auth0\Laravel\Http\Controller\Stateful\Login` now raises a `LoginAttempting` event, offering an opportunity to customize the authorization parameters before the login redirect is issued. ([\#382](https://github.com/auth0/laravel-auth0/pull/382)) **Changed** -- The `tokenCache`, `managementTokenCache`, `sessionStorage` and `transientStorage` configuration values now support `false` or `string` values pointing to class names (e.g. `\Some\Cache::class`) or class aliases (e.g. `cache.psr6`) registered with Laravel. ([\#381](https://github.com/auth0/laravel-auth0/pull/381)) +- The `tokenCache`, `managementTokenCache`, `sessionStorage` and `transientStorage` configuration values now support `false` or `string` values pointing to class names (e.g. `\Some\Cache::class`) or class aliases (e.g. `cache.psr6`) registered with Laravel. ([\#381](https://github.com/auth0/laravel-auth0/pull/381)) ## [7.6.0](https://github.com/auth0/laravel-auth0/tree/7.6.0) (2023-04-12) **Added** -- `Auth0\Laravel\Http\Middleware\Guard`, new middleware that forces Laravel to route requests through a group using a specific Guard. ([\#362](https://github.com/auth0/laravel-auth0/pull/362)) +- `Auth0\Laravel\Http\Middleware\Guard`, new middleware that forces Laravel to route requests through a group using a specific Guard. ([\#362](https://github.com/auth0/laravel-auth0/pull/362)) **Changed** -- `Auth0\Laravel\Http\Middleware\Stateful\Authenticate` now remembers the intended route (using `redirect()->setIntendedUrl()`) before kicking off the authentication flow redirect. Users will be returned to the memorized intended route after completing their authentication flow. ([\#364](https://github.com/auth0/laravel-auth0/pull/364)) +- `Auth0\Laravel\Http\Middleware\Stateful\Authenticate` now remembers the intended route (using `redirect()->setIntendedUrl()`) before kicking off the authentication flow redirect. Users will be returned to the memorized intended route after completing their authentication flow. ([\#364](https://github.com/auth0/laravel-auth0/pull/364)) **Fixed** -- legacyGuardUserMethod behavior should use `$session`, not `$token` ([\#353](https://github.com/auth0/laravel-auth0/pull/365)) +- legacyGuardUserMethod behavior should use `$session`, not `$token` ([\#353](https://github.com/auth0/laravel-auth0/pull/365)) ## [7.5.2](https://github.com/auth0/laravel-auth0/tree/7.5.2) (2023-04-10) **Fixed** -- Relaxed response types from middleware to use low-level `Symfony\Component\HttpFoundation\Response` class, allowing for broader and custom response types. +- Relaxed response types from middleware to use low-level `Symfony\Component\HttpFoundation\Response` class, allowing for broader and custom response types. ## [7.5.1](https://github.com/auth0/laravel-auth0/tree/7.5.1) (2023-04-04) **Fixed** -- Resolved an issue wherein custom user repositories could fail to be instantiated under certain circumstances. +- Resolved an issue wherein custom user repositories could fail to be instantiated under certain circumstances. ## [7.5.0](https://github.com/auth0/laravel-auth0/tree/7.5.0) (2023-04-03) @@ -162,30 +177,30 @@ This release includes support for Laravel 10, and major improvements to the inte **Added** -- Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) -- New `Auth0\Laravel\Traits\Imposter` trait to allow for easier testing. [Example usage](./tests/Unit/Traits/ImpersonateTest.php) -- New Exception types have been added for more precise error-catching. +- Support for Laravel 10 [#349](https://github.com/auth0/laravel-auth0/pull/349) +- New `Auth0\Laravel\Traits\Imposter` trait to allow for easier testing. [Example usage](./tests/Unit/Traits/ImpersonateTest.php) +- New Exception types have been added for more precise error-catching. **Changed** The following changes have no effect on the external API of this package but may affect internal usage. -- `Guard` will now more reliably detect changes in the underlying Auth0-PHP SDK session state. -- `Guard` will now more reliably sync changes back to the underlying Auth0-PHP SDK session state. -- `StateInstance` concept has been replaced by a new `Credentials` entity. -- `Guard` updated to use new `Credentials` entity as primary internal storage for user data. -- `Auth0\Laravel\Traits\ActingAsAuth0User` was updated to use new `Credentials` entity. -- The HTTP middleware has been refactored to more clearly differentiate between token and session-based identities. -- The `authenticate`, `authenticate.optional` and `authorize.optional` HTTP middleware now supports scope filtering, as `authorize` already did. +- `Guard` will now more reliably detect changes in the underlying Auth0-PHP SDK session state. +- `Guard` will now more reliably sync changes back to the underlying Auth0-PHP SDK session state. +- `StateInstance` concept has been replaced by a new `Credentials` entity. +- `Guard` updated to use new `Credentials` entity as primary internal storage for user data. +- `Auth0\Laravel\Traits\ActingAsAuth0User` was updated to use new `Credentials` entity. +- The HTTP middleware has been refactored to more clearly differentiate between token and session-based identities. +- The `authenticate`, `authenticate.optional` and `authorize.optional` HTTP middleware now supports scope filtering, as `authorize` already did. -- Upgraded test suite to use PEST 2.0 framework. -- Updated test coverage to 100%. +- Upgraded test suite to use PEST 2.0 framework. +- Updated test coverage to 100%. **Fixed** -- A 'Session store not set on request' error could occur when downstream applications implemented unit testing that uses the Guard. This should be resolved now. -- `Guard` would not always honor the `provider` configuration value in `config/auth.php`. -- `Guard` is no longer defined as a Singleton to better support applications that need multi-guard configurations. +- A 'Session store not set on request' error could occur when downstream applications implemented unit testing that uses the Guard. This should be resolved now. +- `Guard` would not always honor the `provider` configuration value in `config/auth.php`. +- `Guard` is no longer defined as a Singleton to better support applications that need multi-guard configurations. ### Notes @@ -203,43 +218,43 @@ We identified an issue with using identical alias naming for both the Guard and **Added** -- feat: Add `Auth0\Laravel\Event\Middleware\...` event hooks [\#340](https://github.com/auth0/laravel-auth0/pull/340) -- feat: Add `Auth0\Laravel\Event\Configuration\Building` event hook [\#339](https://github.com/auth0/laravel-auth0/pull/339) +- feat: Add `Auth0\Laravel\Event\Middleware\...` event hooks [\#340](https://github.com/auth0/laravel-auth0/pull/340) +- feat: Add `Auth0\Laravel\Event\Configuration\Building` event hook [\#339](https://github.com/auth0/laravel-auth0/pull/339) ## [7.3.0](https://github.com/auth0/laravel-auth0/tree/7.3.0) (2022-11-07) **Added** -- add: Raise additional Laravel Auth Events [\#331](https://github.com/auth0/laravel-auth0/pull/331) +- add: Raise additional Laravel Auth Events [\#331](https://github.com/auth0/laravel-auth0/pull/331) **Fixed** -- fix: `env()` incorrectly assigns `cookieExpires` to a `string` value [\#332](https://github.com/auth0/laravel-auth0/pull/332) -- fix: Auth0\Laravel\Cache\LaravelCachePool::createItem returning a cache miss [\#329](https://github.com/auth0/laravel-auth0/pull/329) +- fix: `env()` incorrectly assigns `cookieExpires` to a `string` value [\#332](https://github.com/auth0/laravel-auth0/pull/332) +- fix: Auth0\Laravel\Cache\LaravelCachePool::createItem returning a cache miss [\#329](https://github.com/auth0/laravel-auth0/pull/329) ## [7.2.2](https://github.com/auth0/laravel-auth0/tree/7.2.2) (2022-10-19) **Fixed** -- Restore `php artisan vendor:publish` command [\#321](https://github.com/auth0/laravel-auth0/pull/321) -- Bump minimum `auth0/auth0-php` version to `^8.3.4` [\#322](https://github.com/auth0/laravel-auth0/pull/322) +- Restore `php artisan vendor:publish` command [\#321](https://github.com/auth0/laravel-auth0/pull/321) +- Bump minimum `auth0/auth0-php` version to `^8.3.4` [\#322](https://github.com/auth0/laravel-auth0/pull/322) ## [7.2.1](https://github.com/auth0/laravel-auth0/tree/7.2.1) (2022-10-13) **Fixed** -- `Auth0\Laravel\Auth0` no longer requires a session configuration for stateless strategies, restoring previous behavior. [\#317](https://github.com/auth0/laravel-auth0/pull/317) -- The SDK now requires `^3.0` of the `psr/cache` dependency, to accommodate breaking changes made in the upstream interface (typed parameters and return types) for PHP 8.0+. [\#316](https://github.com/auth0/laravel-auth0/pull/316) +- `Auth0\Laravel\Auth0` no longer requires a session configuration for stateless strategies, restoring previous behavior. [\#317](https://github.com/auth0/laravel-auth0/pull/317) +- The SDK now requires `^3.0` of the `psr/cache` dependency, to accommodate breaking changes made in the upstream interface (typed parameters and return types) for PHP 8.0+. [\#316](https://github.com/auth0/laravel-auth0/pull/316) ## [7.2.0](https://github.com/auth0/laravel-auth0/tree/7.2.0) (2022-10-10) **Changed** -- `Auth0\Laravel\Store\LaravelSession` has been added as the default `sessionStorage` and `transientStorage` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Session APIs](https://laravel.com/docs/9.x/session) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307)¹ -- `Auth0\Laravel\Cache\LaravelCachePool` and `Auth0\Laravel\Cache\LaravelCacheItem` have been added as the default `tokenCache` and `managementTokenCache` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Cache APIs](https://laravel.com/docs/9.x/cache) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) -- `Auth0\Laravel\Auth\Guard` now supports the `viaRemember` method. [\#306](https://github.com/auth0/laravel-auth0/pull/306) -- `Auth0\Laravel\Http\Middleware\Stateless\Authorize` now returns a 401 status instead of 403 for unauthenticated users. [\#304](https://github.com/auth0/laravel-auth0/issues/304) -- PHP 8.0 is now the minimum supported runtime version. Please review the [README](README.md) for more information on support windows. +- `Auth0\Laravel\Store\LaravelSession` has been added as the default `sessionStorage` and `transientStorage` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Session APIs](https://laravel.com/docs/9.x/session) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307)¹ +- `Auth0\Laravel\Cache\LaravelCachePool` and `Auth0\Laravel\Cache\LaravelCacheItem` have been added as the default `tokenCache` and `managementTokenCache` interfaces for the underlying [Auth0-PHP SDK](https://github.com/auth0/auth0-PHP/). The SDK now leverages the native [Laravel Cache APIs](https://laravel.com/docs/9.x/cache) by default. [\#307](https://github.com/auth0/laravel-auth0/pull/307) +- `Auth0\Laravel\Auth\Guard` now supports the `viaRemember` method. [\#306](https://github.com/auth0/laravel-auth0/pull/306) +- `Auth0\Laravel\Http\Middleware\Stateless\Authorize` now returns a 401 status instead of 403 for unauthenticated users. [\#304](https://github.com/auth0/laravel-auth0/issues/304) +- PHP 8.0 is now the minimum supported runtime version. Please review the [README](README.md) for more information on support windows. ¹ This change may require your application's users to re-authenticate. You can avoid this by changing the `sessionStorage` and `transientStorage` options in your SDK configuration to their previous default instances of `Auth0\SDK\Store\CookieStore`, but it is recommended you migrate to the new `LaravelSession` default. @@ -247,37 +262,37 @@ We identified an issue with using identical alias naming for both the Guard and **Changed** -- Return interfaces instead of concrete classes [\#296](https://github.com/auth0/laravel-auth0/pull/296) -- change: Use class names for `app()` calls [\#291](https://github.com/auth0/laravel-auth0/pull/291) +- Return interfaces instead of concrete classes [\#296](https://github.com/auth0/laravel-auth0/pull/296) +- change: Use class names for `app()` calls [\#291](https://github.com/auth0/laravel-auth0/pull/291) **Fixed** -- Fix: `Missing Code` error on Callback Route for Octane Customers [\#297](https://github.com/auth0/laravel-auth0/pull/297) +- Fix: `Missing Code` error on Callback Route for Octane Customers [\#297](https://github.com/auth0/laravel-auth0/pull/297) ## [7.0.1](https://github.com/auth0/laravel-auth0/tree/7.0.1) (2022-06-01) **Fixed** -- Fixed an issue in `Auth0\Laravel\Http\Controller\Stateful\Callback` where `$errorDescription`'s value was assigned an incorrect value when an error was encountered. [\#266](https://github.com/auth0/laravel-auth0/pull/288) +- Fixed an issue in `Auth0\Laravel\Http\Controller\Stateful\Callback` where `$errorDescription`'s value was assigned an incorrect value when an error was encountered. [\#266](https://github.com/auth0/laravel-auth0/pull/288) ## [7.0.0](https://github.com/auth0/laravel-auth0/tree/7.0.0) (2022-03-21) Auth0 Laravel SDK v7 includes many significant changes over previous versions: -- Support for Laravel 9. -- Support for Auth0-PHP SDK 8. -- New authentication route controllers for plug-and-play login support. -- Improved authentication middleware for regular web applications. -- New authorization middleware for token-based backend API applications. +- Support for Laravel 9. +- Support for Auth0-PHP SDK 8. +- New authentication route controllers for plug-and-play login support. +- Improved authentication middleware for regular web applications. +- New authorization middleware for token-based backend API applications. As expected with a major release, Auth0 Laravel SDK v7 includes breaking changes. Please review the [upgrade guide](UPGRADE.md) thoroughly to understand the changes required to migrate your application to v7. ### Breaking Changes -- Namespace has been updated from `Auth0\Login` to `Auth0\Laravel` -- Auth0-PHP SDK dependency updated to V8 -- New configuration format -- SDK now self-registers its services and middleware -- New UserProvider API +- Namespace has been updated from `Auth0\Login` to `Auth0\Laravel` +- Auth0-PHP SDK dependency updated to V8 +- New configuration format +- SDK now self-registers its services and middleware +- New UserProvider API > Changelog entries for releases prior to 8.0 have been relocated to [CHANGELOG.ARCHIVE.md](CHANGELOG.ARCHIVE.md). diff --git a/src/ServiceAbstract.php b/src/ServiceAbstract.php index c671a023..43e8e53f 100644 --- a/src/ServiceAbstract.php +++ b/src/ServiceAbstract.php @@ -22,7 +22,7 @@ abstract class ServiceAbstract extends InstanceEntityAbstract * * @var string */ - public const VERSION = '7.12.0'; + public const VERSION = '7.13.0'; /** * Decode a PSR-7 HTTP Response Message containing a JSON content body to a PHP array. Returns null if the response was not successful, or the response body was not JSON. From 9ff4aa75ecb965656ecc2b573ef6716588c49213 Mon Sep 17 00:00:00 2001 From: Alies Lapatsin <5278175+alies-dev@users.noreply.github.com> Date: Fri, 15 Mar 2024 07:58:04 +0400 Subject: [PATCH 504/525] Use official psalm-laravel-plugin (#448) It's ready for Laravel 11 Signed-off-by: Alies Lapatsin <5278175+alies-dev@users.noreply.github.com> --- composer.json | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/composer.json b/composer.json index ef0b824f..11743f2b 100644 --- a/composer.json +++ b/composer.json @@ -54,7 +54,7 @@ "pestphp/pest-plugin-laravel": "^2", "phpstan/phpstan": "^1", "phpstan/phpstan-strict-rules": "^1", - "psalm/plugin-laravel": "dev-laravel11#b93c8f21c18e3355dcdae797c6af266f7aab93f6", + "psalm/plugin-laravel": "^2.10", "psr-mock/http": "^1", "rector/rector": "^1", "squizlabs/php_codesniffer": "^3", @@ -62,12 +62,6 @@ "vimeo/psalm": "^5", "wikimedia/composer-merge-plugin": "^2" }, - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/asbiin/psalm-plugin-laravel.git" - } - ], "minimum-stability": "dev", "prefer-stable": true, "autoload": { From 842946a7c6b0d11475d8d47a09aefac27fa5555d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Fran=C3=A7a?= Date: Fri, 15 Mar 2024 01:31:16 -0300 Subject: [PATCH 505/525] Add verification if telescope is enabled using config helper in other place (#447) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add verification if telescope is enabled using config helper * CS Fixer * chore: fix linter warning * Change Telescope class to CONST and add check telescope enabled in UserProviderAbstract --------- Signed-off-by: Samuel França Co-authored-by: Evan Sims --- src/Guards/AuthenticationGuard.php | 7 ++++++- src/UserProviderAbstract.php | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Guards/AuthenticationGuard.php b/src/Guards/AuthenticationGuard.php index ceea8515..23f8c7a6 100644 --- a/src/Guards/AuthenticationGuard.php +++ b/src/Guards/AuthenticationGuard.php @@ -27,6 +27,11 @@ */ final class AuthenticationGuard extends GuardAbstract implements AuthenticationGuardContract { + /** + * @var string + */ + protected const TELESCOPE = '\Laravel\Telescope\Telescope'; + public function find(): ?CredentialEntityContract { if ($this->isImpersonating()) { @@ -283,7 +288,7 @@ public function user(): ?Authenticatable * @var ?Authenticatable $lastResponse */ // @codeCoverageIgnoreStart - if (class_exists('\Laravel\Telescope\Telescope') && true === config('telescope.enabled')) { + if (class_exists(self::TELESCOPE) && true === config('telescope.enabled')) { static $depth = 0; static $lastCalled = null; diff --git a/src/UserProviderAbstract.php b/src/UserProviderAbstract.php index 0712c1ab..917feb9f 100644 --- a/src/UserProviderAbstract.php +++ b/src/UserProviderAbstract.php @@ -79,7 +79,7 @@ final public function retrieveByCredentials(array $credentials): ?Authenticatabl return $lastResponse; } - if (class_exists('\Laravel\Telescope\Telescope')) { + if (class_exists(self::TELESCOPE) && true === config('telescope.enabled')) { static $depth = 0; static $lastCalled = null; From 81e3cb4e3e345972a52e12161e60f1f1210b820a Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 1 Apr 2024 12:08:17 -0500 Subject: [PATCH 506/525] tests: expand coverage of new L11 user methods --- src/UserProviderAbstract.php | 2 ++ tests/Unit/Users/UserTest.php | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/UserProviderAbstract.php b/src/UserProviderAbstract.php index 917feb9f..6b3b0dbd 100644 --- a/src/UserProviderAbstract.php +++ b/src/UserProviderAbstract.php @@ -43,6 +43,8 @@ final public function getRepository(): UserRepositoryContract * @param Authenticatable $user * @param array $credentials * @param bool $force + * + * @codeCoverageIgnore */ final public function rehashPasswordIfRequired(Authenticatable $user, array $credentials, bool $force = false): void { diff --git a/tests/Unit/Users/UserTest.php b/tests/Unit/Users/UserTest.php index ec63a897..1bb58ecf 100644 --- a/tests/Unit/Users/UserTest.php +++ b/tests/Unit/Users/UserTest.php @@ -70,6 +70,13 @@ ->toBe(''); }); +it('supports getting the password name', function (): void { + $user = new ImposterUser(); + + expect($user->getAuthPasswordName()) + ->toBe('password'); +}); + it('supports getting the remember token', function (): void { $user = new ImposterUser(); From 4dc73fc246fbfdfa2b74606b990bbe3e9288b195 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 1 Apr 2024 13:37:32 -0500 Subject: [PATCH 507/525] docs: update supported release details --- README.md | 43 ++++++++++++++++++++++++++++++++++++------- docs/Installation.md | 11 +---------- docs/Support.md | 43 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 73 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 7dfa40d1..c25f3bc1 100644 --- a/README.md +++ b/README.md @@ -26,16 +26,45 @@ ## Requirements -Your application must use the [latest supported Laravel version](https://endoflife.date/laravel), and your host environment must be running a [supported PHP version](https://www.php.net/supported-versions.php). Please review [our support policy](./docs/Support.md) for more information. +Your application must use a [supported Laravel version](#supported-laravel-releases), and your host environment must be running a [maintained PHP version](https://www.php.net/supported-versions.php). Please review [our support policy](./docs/Support.md) for more information. -| SDK | Laravel | PHP | Supported Until | -| ----- | ---------------------------------------------- | ---------------------------------------------- | --------------- | -| 7.13+ | [11.x](https://laravel.com/docs/11.x/releases) | [8.3](https://www.php.net/releases/8.3/en.php) | ~Sep 2025 | -| | | [8.2](https://www.php.net/releases/8.2/en.php) | ~Sep 2025 | +You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). -Due to breaking changes in Laravel 11, SDK 7.12 was the last version to support Laravel 9 and 10. +### Supported Laravel Releases -You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). +The next major release of Laravel is forecasted for Q1 2025. We anticipate supporting it upon release. + +| Laravel | SDK | PHP | Supported Until | +| ---------------------------------------------- | ----- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| [11.x](https://laravel.com/docs/11.x/releases) | 7.13+ | [8.3](https://www.php.net/releases/8.3/en.php) | Approx. [March 2026](https://laravel.com/docs/11.x/releases#support-policy) (EOL for Laravel 11) | +| | | [8.2](https://www.php.net/releases/8.2/en.php) | Approx. [Dec 2025](https://www.php.net/supported-versions.php) (EOL for PHP 8.2) | + +We strive to support all actively maintained Laravel releases, prioritizing support for the latest major version with our SDK. If a new Laravel major introduces breaking changes, we may have to end support for past Laravel versions earlier than planned. + +Affected Laravel versions will still receive security fixes until their end-of-life date, as announced in our release notes. + +### Maintenance Releases + +The following releases are no longer being updated with new features by Auth0, but will continue to receive security updates through their end-of-life date. + +| Laravel | SDK | PHP | Security Fixes Until | +| ---------------------------------------------- | ---------- | ---------------------------------------------- | -------------------------------------------------------------------------------------- | +| [10.x](https://laravel.com/docs/10.x/releases) | 7.5 - 7.12 | [8.3](https://www.php.net/releases/8.3/en.php) | [Feb 2025](https://laravel.com/docs/10.x/releases#support-policy) (EOL for Laravel 10) | +| | | [8.2](https://www.php.net/releases/8.2/en.php) | [Feb 2025](https://laravel.com/docs/10.x/releases#support-policy) (EOL for Laravel 10) | +| | | [8.1](https://www.php.net/releases/8.2/en.php) | [Nov 2024](https://www.php.net/supported-versions.php) (EOL for PHP 8.1) | + +### Unsupported Releases + +The following releases are unsupported by Auth0. While they may be suitable for some legacy applications, your mileage may vary. We recommend upgrading to a supported version as soon as possible. + +| Laravel | SDK | +| -------------------------------------------- | ---------- | +| [9.x](https://laravel.com/docs/9.x/releases) | 7.0 - 7.12 | +| [8.x](https://laravel.com/docs/8.x/releases) | 7.0 - 7.4 | +| [7.x](https://laravel.com/docs/7.x/releases) | 5.4 - 6.5 | +| [6.x](https://laravel.com/docs/6.x/releases) | 5.3 - 6.5 | +| [5.x](https://laravel.com/docs/5.x/releases) | 2.0 - 6.1 | +| [4.x](https://laravel.com/docs/4.x/releases) | 1.x | ## Getting Started diff --git a/docs/Installation.md b/docs/Installation.md index 7b537ed9..15808f5e 100644 --- a/docs/Installation.md +++ b/docs/Installation.md @@ -14,16 +14,7 @@ ## Prerequisites -Your application must use the [latest supported Laravel version](https://endoflife.date/laravel), and your host environment must be running a [supported PHP version](https://www.php.net/supported-versions.php). Please review [our support policy](./docs/Support.md) for more information. - -| SDK | Laravel | PHP | Supported Until | -| ----- | ---------------------------------------------- | ---------------------------------------------- | --------------- | -| 7.13+ | [11.x](https://laravel.com/docs/11.x/releases) | [8.3](https://www.php.net/releases/8.3/en.php) | ~Sep 2025 | -| | | [8.2](https://www.php.net/releases/8.2/en.php) | ~Sep 2025 | - -Due to breaking changes in Laravel 11, SDK 7.12 was the last version to support Laravel 9 and 10. - -You will also need [Composer 2.0+](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). +Your application must use the [latest supported Laravel version](https://endoflife.date/laravel), and your host environment must be running a [supported PHP version](https://www.php.net/supported-versions.php). Please review [our support policy](./docs/Support.md) for more information. You will also need [Composer 2.0+](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). ## Install the SDK diff --git a/docs/Support.md b/docs/Support.md index 97352be1..7a1251b7 100644 --- a/docs/Support.md +++ b/docs/Support.md @@ -1,15 +1,44 @@ # Support -To integrate our SDK, your application must use the [latest supported Laravel version](https://endoflife.date/laravel), and your environment must run a [supported PHP version](https://www.php.net/supported-versions.php). We do not support versions of either that are no longer supported by their maintainers. +Your application must use a [supported Laravel version](#supported-laravel-releases), and your host environment must be running a [maintained PHP version](https://www.php.net/supported-versions.php). -| SDK | Laravel | PHP | Supported Until | -| ----- | ---------------------------------------------- | ---------------------------------------------- | --------------- | -| 7.13+ | [11.x](https://laravel.com/docs/11.x/releases) | [8.3](https://www.php.net/releases/8.3/en.php) | ~Sep 2025 | -| | | [8.2](https://www.php.net/releases/8.2/en.php) | ~Sep 2025 | +You will also need [Composer](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). -Due to breaking changes in Laravel 11, SDK 7.12 was the last version to support Laravel 9 and 10. +### Supported Laravel Releases -You will also need [Composer 2.0+](https://getcomposer.org/) and an [Auth0 account](https://auth0.com/signup). +The next major release of Laravel is forecasted for Q1 2025. We anticipate supporting it upon release. + +| Laravel | SDK | PHP | Supported Until | +| ---------------------------------------------- | ----- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| [11.x](https://laravel.com/docs/11.x/releases) | 7.13+ | [8.3](https://www.php.net/releases/8.3/en.php) | Approx. [March 2026](https://laravel.com/docs/11.x/releases#support-policy) (EOL for Laravel 11) | +| | | [8.2](https://www.php.net/releases/8.2/en.php) | Approx. [Dec 2025](https://www.php.net/supported-versions.php) (EOL for PHP 8.2) | + +We strive to support all actively maintained Laravel releases, prioritizing support for the latest major version with our SDK. If a new Laravel major introduces breaking changes, we may have to end support for past Laravel versions earlier than planned. + +Affected Laravel versions will still receive security fixes until their end-of-life date, as announced in our release notes. + +### Maintenance Releases + +The following releases are no longer being updated with new features by Auth0, but will continue to receive security updates through their end-of-life date. + +| Laravel | SDK | PHP | Security Fixes Until | +| ---------------------------------------------- | ---------- | ---------------------------------------------- | -------------------------------------------------------------------------------------- | +| [10.x](https://laravel.com/docs/10.x/releases) | 7.5 - 7.12 | [8.3](https://www.php.net/releases/8.3/en.php) | [Feb 2025](https://laravel.com/docs/10.x/releases#support-policy) (EOL for Laravel 10) | +| | | [8.2](https://www.php.net/releases/8.2/en.php) | [Feb 2025](https://laravel.com/docs/10.x/releases#support-policy) (EOL for Laravel 10) | +| | | [8.1](https://www.php.net/releases/8.2/en.php) | [Nov 2024](https://www.php.net/supported-versions.php) (EOL for PHP 8.1) | + +### Unsupported Releases + +The following releases are unsupported by Auth0. While they may be suitable for some legacy applications, your mileage may vary. We recommend upgrading to a supported version as soon as possible. + +| Laravel | SDK | +| -------------------------------------------- | ---------- | +| [9.x](https://laravel.com/docs/9.x/releases) | 7.0 - 7.12 | +| [8.x](https://laravel.com/docs/8.x/releases) | 7.0 - 7.4 | +| [7.x](https://laravel.com/docs/7.x/releases) | 5.4 - 6.5 | +| [6.x](https://laravel.com/docs/6.x/releases) | 5.3 - 6.5 | +| [5.x](https://laravel.com/docs/5.x/releases) | 2.0 - 6.1 | +| [4.x](https://laravel.com/docs/4.x/releases) | 1.x | ## Support Policy From 09f993cd8817ba89f0a1b561fa18017424febc49 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 1 Apr 2024 13:46:03 -0500 Subject: [PATCH 508/525] chore(deps): use `orchestra/testbench@^9` instead of `^9.x-dev` --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 11743f2b..471d32e3 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,7 @@ "friendsofphp/php-cs-fixer": "^3", "larastan/larastan": "^2", "mockery/mockery": "^1", - "orchestra/testbench": "^9.x-dev", + "orchestra/testbench": "^9", "pestphp/pest": "^2", "pestphp/pest-plugin-laravel": "^2", "phpstan/phpstan": "^1", @@ -112,9 +112,9 @@ } }, "scripts": { - "pest": "@php vendor/bin/pest --order-by random --fail-on-risky --parallel --no-progress", - "pest:coverage": "@php vendor/bin/pest --order-by random --fail-on-risky --coverage --parallel --no-progress", - "pest:debug": "@php vendor/bin/pest --log-events-verbose-text pest.log --display-errors --fail-on-risky --no-progress", + "pest": "@php vendor/bin/pest --order-by random --fail-on-risky --parallel", + "pest:coverage": "@php vendor/bin/pest --order-by random --fail-on-risky --coverage --parallel", + "pest:debug": "@php vendor/bin/pest --log-events-verbose-text pest.log --display-errors --fail-on-risky", "pest:profile": "@php vendor/bin/pest --profile", "phpcs": "@php vendor/bin/php-cs-fixer fix --dry-run --diff", "phpcs:fix": "@php vendor/bin/php-cs-fixer fix", From 908ff13b7f13b62510a09f40399b69ff301f03d8 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 1 Apr 2024 23:40:22 -0500 Subject: [PATCH 509/525] Release 7.14.0 (#450) --- .version | 2 +- CHANGELOG.md | 9 ++++++++- src/ServiceAbstract.php | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.version b/.version index eb1dc6a5..e465da43 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -7.13.0 +7.14.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index eda944c4..ca696394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,11 @@ -# Changelog +# Change Log + +## [7.14.0](https://github.com/auth0/laravel-auth0/tree/7.14.0) (2024-04-01) +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.13.0...7.14.0) + +**Changed** +- refactor: add additional Telescope state check [\#447](https://github.com/auth0/laravel-auth0/pull/447) ([samuelhgf](https://github.com/samuelhgf)) +- chore(deps): replace temporary `psalm-laravel-plugin` fork with official [\#448](https://github.com/auth0/laravel-auth0/pull/448) ([alies-dev](https://github.com/alies-dev)) ## [7.13.0](https://github.com/auth0/laravel-auth0/tree/7.12.0) (2024-03-11) diff --git a/src/ServiceAbstract.php b/src/ServiceAbstract.php index 43e8e53f..3d262055 100644 --- a/src/ServiceAbstract.php +++ b/src/ServiceAbstract.php @@ -22,7 +22,7 @@ abstract class ServiceAbstract extends InstanceEntityAbstract * * @var string */ - public const VERSION = '7.13.0'; + public const VERSION = '7.14.0'; /** * Decode a PSR-7 HTTP Response Message containing a JSON content body to a PHP array. Returns null if the response was not successful, or the response body was not JSON. From b4d099abcf826d26f836303e5a68e7fdc474e3d3 Mon Sep 17 00:00:00 2001 From: Russ Date: Mon, 3 Jun 2024 23:30:38 -0400 Subject: [PATCH 510/525] perf: Update getCredential to only refresh credential once per request (#453) * Update getCredential to only refresh creds once per request Signed-off-by: Russ * Update PHP syntax to fix phpstan, psalm, phpcs, and rector tests * Implement initial thumbprint logic in getCredential * Make thumbprinting more performant by using sdk->getCredentials instead of this->findSession --------- Signed-off-by: Russ Co-authored-by: Russell Kenny --- src/Guards/AuthenticationGuard.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Guards/AuthenticationGuard.php b/src/Guards/AuthenticationGuard.php index 23f8c7a6..e3cc4ff2 100644 --- a/src/Guards/AuthenticationGuard.php +++ b/src/Guards/AuthenticationGuard.php @@ -32,6 +32,8 @@ final class AuthenticationGuard extends GuardAbstract implements AuthenticationG */ protected const TELESCOPE = '\Laravel\Telescope\Telescope'; + private ?string $credThumbprint = null; + public function find(): ?CredentialEntityContract { if ($this->isImpersonating()) { @@ -93,9 +95,13 @@ public function getCredential(): ?CredentialEntityContract } if ($this->credential instanceof CredentialEntityContract) { - $updated = $this->findSession(); - $this->setCredential($updated); - $this->pushState($updated); + $currThumbprint = $this->getCredThumbprint($this->sdk()->getCredentials()); + if ($currThumbprint !== $this->credThumbprint) { + $updated = $this->findSession(); + $this->setCredential($updated); + $this->pushState($updated); + $this->credThumbprint = $currThumbprint; + } } return $this->credential; @@ -331,6 +337,15 @@ public function user(): ?Authenticatable return $lastResponse = null; } + private function getCredThumbprint(?object $credential): null | string + { + if (null === $credential) { + return null; + } + + return md5(serialize($credential)); + } + private function pullState(): ?CredentialEntityContract { $sdk = $this->sdk(); From 57b4aeb45cef57af66232b27cc1eb9c4ecf935b0 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 3 Jun 2024 22:41:21 -0500 Subject: [PATCH 511/525] Release 7.15.0 --- .version | 2 +- CHANGELOG.md | 19 ++++++++++++++++++- src/ServiceAbstract.php | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/.version b/.version index eb1dc6a5..368fd8fd 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -7.13.0 +7.15.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index eda944c4..24cf229a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,23 @@ # Changelog -## [7.13.0](https://github.com/auth0/laravel-auth0/tree/7.12.0) (2024-03-11) +## [7.15.0](https://github.com/auth0/laravel-auth0/tree/7.15.0) (2024-06-03) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.14.0...7.15.0) + +**Changed** + +- perf: Update getCredential to only refresh credential once per request [\#453](https://github.com/auth0/laravel-auth0/pull/453) ([ComputerTinker](https://github.com/ComputerTinker)) + +## [7.14.0](https://github.com/auth0/laravel-auth0/tree/7.14.0) (2024-04-01) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.13.0...7.14.0) + +**Changed** + +- refactor: add additional Telescope state check #447 (samuelhgf) +- chore(deps): replace temporary psalm-laravel-plugin fork with official #448 (alies-dev) + +## [7.13.0](https://github.com/auth0/laravel-auth0/tree/7.13.0) (2024-03-11) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.12.0...7.13.0) diff --git a/src/ServiceAbstract.php b/src/ServiceAbstract.php index 43e8e53f..dae4a90e 100644 --- a/src/ServiceAbstract.php +++ b/src/ServiceAbstract.php @@ -22,7 +22,7 @@ abstract class ServiceAbstract extends InstanceEntityAbstract * * @var string */ - public const VERSION = '7.13.0'; + public const VERSION = '7.15.0'; /** * Decode a PSR-7 HTTP Response Message containing a JSON content body to a PHP array. Returns null if the response was not successful, or the response body was not JSON. From c50c6cb6d1c48998ae7fef2f44b5528ba7e7775d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 3 Jun 2024 22:42:48 -0500 Subject: [PATCH 512/525] Release 7.15.0 --- CHANGELOG.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3c6cdaf..56ad8c72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,5 @@ # Change Log -## [7.14.0](https://github.com/auth0/laravel-auth0/tree/7.14.0) (2024-04-01) -[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.13.0...7.14.0) - -**Changed** -- refactor: add additional Telescope state check [\#447](https://github.com/auth0/laravel-auth0/pull/447) ([samuelhgf](https://github.com/samuelhgf)) -- chore(deps): replace temporary `psalm-laravel-plugin` fork with official [\#448](https://github.com/auth0/laravel-auth0/pull/448) ([alies-dev](https://github.com/alies-dev)) - ## [7.15.0](https://github.com/auth0/laravel-auth0/tree/7.15.0) (2024-06-03) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.14.0...7.15.0) @@ -21,8 +14,8 @@ **Changed** -- refactor: add additional Telescope state check #447 (samuelhgf) -- chore(deps): replace temporary psalm-laravel-plugin fork with official #448 (alies-dev) +- refactor: add additional Telescope state check [\#447](https://github.com/auth0/laravel-auth0/pull/447) ([samuelhgf](https://github.com/samuelhgf)) +- chore(deps): replace temporary `psalm-laravel-plugin` fork with official [\#448](https://github.com/auth0/laravel-auth0/pull/448) ([alies-dev](https://github.com/alies-dev)) ## [7.13.0](https://github.com/auth0/laravel-auth0/tree/7.13.0) (2024-03-11) From 522eb5f77d4560fe65c798c892178c8e95617466 Mon Sep 17 00:00:00 2001 From: Steven Wong Date: Thu, 25 Jul 2024 22:25:16 +0800 Subject: [PATCH 513/525] Update codeowner file with new GitHub team name --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 60f116c0..7958e8bd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @auth0/dx-sdks-engineer +* @auth0/project-dx-sdks-engineer-codeowner From a69509ed0a047d19d2793337a7b8bb30b7c4aa27 Mon Sep 17 00:00:00 2001 From: Arpit Jain <167312832+arpit-jn@users.noreply.github.com> Date: Mon, 9 Sep 2024 13:19:39 +0530 Subject: [PATCH 514/525] Changed pull_request_target to pull_request (#462) --- .github/workflows/semgrep.yml | 11 +---------- .github/workflows/snyk.yml | 10 +--------- .github/workflows/tests.yml | 10 +--------- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index e53b2034..514ae7db 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -2,7 +2,7 @@ name: Semgrep on: merge_group: - pull_request_target: + pull_request: types: - opened - synchronize @@ -20,16 +20,7 @@ concurrency: cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} jobs: - authorize: - name: Authorize - environment: ${{ github.actor != 'dependabot[bot]' && github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository && 'external' || 'internal' }} - runs-on: ubuntu-latest - steps: - - run: true - check: - needs: authorize - name: Check for Vulnerabilities runs-on: ubuntu-latest diff --git a/.github/workflows/snyk.yml b/.github/workflows/snyk.yml index 516645a8..eebccb46 100644 --- a/.github/workflows/snyk.yml +++ b/.github/workflows/snyk.yml @@ -2,7 +2,7 @@ name: Snyk on: merge_group: - pull_request_target: + pull_request: types: - opened - synchronize @@ -26,16 +26,8 @@ concurrency: cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} jobs: - authorize: - name: Authorize - environment: ${{ github.actor != 'dependabot[bot]' && github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository && 'external' || 'internal' }} - runs-on: ubuntu-latest - steps: - - run: true - configure: name: Configure - needs: [authorize] runs-on: ubuntu-latest outputs: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f34167be..eef53486 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -3,7 +3,7 @@ name: Build and Test on: merge_group: workflow_dispatch: - pull_request_target: + pull_request: types: - opened - synchronize @@ -18,16 +18,8 @@ concurrency: cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} jobs: - authorize: - name: Authorize - environment: ${{ github.actor != 'dependabot[bot]' && github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository && 'external' || 'internal' }} - runs-on: ubuntu-latest - steps: - - run: true - configure: name: Configure - needs: [authorize] runs-on: ubuntu-latest outputs: From 890ef8cdd2838eadc4f724decb166ad797b06138 Mon Sep 17 00:00:00 2001 From: Snehil Kishore Date: Thu, 31 Oct 2024 13:36:56 +0530 Subject: [PATCH 515/525] Adding Reversing Labs Scanner (#464) * Adding Reversing Labs Scanner * Changing the PHP Version to 8.2 * Adding Laravel Specific Build Files * New Changes To RL-Workflow * Added the need flag for release job * Testing Changes and get-version file changes * Reverting Testing Changes * Fixing PHP Stan and Rector Test Failures --- .github/actions/get-version/action.yml | 4 +- .github/actions/rl-scanner/action.yml | 71 +++++++++++++++++++ .github/workflows/release.yml | 17 +++++ .github/workflows/rl-scanner.yml | 68 ++++++++++++++++++ phpstan.neon.dist | 1 + rector.php | 16 ++--- .../CallbackControllerAbstract.php | 1 + src/Controllers/LoginControllerAbstract.php | 2 + src/Controllers/LogoutControllerAbstract.php | 2 + src/Guards/GuardAbstract.php | 1 + src/UserProviderAbstract.php | 1 + 11 files changed, 173 insertions(+), 11 deletions(-) create mode 100644 .github/actions/rl-scanner/action.yml create mode 100644 .github/workflows/rl-scanner.yml diff --git a/.github/actions/get-version/action.yml b/.github/actions/get-version/action.yml index 387fdba6..4dafb528 100644 --- a/.github/actions/get-version/action.yml +++ b/.github/actions/get-version/action.yml @@ -17,7 +17,5 @@ runs: - id: get_version shell: bash run: | - VERSION=$(echo ${BRANCH_NAME} | sed -r 's#release/+##g') + VERSION=$(head -1 .version) echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT - env: - BRANCH_NAME: ${{ github.event.pull_request.head.ref }} diff --git a/.github/actions/rl-scanner/action.yml b/.github/actions/rl-scanner/action.yml new file mode 100644 index 00000000..b3df2d95 --- /dev/null +++ b/.github/actions/rl-scanner/action.yml @@ -0,0 +1,71 @@ +name: 'Reversing Labs Scanner' +description: 'Runs the Reversing Labs scanner on a specified artifact.' +inputs: + artifact-path: + description: 'Path to the artifact to be scanned.' + required: true + version: + description: 'Version of the artifact.' + required: true + +runs: + using: 'composite' + steps: + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Install Python dependencies + shell: bash + run: | + pip install boto3 requests + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + role-to-assume: ${{ env.PRODSEC_TOOLS_ARN }} + aws-region: us-east-1 + mask-aws-account-id: true + + - name: Install RL Wrapper + shell: bash + run: | + pip install rl-wrapper>=1.0.0 --index-url "https://$%7B%7B%20env.PRODSEC_TOOLS_USER%20%7D%7D:$%7B%7B%20env.PRODSEC_TOOLS_TOKEN%20%7D%7D@a0us.jfrog.io/artifactory/api/pypi/python-local/simple" + + - name: Run RL Scanner + shell: bash + env: + RLSECURE_LICENSE: ${{ env.RLSECURE_LICENSE }} + RLSECURE_SITE_KEY: ${{ env.RLSECURE_SITE_KEY }} + SIGNAL_HANDLER_TOKEN: ${{ env.SIGNAL_HANDLER_TOKEN }} + PYTHONUNBUFFERED: 1 + run: | + if [ ! -f "${{ inputs.artifact-path }}" ]; then + echo "Artifact not found: ${{ inputs.artifact-path }}" + exit 1 + fi + + rl-wrapper \ + --artifact "${{ inputs.artifact-path }}" \ + --name "${{ github.event.repository.name }}" \ + --version "${{ inputs.version }}" \ + --repository "${{ github.repository }}" \ + --commit "${{ github.sha }}" \ + --build-env "github_actions" \ + --suppress_output + + # Check the outcome of the scanner + if [ $? -ne 0 ]; then + echo "RL Scanner failed." + echo "scan-status=failed" >> $GITHUB_ENV + exit 1 + else + echo "RL Scanner passed." + echo "scan-status=success" >> $GITHUB_ENV + fi + +outputs: + scan-status: + description: 'The outcome of the scan process.' + value: ${{ env.scan-status }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7aa14e53..a6e34617 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,15 +5,32 @@ on: types: - closed + + permissions: contents: write + id-token: write # This is required for requesting the JWT ### TODO: Replace instances of './.github/actions/' w/ `auth0/dx-sdk-actions/` and append `@latest` after the common `dx-sdk-actions` repo is made public. ### TODO: Also remove `get-prerelease`, `get-version`, `release-create`, `tag-create` and `tag-exists` actions from this repo's .github/actions folder once the repo is public. jobs: + rl-scanner: + uses: ./.github/workflows/rl-scanner.yml + with: + php-version: 8.2 + artifact-name: 'laravel-auth0.zip' + secrets: + RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }} + RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }} + SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }} + PRODSEC_TOOLS_USER: ${{ secrets.PRODSEC_TOOLS_USER }} + PRODSEC_TOOLS_TOKEN: ${{ secrets.PRODSEC_TOOLS_TOKEN }} + PRODSEC_TOOLS_ARN: ${{ secrets.PRODSEC_TOOLS_ARN }} + release: if: github.event.pull_request.merged && startsWith(github.event.pull_request.head.ref, 'release/') + needs: rl-scanner runs-on: ubuntu-latest steps: diff --git a/.github/workflows/rl-scanner.yml b/.github/workflows/rl-scanner.yml new file mode 100644 index 00000000..0a27d209 --- /dev/null +++ b/.github/workflows/rl-scanner.yml @@ -0,0 +1,68 @@ +name: RL-Secure Workflow + +on: + workflow_call: + inputs: + php-version: + required: true + type: string + artifact-name: + required: true + type: string + secrets: + RLSECURE_LICENSE: + required: true + RLSECURE_SITE_KEY: + required: true + SIGNAL_HANDLER_TOKEN: + required: true + PRODSEC_TOOLS_USER: + required: true + PRODSEC_TOOLS_TOKEN: + required: true + PRODSEC_TOOLS_ARN: + required: true + +jobs: + rl-scanner: + if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.merged && startsWith(github.event.pull_request.head.ref, 'release/')) + runs-on: ubuntu-latest + outputs: + scan-status: ${{ steps.rl-scan-conclusion.outcome }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha || github.ref }} + + - name: Setup PHP + uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # pin@2.25.4 + with: + php-version: ${{ inputs.php-version }} + + - name: Build Laravel + shell: bash + run: | + zip -r ${{ inputs.artifact-name }} ./* + + - name: Get Artifact Version + id: get_version + uses: ./.github/actions/get-version + + - name: Run RL Scanner + id: rl-scan-conclusion + uses: ./.github/actions/rl-scanner + with: + artifact-path: "$(pwd)/${{ inputs.artifact-name }}" + version: "${{ steps.get_version.outputs.version }}" + env: + RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }} + RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }} + SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }} + PRODSEC_TOOLS_USER: ${{ secrets.PRODSEC_TOOLS_USER }} + PRODSEC_TOOLS_TOKEN: ${{ secrets.PRODSEC_TOOLS_TOKEN }} + PRODSEC_TOOLS_ARN: ${{ secrets.PRODSEC_TOOLS_ARN }} + + - name: Output scan result + run: echo "scan-status=${{ steps.rl-scan-conclusion.outcome }}" >> $GITHUB_ENV \ No newline at end of file diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 4b604cc9..c332cb11 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -13,6 +13,7 @@ parameters: - '#Constructor of class (.*) has an unused parameter (.*).#' - '#Method (.*) has parameter (.*) with no value type specified in iterable type array.#' - '#no value type specified in iterable type array.#' + - '#Dynamic call to static method (.*).#' reportUnmatchedIgnoredErrors: false treatPhpDocTypesAsCertain: false diff --git a/rector.php b/rector.php index 0ce41546..a0fee449 100644 --- a/rector.php +++ b/rector.php @@ -339,8 +339,8 @@ // ArrayShapeFromConstantArrayReturnRector::class, // BinarySwitchToIfElseRector::class, BooleanNotIdenticalToNotIdenticalRector::class, - BoolvalToTypeCastRector::class, - CallableThisArrayToAnonymousFunctionRector::class, + //BoolvalToTypeCastRector::class, + //CallableThisArrayToAnonymousFunctionRector::class, CallUserFuncArrayToVariadicRector::class, CallUserFuncToMethodCallRector::class, CallUserFuncWithArrowFunctionToInlineRector::class, @@ -373,19 +373,19 @@ // FinalizeClassesWithoutChildrenRector::class, FinalPrivateToPrivateVisibilityRector::class, FlipTypeControlToUseExclusiveTypeRector::class, - FloatvalToTypeCastRector::class, + //FloatvalToTypeCastRector::class, ForeachItemsAssignToEmptyArrayToAssignRector::class, ForeachToInArrayRector::class, ForRepeatedCountToOwnVariableRector::class, // ForToForeachRector::class, FuncGetArgsToVariadicParamRector::class, - GetClassToInstanceOfRector::class, + //GetClassToInstanceOfRector::class, GetDebugTypeRector::class, InlineArrayReturnAssignRector::class, InlineConstructorDefaultToPropertyRector::class, InlineIfToExplicitIfRector::class, InlineIsAInstanceOfRector::class, - IntvalToTypeCastRector::class, + //IntvalToTypeCastRector::class, IsAWithStringWithThirdArgumentRector::class, IssetOnPropertyObjectToPropertyExistsRector::class, JoinStringConcatRector::class, @@ -459,7 +459,7 @@ ReturnNeverTypeRector::class, ReturnTypeFromReturnDirectArrayRector::class, ReturnTypeFromReturnNewRector::class, - ReturnTypeFromStrictBoolReturnExprRector::class, + //ReturnTypeFromStrictBoolReturnExprRector::class, ReturnTypeFromStrictConstantReturnRector::class, ReturnTypeFromStrictNativeCallRector::class, ReturnTypeFromStrictNewArrayRector::class, @@ -507,7 +507,7 @@ StringableForToStringRector::class, StrlenZeroToIdenticalEmptyStringRector::class, StrStartsWithRector::class, - StrvalToTypeCastRector::class, + //StrvalToTypeCastRector::class, SwitchNegatedTernaryRector::class, SymplifyQuoteEscapeRector::class, TernaryConditionVariableAssignmentRector::class, @@ -527,7 +527,7 @@ UnwrapSprintfOneArgumentRector::class, UseClassKeywordForClassNameResolutionRector::class, UseIdenticalOverEqualWithSameTypeRector::class, - UseIncrementAssignRector::class, + //UseIncrementAssignRector::class, // VarAnnotationIncorrectNullableRector::class, // VarConstantCommentRector::class, VarToPublicPropertyRector::class, diff --git a/src/Controllers/CallbackControllerAbstract.php b/src/Controllers/CallbackControllerAbstract.php index bd9a4618..82a43402 100644 --- a/src/Controllers/CallbackControllerAbstract.php +++ b/src/Controllers/CallbackControllerAbstract.php @@ -18,6 +18,7 @@ use Throwable; use function is_string; +use function sprintf; /** * @api diff --git a/src/Controllers/LoginControllerAbstract.php b/src/Controllers/LoginControllerAbstract.php index 7c558d2e..83343e27 100644 --- a/src/Controllers/LoginControllerAbstract.php +++ b/src/Controllers/LoginControllerAbstract.php @@ -13,6 +13,8 @@ use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; +use function sprintf; + /** * Controller for handling a login request. * diff --git a/src/Controllers/LogoutControllerAbstract.php b/src/Controllers/LogoutControllerAbstract.php index c5d81f66..62cf1b3e 100644 --- a/src/Controllers/LogoutControllerAbstract.php +++ b/src/Controllers/LogoutControllerAbstract.php @@ -12,6 +12,8 @@ use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; +use function sprintf; + /** * Controller for handling a logout request. * diff --git a/src/Guards/GuardAbstract.php b/src/Guards/GuardAbstract.php index f5cf935b..175c149a 100644 --- a/src/Guards/GuardAbstract.php +++ b/src/Guards/GuardAbstract.php @@ -22,6 +22,7 @@ use function is_array; use function is_int; use function is_string; +use function sprintf; /** * @internal diff --git a/src/UserProviderAbstract.php b/src/UserProviderAbstract.php index 6b3b0dbd..2d6f2232 100644 --- a/src/UserProviderAbstract.php +++ b/src/UserProviderAbstract.php @@ -10,6 +10,7 @@ use Illuminate\Support\Facades\Cache; use function is_string; +use function sprintf; /** * User provider for the Auth0 user repository. From 891e2298a9f0454fd216f72973f2930ca7b5d379 Mon Sep 17 00:00:00 2001 From: Kyle Murphy Date: Thu, 20 Mar 2025 16:55:22 +1100 Subject: [PATCH 516/525] refactor: fix failing tests (#471) Add type hinting Add missing spatie/laravel-ray as dev dependency --- composer.json | 1 + src/Bridges/SessionBridgeAbstract.php | 7 +++++++ src/EventsContract.php | 26 +++++++++++++------------- src/Guards/AuthorizationGuard.php | 7 ++++++- src/Guards/GuardAbstract.php | 13 ++++++++++++- src/UserProviderAbstract.php | 7 ++++++- 6 files changed, 45 insertions(+), 16 deletions(-) diff --git a/composer.json b/composer.json index 471d32e3..ea48fefc 100644 --- a/composer.json +++ b/composer.json @@ -57,6 +57,7 @@ "psalm/plugin-laravel": "^2.10", "psr-mock/http": "^1", "rector/rector": "^1", + "spatie/laravel-ray": "^1.40", "squizlabs/php_codesniffer": "^3", "symfony/cache": "^6 || ^7", "vimeo/psalm": "^5", diff --git a/src/Bridges/SessionBridgeAbstract.php b/src/Bridges/SessionBridgeAbstract.php index 0403f558..3121e814 100644 --- a/src/Bridges/SessionBridgeAbstract.php +++ b/src/Bridges/SessionBridgeAbstract.php @@ -5,6 +5,7 @@ namespace Auth0\Laravel\Bridges; use Auth0\Laravel\Exceptions\SessionException; +use Illuminate\Http\Request; use Illuminate\Session\Store; use InvalidArgumentException; @@ -155,7 +156,13 @@ protected function getPayload(): ?array */ protected function getStore(): Store { + /** + * @var Store $store + */ $store = app('session.store'); + /** + * @var Request $request + */ $request = app('request'); if (! $request->hasSession(true)) { diff --git a/src/EventsContract.php b/src/EventsContract.php index 5ad8b9c9..8cc0c1d8 100644 --- a/src/EventsContract.php +++ b/src/EventsContract.php @@ -34,67 +34,67 @@ interface EventsContract { /** - * @var class-string<\Auth0\Laravel\Events\AuthenticationFailed> + * @var class-string */ public const AUTHENTICATION_FAILED = AuthenticationFailed::class; /** - * @var class-string<\Auth0\Laravel\Events\AuthenticationSucceeded> + * @var class-string */ public const AUTHENTICATION_SUCCEEDED = AuthenticationSucceeded::class; /** - * @var class-string<\Auth0\Laravel\Events\Configuration\BuildingConfigurationEvent> + * @var class-string */ public const CONFIGURATION_BUILDING = BuildingConfigurationEvent::class; /** - * @var class-string<\Auth0\Laravel\Events\Configuration\BuiltConfigurationEvent> + * @var class-string */ public const CONFIGURATION_BUILT = BuiltConfigurationEvent::class; /** - * @var class-string<\Auth0\Laravel\Events\LoginAttempting> + * @var class-string */ public const LOGIN_ATTEMPTING = LoginAttempting::class; /** - * @var class-string<\Auth0\Laravel\Events\Middleware\StatefulMiddlewareRequest> + * @var class-string */ public const MIDDLEWARE_STATEFUL_REQUEST = StatefulMiddlewareRequest::class; /** - * @var class-string<\Auth0\Laravel\Events\Middleware\StatelessMiddlewareRequest> + * @var class-string */ public const MIDDLEWARE_STATELESS_REQUEST = StatelessMiddlewareRequest::class; /** - * @var class-string<\Auth0\Laravel\Events\TokenExpired> + * @var class-string */ public const TOKEN_EXPIRED = TokenExpired::class; /** - * @var class-string<\Auth0\Laravel\Events\TokenRefreshFailed> + * @var class-string */ public const TOKEN_REFRESH_FAILED = TokenRefreshFailed::class; /** - * @var class-string<\Auth0\Laravel\Events\TokenRefreshSucceeded> + * @var class-string */ public const TOKEN_REFRESH_SUCCEEDED = TokenRefreshSucceeded::class; /** - * @var class-string<\Auth0\Laravel\Events\TokenVerificationAttempting> + * @var class-string */ public const TOKEN_VERIFICATION_ATTEMPTING = TokenVerificationAttempting::class; /** - * @var class-string<\Auth0\Laravel\Events\TokenVerificationFailed> + * @var class-string */ public const TOKEN_VERIFICATION_FAILED = TokenVerificationFailed::class; /** - * @var class-string<\Auth0\Laravel\Events\TokenVerificationSucceeded> + * @var class-string */ public const TOKEN_VERIFICATION_SUCCEEDED = TokenVerificationSucceeded::class; diff --git a/src/Guards/AuthorizationGuard.php b/src/Guards/AuthorizationGuard.php index 0172038c..73bb1f1f 100644 --- a/src/Guards/AuthorizationGuard.php +++ b/src/Guards/AuthorizationGuard.php @@ -34,7 +34,12 @@ public function findToken(): ?CredentialEntityContract return $this->getImposter(); } - $token = trim(app('request')->bearerToken() ?? ''); + /** + * @var \Illuminate\Http\Request $request + */ + $request = app('request'); + + $token = trim($request->bearerToken() ?? ''); if ('' === $token) { return null; diff --git a/src/Guards/GuardAbstract.php b/src/Guards/GuardAbstract.php index 175c149a..9b125eac 100644 --- a/src/Guards/GuardAbstract.php +++ b/src/Guards/GuardAbstract.php @@ -92,7 +92,12 @@ final public function getProvider(): UserProvider } $providerName = trim($providerName); - $provider = app('auth')->createUserProvider($providerName); + + /** + * @var \Illuminate\Auth\AuthManager $auth + */ + $auth = app('auth'); + $provider = $auth->createUserProvider($providerName); if ($provider instanceof UserProvider) { $this->provider = $provider; @@ -115,7 +120,13 @@ final public function getRefreshedUser(): ?Authenticatable final public function getSession(): Session { if (! $this->session instanceof Session) { + /** + * @var \Illuminate\Session\Store $store + */ $store = app('session.store'); + /** + * @var \Illuminate\Http\Request $request + */ $request = app('request'); if (! $request->hasSession(true)) { diff --git a/src/UserProviderAbstract.php b/src/UserProviderAbstract.php index 2d6f2232..8ef5d99a 100644 --- a/src/UserProviderAbstract.php +++ b/src/UserProviderAbstract.php @@ -222,7 +222,12 @@ protected function resolveRepository( $this->setRepositoryName($model); - return $this->repository = app($model); + /** + * @var UserRepositoryContract $repository + */ + $repository = app($model); + + return $this->repository = $repository; } protected function setConfiguration( From 57df12ecf1195175efc1442b54d11147557cbbfc Mon Sep 17 00:00:00 2001 From: Danil Shutsky Date: Wed, 26 Mar 2025 16:54:12 +0100 Subject: [PATCH 517/525] Laravel 12 Support (#470) Rebase with sign --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index ea48fefc..5b30ff0f 100644 --- a/composer.json +++ b/composer.json @@ -38,9 +38,9 @@ "php": "^8.2", "ext-json": "*", "auth0/auth0-php": "^8.10", - "illuminate/contracts": "^11", - "illuminate/http": "^11", - "illuminate/support": "^11", + "illuminate/contracts": "^11 || ^12", + "illuminate/http": "^11 || ^12", + "illuminate/support": "^11 || ^12", "psr-discovery/all": "^1", "psr/cache": "^2 || ^3" }, From 3b24f36c6b935dd45ec88b8bb7ffb45136e55c39 Mon Sep 17 00:00:00 2001 From: Snehil Kishore Date: Tue, 8 Apr 2025 12:43:15 +0530 Subject: [PATCH 518/525] Release 7.16.0 (#472) * Release 7.16.0 * refactor : Fix PHP CS Fixer * refactor: Fix PHP CS Fixer * Version File Changes --- .version | 2 +- CHANGELOG.md | 12 +++++++++ README.md | 27 ++++++++++--------- .../CallbackControllerAbstract.php | 2 +- src/Controllers/LoginControllerAbstract.php | 2 +- src/Entities/InstanceEntityAbstract.php | 2 +- src/Events.php | 20 +++++++------- src/EventsContract.php | 24 ++++++++--------- 8 files changed, 52 insertions(+), 39 deletions(-) diff --git a/.version b/.version index 368fd8fd..971ecb25 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -7.15.0 +7.16.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 56ad8c72..e7d5d12e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Change Log +## [7.16.0](https://github.com/auth0/laravel-auth0/tree/7.16.0) (2025-04-06) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.15.0...7.16.0) + +**Added** + +- Laravel 12 Support [\#470](https://github.com/auth0/laravel-auth0/pull/470) ([lee-to](https://github.com/lee-to)) + +**Fixed** + +- refactor: fix failing tests [\#471](https://github.com/auth0/laravel-auth0/pull/471) ([noevidenz](https://github.com/noevidenz)) + ## [7.15.0](https://github.com/auth0/laravel-auth0/tree/7.15.0) (2024-06-03) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.14.0...7.15.0) diff --git a/README.md b/README.md index c25f3bc1..a39eb305 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,8 @@ The next major release of Laravel is forecasted for Q1 2025. We anticipate suppo | Laravel | SDK | PHP | Supported Until | | ---------------------------------------------- | ----- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------ | -| [11.x](https://laravel.com/docs/11.x/releases) | 7.13+ | [8.3](https://www.php.net/releases/8.3/en.php) | Approx. [March 2026](https://laravel.com/docs/11.x/releases#support-policy) (EOL for Laravel 11) | -| | | [8.2](https://www.php.net/releases/8.2/en.php) | Approx. [Dec 2025](https://www.php.net/supported-versions.php) (EOL for PHP 8.2) | +| [12.x](https://laravel.com/docs/11.x/releases) | 7.15+ | [8.4](https://www.php.net/releases/8.4/en.php) | Approx. [Feb 2027](https://laravel.com/docs/12.x/releases#support-policy) (EOL for Laravel 12) | +| | | [8.2](https://www.php.net/releases/8.3/en.php) | Approx. [Dec 2025](https://www.php.net/supported-versions.php) (EOL for PHP 8.3) | We strive to support all actively maintained Laravel releases, prioritizing support for the latest major version with our SDK. If a new Laravel major introduces breaking changes, we may have to end support for past Laravel versions earlier than planned. @@ -49,22 +49,23 @@ The following releases are no longer being updated with new features by Auth0, b | Laravel | SDK | PHP | Security Fixes Until | | ---------------------------------------------- | ---------- | ---------------------------------------------- | -------------------------------------------------------------------------------------- | -| [10.x](https://laravel.com/docs/10.x/releases) | 7.5 - 7.12 | [8.3](https://www.php.net/releases/8.3/en.php) | [Feb 2025](https://laravel.com/docs/10.x/releases#support-policy) (EOL for Laravel 10) | -| | | [8.2](https://www.php.net/releases/8.2/en.php) | [Feb 2025](https://laravel.com/docs/10.x/releases#support-policy) (EOL for Laravel 10) | -| | | [8.1](https://www.php.net/releases/8.2/en.php) | [Nov 2024](https://www.php.net/supported-versions.php) (EOL for PHP 8.1) | +| [11.x](https://laravel.com/docs/10.x/releases) | 7.13+ | [8.4](https://www.php.net/releases/8.4/en.php) | [March 2026](https://laravel.com/docs/11.x/releases#support-policy) (EOL for Laravel 11) | +| | | [8.3](https://www.php.net/releases/8.3/en.php) | [March 2026](https://laravel.com/docs/11.x/releases#support-policy) (EOL for Laravel 11) | +| | | [8.2](https://www.php.net/releases/8.2/en.php) | [Dec 2026](https://www.php.net/supported-versions.php) (EOL for PHP 8.2) | ### Unsupported Releases The following releases are unsupported by Auth0. While they may be suitable for some legacy applications, your mileage may vary. We recommend upgrading to a supported version as soon as possible. -| Laravel | SDK | -| -------------------------------------------- | ---------- | -| [9.x](https://laravel.com/docs/9.x/releases) | 7.0 - 7.12 | -| [8.x](https://laravel.com/docs/8.x/releases) | 7.0 - 7.4 | -| [7.x](https://laravel.com/docs/7.x/releases) | 5.4 - 6.5 | -| [6.x](https://laravel.com/docs/6.x/releases) | 5.3 - 6.5 | -| [5.x](https://laravel.com/docs/5.x/releases) | 2.0 - 6.1 | -| [4.x](https://laravel.com/docs/4.x/releases) | 1.x | +| Laravel | SDK | +| -------------------------------------------- | ---------- | +| [10.x](https://laravel.com/docs/10.x/releases)| 7.5 - 7.12 | +| [9.x](https://laravel.com/docs/9.x/releases) | 7.0 - 7.12 | +| [8.x](https://laravel.com/docs/8.x/releases) | 7.0 - 7.4 | +| [7.x](https://laravel.com/docs/7.x/releases) | 5.4 - 6.5 | +| [6.x](https://laravel.com/docs/6.x/releases) | 5.3 - 6.5 | +| [5.x](https://laravel.com/docs/5.x/releases) | 2.0 - 6.1 | +| [4.x](https://laravel.com/docs/4.x/releases) | 1.x | ## Getting Started diff --git a/src/Controllers/CallbackControllerAbstract.php b/src/Controllers/CallbackControllerAbstract.php index 82a43402..7ab3868a 100644 --- a/src/Controllers/CallbackControllerAbstract.php +++ b/src/Controllers/CallbackControllerAbstract.php @@ -5,12 +5,12 @@ namespace Auth0\Laravel\Controllers; use Auth0\Laravel\Auth\Guard; +use Auth0\Laravel\{Configuration, Events}; use Auth0\Laravel\Entities\CredentialEntityContract; use Auth0\Laravel\Events\{AuthenticationFailed, AuthenticationSucceeded}; use Auth0\Laravel\Exceptions\ControllerException; use Auth0\Laravel\Exceptions\Controllers\CallbackControllerException; use Auth0\Laravel\Guards\GuardAbstract; -use Auth0\Laravel\{Configuration, Events}; use Illuminate\Auth\Events\{Attempting, Authenticated, Failed, Validated}; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Http\Request; diff --git a/src/Controllers/LoginControllerAbstract.php b/src/Controllers/LoginControllerAbstract.php index 83343e27..6e4ff38a 100644 --- a/src/Controllers/LoginControllerAbstract.php +++ b/src/Controllers/LoginControllerAbstract.php @@ -5,11 +5,11 @@ namespace Auth0\Laravel\Controllers; use Auth0\Laravel\Auth\Guard; +use Auth0\Laravel\{Configuration, Events}; use Auth0\Laravel\Entities\CredentialEntityContract; use Auth0\Laravel\Events\LoginAttempting; use Auth0\Laravel\Exceptions\ControllerException; use Auth0\Laravel\Guards\GuardAbstract; -use Auth0\Laravel\{Configuration, Events}; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/src/Entities/InstanceEntityAbstract.php b/src/Entities/InstanceEntityAbstract.php index 36d2929f..2e230249 100644 --- a/src/Entities/InstanceEntityAbstract.php +++ b/src/Entities/InstanceEntityAbstract.php @@ -5,8 +5,8 @@ namespace Auth0\Laravel\Entities; use Auth0\Laravel\Bridges\{CacheBridge, SessionBridge}; -use Auth0\Laravel\Events\Configuration\{BuildingConfigurationEvent, BuiltConfigurationEvent}; use Auth0\Laravel\{Configuration, Events, Service}; +use Auth0\Laravel\Events\Configuration\{BuildingConfigurationEvent, BuiltConfigurationEvent}; use Auth0\SDK\Auth0; use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\SDK\Contract\API\ManagementInterface; diff --git a/src/Events.php b/src/Events.php index e558c5d6..04003c2f 100644 --- a/src/Events.php +++ b/src/Events.php @@ -4,16 +4,6 @@ namespace Auth0\Laravel; -use Auth0\Laravel\Events\Configuration\{ - BuildingConfigurationEvent, - BuiltConfigurationEvent, -}; - -use Auth0\Laravel\Events\Middleware\{ - StatefulMiddlewareRequest, - StatelessMiddlewareRequest, -}; - use Auth0\Laravel\Events\{ AuthenticationFailed, AuthenticationSucceeded, @@ -27,6 +17,16 @@ TokenVerificationSucceeded, }; +use Auth0\Laravel\Events\Configuration\{ + BuildingConfigurationEvent, + BuiltConfigurationEvent, +}; + +use Auth0\Laravel\Events\Middleware\{ + StatefulMiddlewareRequest, + StatelessMiddlewareRequest, +}; + /** * @api * diff --git a/src/EventsContract.php b/src/EventsContract.php index 8cc0c1d8..1e64d225 100644 --- a/src/EventsContract.php +++ b/src/EventsContract.php @@ -4,18 +4,6 @@ namespace Auth0\Laravel; -use Auth0\Laravel\Events\Configuration\{ - BuildingConfigurationEvent, - BuiltConfigurationEvent, -}; - -use Auth0\Laravel\Events\EventContract; - -use Auth0\Laravel\Events\Middleware\{ - StatefulMiddlewareRequest, - StatelessMiddlewareRequest, -}; - use Auth0\Laravel\Events\{ AuthenticationFailed, AuthenticationSucceeded, @@ -28,6 +16,18 @@ TokenVerificationSucceeded, }; +use Auth0\Laravel\Events\Configuration\{ + BuildingConfigurationEvent, + BuiltConfigurationEvent, +}; + +use Auth0\Laravel\Events\EventContract; + +use Auth0\Laravel\Events\Middleware\{ + StatefulMiddlewareRequest, + StatelessMiddlewareRequest, +}; + /** * @api */ From 78f84050d74ff423d6a6a70574ebc98e3a573502 Mon Sep 17 00:00:00 2001 From: Snehil Kishore Date: Tue, 13 May 2025 21:14:08 +0530 Subject: [PATCH 519/525] fix(deps): Update auth0/auth0-php for security fix --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5b30ff0f..d6d2e2b8 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,7 @@ "require": { "php": "^8.2", "ext-json": "*", - "auth0/auth0-php": "^8.10", + "auth0/auth0-php": "^8.14", "illuminate/contracts": "^11 || ^12", "illuminate/http": "^11 || ^12", "illuminate/support": "^11 || ^12", From a2144123f5d1015e04f0c5c868a81e6032a01cdd Mon Sep 17 00:00:00 2001 From: Snehil Kishore Date: Fri, 16 May 2025 02:26:39 +0530 Subject: [PATCH 520/525] Release 7.17.0 (#474) --- .version | 2 +- CHANGELOG.md | 8 ++++++++ src/ServiceAbstract.php | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.version b/.version index 971ecb25..6328c542 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -7.16.0 +7.17.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index e7d5d12e..111f32f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## [7.17.0](https://github.com/auth0/laravel-auth0/tree/7.17.0) (2025-05-16) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.16.0...7.17.0) + +**Fixed** + +- Security fix: Resolve CVE-2025-47275 + ## [7.16.0](https://github.com/auth0/laravel-auth0/tree/7.16.0) (2025-04-06) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.15.0...7.16.0) diff --git a/src/ServiceAbstract.php b/src/ServiceAbstract.php index dae4a90e..5b7c2283 100644 --- a/src/ServiceAbstract.php +++ b/src/ServiceAbstract.php @@ -22,7 +22,7 @@ abstract class ServiceAbstract extends InstanceEntityAbstract * * @var string */ - public const VERSION = '7.15.0'; + public const VERSION = '7.17.0'; /** * Decode a PSR-7 HTTP Response Message containing a JSON content body to a PHP array. Returns null if the response was not successful, or the response body was not JSON. From b8b8c7ddbba0f3c5a08446366f37f1e6f29e40fb Mon Sep 17 00:00:00 2001 From: Snehil Kishore Date: Tue, 2 Sep 2025 15:29:44 +0530 Subject: [PATCH 521/525] Mixed changes: feature, fixes, and docs from community (#477) * Mixed changes: feature, fixes, and docs from community * style: Improve code formatting and consistency in Auth0 and AuthenticationGuard classes * fix(deps): Update psalm/plugin-laravel to version ^2.12 * fix: Add ignoreFiles section for vendor directory in psalm configuration --- .github/workflows/semgrep.yml | 40 ------------------------------ CHANGELOG.md | 2 +- composer.json | 2 +- psalm.xml.dist | 3 +++ src/Auth0.php | 15 +++++++++++ src/Guards/AuthenticationGuard.php | 3 +++ src/Guards/AuthorizationGuard.php | 3 +++ 7 files changed, 26 insertions(+), 42 deletions(-) delete mode 100644 .github/workflows/semgrep.yml diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml deleted file mode 100644 index 514ae7db..00000000 --- a/.github/workflows/semgrep.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Semgrep - -on: - merge_group: - pull_request: - types: - - opened - - synchronize - push: - branches: - - main - schedule: - - cron: "30 0 1,15 * *" - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} - -jobs: - check: - name: Check for Vulnerabilities - runs-on: ubuntu-latest - - container: - image: returntocorp/semgrep - - steps: - - if: github.actor == 'dependabot[bot]' || github.event_name == 'merge_group' - run: exit 0 - - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.merge_commit_sha || github.ref }} - - - run: semgrep ci - env: - SEMGREP_APP_TOKEN: ${{ secrets.DX_SDKS_SEMGREP_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 111f32f6..6f365931 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -249,7 +249,7 @@ A new property has been added to the `config/auth0.php` configuration file: `beh #### Changes to Guard and Provider driver aliases -We identified an issue with using identical alias naming for both the Guard and Provider singletons under Laravel 10, which has required us to rename these aliases. As previous guidance had been to instantiate these using their class names, this should not be a breaking change in most cases. However, if you had used `auth0` as the name for either the Guard or the Provider drivers, kindly note that these have changed. Please use `auth0.guard` for the Guard driver and `auth0.provider`` for the Provider driver. This is a regrettable change but was necessary for adequate Laravel 10 support. +We identified an issue with using identical alias naming for both the Guard and Provider singletons under Laravel 10, which has required us to rename these aliases. As previous guidance had been to instantiate these using their class names, this should not be a breaking change in most cases. However, if you had used `auth0` as the name for either the Guard or the Provider drivers, kindly note that these have changed. Please use `auth0.guard` for the Guard driver and `auth0.provider` for the Provider driver. This is a regrettable change but was necessary for adequate Laravel 10 support. ## [7.4.0](https://github.com/auth0/laravel-auth0/tree/7.4.0) (2022-12-12) diff --git a/composer.json b/composer.json index d6d2e2b8..540f98f8 100644 --- a/composer.json +++ b/composer.json @@ -54,7 +54,7 @@ "pestphp/pest-plugin-laravel": "^2", "phpstan/phpstan": "^1", "phpstan/phpstan-strict-rules": "^1", - "psalm/plugin-laravel": "^2.10", + "psalm/plugin-laravel": "^2.12", "psr-mock/http": "^1", "rector/rector": "^1", "spatie/laravel-ray": "^1.40", diff --git a/psalm.xml.dist b/psalm.xml.dist index 6e8412c3..5256e8be 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -12,6 +12,9 @@ + + + diff --git a/src/Auth0.php b/src/Auth0.php index c6db0b32..25b9616f 100644 --- a/src/Auth0.php +++ b/src/Auth0.php @@ -9,6 +9,21 @@ /** * Auth0 Laravel SDK service provider. Provides access to the SDK's methods. * + * @method static \Auth0\SDK\Configuration\SdkConfiguration getConfiguration() + * @method static null|object getCredentials() + * @method static null|string getGuardConfigurationKey() + * @method static \Auth0\SDK\Contract\Auth0Interface getSdk() + * @method static \Auth0\SDK\Contract\API\ManagementInterface management() + * @method static self setGuardConfigurationKey(null|string $guardConfigurationKey = null) + * @method static \Auth0\SDK\Contract\Auth0Interface setSdk(\Auth0\SDK\Contract\Auth0Interface $sdk) + * @method static self reset() + * @method static self setConfiguration(\Auth0\SDK\Configuration\SdkConfiguration|array|null $configuration = null) + * + * @see Service + * @see ServiceAbstract + * @see Entities\InstanceEntityAbstract + * @see InstanceEntityTrait + * * @codeCoverageIgnore * * @deprecated 7.8.0 Use Auth0\Laravel\Service instead. diff --git a/src/Guards/AuthenticationGuard.php b/src/Guards/AuthenticationGuard.php index e3cc4ff2..03ca2dd6 100644 --- a/src/Guards/AuthenticationGuard.php +++ b/src/Guards/AuthenticationGuard.php @@ -13,6 +13,7 @@ use Auth0\SDK\Utility\HttpResponse; use Illuminate\Auth\Events\{Login, Logout}; use Illuminate\Contracts\Auth\Authenticatable; +use Illuminate\Support\Traits\Macroable; use Throwable; @@ -27,6 +28,8 @@ */ final class AuthenticationGuard extends GuardAbstract implements AuthenticationGuardContract { + use Macroable; + /** * @var string */ diff --git a/src/Guards/AuthorizationGuard.php b/src/Guards/AuthorizationGuard.php index 73bb1f1f..77f5e25e 100644 --- a/src/Guards/AuthorizationGuard.php +++ b/src/Guards/AuthorizationGuard.php @@ -8,6 +8,7 @@ use Auth0\Laravel\UserProviderContract; use Auth0\SDK\Utility\HttpResponse; use Illuminate\Contracts\Auth\Authenticatable; +use Illuminate\Support\Traits\Macroable; use function is_array; use function is_string; @@ -19,6 +20,8 @@ */ final class AuthorizationGuard extends GuardAbstract implements AuthorizationGuardContract { + use Macroable; + public function find(): ?CredentialEntityContract { if ($this->isImpersonating()) { From 09cc9ac0685451d9dcf739ef770c7eb6be4924a9 Mon Sep 17 00:00:00 2001 From: Snehil Kishore Date: Tue, 2 Sep 2025 15:42:06 +0530 Subject: [PATCH 522/525] Release 7.18.0 (#478) --- .version | 2 +- CHANGELOG.md | 6 ++++++ src/ServiceAbstract.php | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.version b/.version index 6328c542..1b2d969d 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -7.17.0 +7.18.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f365931..5a7422e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## [7.18.0](https://github.com/auth0/laravel-auth0/tree/7.18.0) (2025-09-02) +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.17.0...7.18.0) + +**Added** +- Mixed changes: feature, fixes, and docs from community [\#477](https://github.com/auth0/laravel-auth0/pull/477) ([kishore7snehil](https://github.com/kishore7snehil)) + ## [7.17.0](https://github.com/auth0/laravel-auth0/tree/7.17.0) (2025-05-16) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.16.0...7.17.0) diff --git a/src/ServiceAbstract.php b/src/ServiceAbstract.php index 5b7c2283..34e3184b 100644 --- a/src/ServiceAbstract.php +++ b/src/ServiceAbstract.php @@ -22,7 +22,7 @@ abstract class ServiceAbstract extends InstanceEntityAbstract * * @var string */ - public const VERSION = '7.17.0'; + public const VERSION = '7.18.0'; /** * Decode a PSR-7 HTTP Response Message containing a JSON content body to a PHP array. Returns null if the response was not successful, or the response body was not JSON. From c33c609fb041f7fe65deb6133feee0cb33fa80a5 Mon Sep 17 00:00:00 2001 From: Snehil Kishore Date: Wed, 1 Oct 2025 14:20:14 +0530 Subject: [PATCH 523/525] fix(deps): Update auth0/auth0-php for security fix --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 540f98f8..987874fc 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,7 @@ "require": { "php": "^8.2", "ext-json": "*", - "auth0/auth0-php": "^8.14", + "auth0/auth0-php": "^8.17", "illuminate/contracts": "^11 || ^12", "illuminate/http": "^11 || ^12", "illuminate/support": "^11 || ^12", From a8cdf1add3dac0b52112abcec3ff84f168444803 Mon Sep 17 00:00:00 2001 From: Snehil Kishore Date: Wed, 1 Oct 2025 16:58:46 +0530 Subject: [PATCH 524/525] Release 7.19.0 (#479) * Release 7.19.0 --- .version | 2 +- CHANGELOG.md | 8 ++++++++ src/ServiceAbstract.php | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.version b/.version index 1b2d969d..3821090f 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -7.18.0 +7.19.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a7422e7..c11b7974 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## [7.19.0](https://github.com/auth0/laravel-auth0/tree/7.19.0) (2025-10-01) + +[Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.18.0...7.19.0) + +**Fixed** + +- Security fix: Resolve CVE-2025-58769 + ## [7.18.0](https://github.com/auth0/laravel-auth0/tree/7.18.0) (2025-09-02) [Full Changelog](https://github.com/auth0/laravel-auth0/compare/7.17.0...7.18.0) diff --git a/src/ServiceAbstract.php b/src/ServiceAbstract.php index 34e3184b..3c46e4e5 100644 --- a/src/ServiceAbstract.php +++ b/src/ServiceAbstract.php @@ -22,7 +22,7 @@ abstract class ServiceAbstract extends InstanceEntityAbstract * * @var string */ - public const VERSION = '7.18.0'; + public const VERSION = '7.19.0'; /** * Decode a PSR-7 HTTP Response Message containing a JSON content body to a PHP array. Returns null if the response was not successful, or the response body was not JSON. From 00c97eef5886e4b86af60734bf7885246240bee6 Mon Sep 17 00:00:00 2001 From: Snehil Kishore Date: Wed, 22 Oct 2025 13:05:49 +0530 Subject: [PATCH 525/525] feat: Add Claude Code PR Review workflow (#481) --- .github/workflows/claude-code-review.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/claude-code-review.yml diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml new file mode 100644 index 00000000..d2183bca --- /dev/null +++ b/.github/workflows/claude-code-review.yml @@ -0,0 +1,18 @@ +name: Claude Code PR Review + +on: + issue_comment: + types: [ created ] + pull_request_review_comment: + types: [ created ] + pull_request_review: + types: [ submitted ] + +jobs: + claude-review: + permissions: + contents: write + issues: write + pull-requests: write + id-token: write + uses: auth0/auth0-ai-pr-analyzer-gh-action/.github/workflows/claude-code-review.yml@main \ No newline at end of file