{"action":"created","comment":{"url":"https://api.github.com/repos/auth0/auth0-PHP/pulls/comments/185911185","pull_request_review_id":117316072,"id":185911185,"diff_hunk":"@@ -7,290 +7,505 @@\n [![License](https://poser.pugx.org/auth0/auth0-php/license)](https://packagist.org/packages/auth0/auth0-php)\n [![Total Downloads](https://poser.pugx.org/auth0/auth0-php/downloads)](https://packagist.org/packages/auth0/auth0-php)\n \n+The Auth0 PHP SDK provides straight-forward and tested methods for accessing Authentication and Management API endpoints. This README describes how to get started and provides simple examples of how to use the SDK.\n+\n+For more details about how to install this SDK into an existing project or how to download a preconfigured seed project, see:\n+\n+* [Basic PHP application quickstart](https://auth0.com/docs/quickstart/webapp/php/)\n+* [PHP API quickstart](https://auth0.com/docs/quickstart/backend/php/)\n+\n+## Upgrading Through 5.1.0?\n+\n+Please see the notes in the [changelog](CHANGELOG.md#510-2018-03-02) regarding state validation.\n+\n ## Installation\n \n-Installing via composer\n+We recommend installing the SDK with [Composer](https://getcomposer.org/doc/00-intro.md). If you already have Composer installed globally, run the following:\n \n ```\n $ composer require auth0/auth0-php\n ```\n \n-Check our docs page to get a complete guide on how to install it in an existing project or download a pre configured seedproject:\n+Otherwise, [download Composer locally](https://getcomposer.org/doc/00-intro.md#locally) and run:\n \n-* Regular webapp: https://auth0.com/docs/quickstart/webapp/php/\n-* Web API: https://auth0.com/docs/quickstart/backend/php/\n+```\n+php composer.phar require auth0/auth0-php\n+``` \n \n-> If you find something wrong in our docs, PR are welcome in our docs repo: https://github.com/auth0/docs\n+This will create `composer.json` and `composer.lock` files in the directory where the command was run, along with a vendor folder containing this SDK and its dependencies. \n \n-## Security Upgrade Notes 5.1.0+\n+Finally, include the Composer autoload file in your project to use the SDK:\n \n-**State validation** is now default behaviour for improved security. By default this will automatically use **Session Storage** and will apply if you are using the combination of the `Auth0->login()` method to call the `/authorize` endpoint and using any method which calls the `Auth0->exchange()` method in your callback.\n+```php\n+require __DIR__ . '/vendor/autoload.php';\n \n-If you require custom storage methods you can implement your own [StateHandler](https://github.com/auth0/auth0-PHP/blob/master/src/API/Helpers/State/StateHandler.php) and set it using the `state_handler` key when you initialize an `Auth0` instance.\n+use Auth0\\SDK\\Auth0;\n+```\n \n-**Important:** If you are using the `Auth0->exchange()` and using a method other than `Auth0->login()` to generate the Authorize URL you can disable the *StateHandler* by setting the `state_handler` key to `false` when you initialize the `Auth0` instance. However, it is **Highly Recommended** to implement state validation.\n+The examples below use [PHP Dotenv](https://github.com/josegonzalez/php-dotenv) to store and load sensitive Auth0 credentials from the environment rather than hard-coding them into your application. PHP Dotenv is a dependency of this SDK so if you followed the steps above to install via Composer, the class is available for you to use in your project. \n \n-## Getting started\n+First, you'll need a free Auth0 account and an Application:\n \n-### Decoding and verifying tokens\n+1. Go to [auth0.com/signup](https://auth0.com/signup) and create your account.\n+2. Once you are in the dashboard, go to **Applications**, then **Create Application**.\n+3. Give your Application a name, select **Regular Web Application**, then **Create**\n+4. Click the **Settings** tab for the required credentials used below.\n \n-```php\n-// HS256 tokens\n-use Auth0\\SDK\\JWTVerifier;\n+Next, create a `.env` file and add the following values:\n \n-$verifier = new JWTVerifier([\n-    'valid_audiences' => [$client_id],\n-    'client_secret' => $client_secret\n-]);\n+```\n+# Auth0 tenant domain, found in your Application settings\n+AUTH0_DOMAIN=\"tenant.auth0.com\"\n \n-$decoded = $verifier->verifyAndDecode($jwt);\n+# Auth0 Client ID, found in your Application settings\n+AUTH0_CLIENT_ID=\"Client ID goes here\"\n \n-// RS256 tokens\n-$verifier = new JWTVerifier([\n-    'supported_algs' => ['RS256'],\n-    'valid_audiences' => [$client_id],\n-    'authorized_iss' => [\"https://$domain/\"] // the issues will look like https://your_account[.region].auth0.com/ (being region an optional segment only present for eu and au accounts.\n-]);\n+# Auth0 Client Secret, found in your Application settings\n+AUTH0_CLIENT_SECRET=\"Client Secret goes here\"\n \n-$decoded = $verifier->verifyAndDecode($jwt);\n+# URL to handle the authentication callback\n+# Save this URL in the \"Allowed Callback URLs\" field in the Auth0 dashboard\n+AUTH0_CALLBACK_URL=\"Callback URL goes here\"\n \n-```\n+# Audience for profile data endpoint calls after authentication\n+AUTH0_AUTH_AUDIENCE=\"https://${AUTH0_DOMAIN}/userinfo/\"\n \n-Accepted params:\n-- **cache**: Receives an instance of `Auth0\\SDK\\Helpers\\Cache\\CacheHandler` (Supported `FileSystemCacheHandler` and `NoCacheHandler`). Defaults to `NoCacheHandler`.\n-- **guzzle_options**: Configuration propagated to guzzle when fetching the JWKs.\n-- **supported_algs**: `RS256` and `HS256` supported. Defaults to `HS256`.\n-- **valid_audiences**: List of audiences that identifies the API (useful for multi-tenant environments).\n-- **authorized_iss**: List of issues authorized to sign tokens for the API.\n-- **client_secret**: Client secret used to verify the token signature (only for `HS256`).\n-- **secret_base64_encoded**: When `true`, it will decode the secret used to verify the token signature. Defaults to `true` (used only for `HS256`).\n+# Audience for Management API calls (not required for authentication calls)\n+AUTH0_MANAGEMENT_AUDIENCE=\"https://${AUTH0_DOMAIN}/api/v2/\"\n+\n+# API token for accessing the Management API (not required for authentication calls)\n+AUTH0_MANAGEMENT_API_TOKEN=\"App token goes here\"\n+```\n \n-### Oauth2 authentication\n+In your application below the Composer autoload `require`, add:\n \n ```php\n-require __DIR__ . '/vendor/autoload.php';\n+// ... other use declarations\n+use josegonzalez\\Dotenv\\Loader;\n \n-use Auth0\\SDK\\Auth0;\n+// Setup environment vars\n+$Dotenv = new Loader(__DIR__ . '/.env');\n+$Dotenv->parse()->putenv(true);\n+\n+// Get environment variables\n+echo 'My Auth0 domain is ' . getenv('AUTH0_DOMAIN') . '!';\n+```\n+\n+## Usage - Authentication API\n+\n+This SDK provides easy-to-implement methods to access the [Authentication API](https://auth0.com/docs/api/authentication). Some common authentication operations are explained below with examples. For additional information and capabilities, please see the methods in the `\\Auth0\\SDK\\API\\Authentication` class. Avoid using any methods marked `@deprecated` as they will be removed in the next major version and may not be enabled for your account.\n+\n+The examples below assume that you followed the installation steps above and are using a `.env` file and loader to store credentials.\n+\n+### Login\n+\n+The easiest and most secure way to handle logins to a web application is to use the [Authentication Code grant](https://auth0.com/docs/api-auth/tutorials/authorization-code-grant) combined with Auth0's Universal Login page. In short, that process is:\n \n-$domain        = 'YOUR_NAMESPACE';\n-$client_id     = 'YOUR_CLIENT_ID';\n-$client_secret = 'YOUR_CLIENT_SECRET';\n-$redirect_uri  = 'http://YOUR_APP/callback';\n+1. An user requesting access is redirected to the Universal Login Page.\n+2. The user authenticates using one of many possible connections: social (Twitter or Facebook); database (email and password); passwordless (email or a mobile device).\n+3. The user is redirected back to your application's callback URL with a `code` and `state` parameter if successful or an `error` and `error_description` if not.\n+4. If the authentication was successful, the `state` parameter is validated.\n+5. If the `state` is valid, the `code` parameter is exchanged with Auth0 for an access token.\n+6. If the exchange is successful, the access token is used to call an Auth0 `/userinfo` endpoint, which returns the authenticated user's information.\n+7. This information can be used to create an account, to start an application-specific session, or to persist as the user session.\n \n+The PHP SDK handles most of the previous steps. Your application needs to:\n+\n+1. Determine a log in action (for example: click a link, visit walled content, etc.) and call  `Auth0::login()`\n+2. Handle returned errors.\n+\n+A simple implementation of these steps looks like this:\n+\n+```php\n+// Example #1\n+// login.php\n+use Auth0\\SDK\\Auth0;\n+\n+// Initialize the Auth0 class with required credentials.\n $auth0 = new Auth0([\n-  'domain' => $domain,\n-  'client_id' => $client_id,\n-  'client_secret' => $client_secret,\n-  'redirect_uri' => $redirect_uri,\n-  'audience' => 'urn:test:api',\n-  'persist_id_token' => true,\n-  'persist_access_token' => true,\n-  'persist_refresh_token' => true,\n+\n+    // See Installation above to setup environment variables.\n+    'domain' => getenv('AUTH0_DOMAIN'),\n+    'client_id' => getenv('AUTH0_CLIENT_ID'),\n+    'client_secret' => getenv('AUTH0_CLIENT_SECRET'),\n+    'audience' => getenv('AUTH0_AUTH_AUDIENCE'),\n+\n+    // This would be the URL for this file in this example.\n+    'redirect_uri' => getenv('AUTH0_LOGIN_CALLBACK_URL'),\n+\n+    // The scope determines what data is provided by the /userinfo endpoint.\n+    'scope' => 'openid',\n ]);\n \n-$userInfo = $auth0->getUser();\n+if (! empty($_GET['error']) || ! empty($_GET['error_description'])) {\n+    // Handle errors sent back by Auth0.\n+}\n+\n+// If there is a user persisted (PHP session by default), return that.\n+// Otherwise, look for a `state` and `code` URL parameter to validate and exchange, respectively.\n+// If the state validation and code exchange are successful, return the userinfo.\n+$userinfo = $auth0->getUser();\n \n-if (!$userInfo) {\n+// We have no persisted user and no `code` parameter so we redirect to the Universal Login Page.\n+if (empty($userinfo)) {\n     $auth0->login();\n }\n \n-var_dump($profile);\n+// We either have a persisted user or a successful code exchange.\n+var_dump($userinfo);\n+\n+// This is where a user record in a local database could be retrieved or created.\n+// Redirect somewhere to remove `code` and `state` parameters to avoid a fatal error on refresh.\n+\n ```\n \n-> For more info, check the quickstart docs for [Regular webapp](https://auth0.com/docs/quickstart/webapp/php/) and [Web API](https://auth0.com/docs/quickstart/backend/php/).\n+Loading the script above in your browser should:\n \n-### Calling the management API\n+1. Immediately redirect you to an Auth0 login page for your tenant.\n+2. After successfully logging in using any connection, redirect you back to your app.\n+3. Display the returned userinfo:\n \n ```php\n-require __DIR__ . '/vendor/autoload.php';\n+array(1) { [\"sub\"]=> string(30) \"auth0|4b12v471de68e34446mq7c2v\" }\n+```\n \n-use Auth0\\SDK\\API\\Management;\n+### Profile\n \n-$token = \"eyJhbGciO....eyJhdWQiOiI....1ZVDisdL...\";\n-$domain = \"account.auth0.com\";\n+Once a user has authenticated, we can use their persisted data to determine whether they are allowed to access sensitive site pages, like a user profile. \n \n-$auth0Api = new Management($token, $domain);\n+Using the example above, we'll add additional [scope](https://auth0.com/docs/api-auth/tutorials/adoption/scope-custom-claims) to make the profile a little more interesting:\n \n-$usersList = $auth0Api->users->search([ \"q\" => \"email@test.com\" ]);\n+```php\n+// login.php\n \n-var_dump($usersList);\n+// ...\n+\t'scope' => 'openid email name nickname picture updated_at profile',\n+// ...\n ```\n \n-### Calling the Authentication API\n+Once someone has logged in requesting the new user claims, let's redirect to a profile page:\n+\n \n ```php\n-require __DIR__ . '/vendor/autoload.php';\n+// login.php\n \n-use Auth0\\SDK\\API\\Authentication;\n+//...\n+// var_dump($userinfo);\n+header('Location: /profile.php');\n \n-$domain = \"account.auth0.com\";\n-$client_id = '...';\n-$client_secret = '...'; // This is optional, only needed for code exchange and impersonation api\n+```\n \n-$auth0Api = new Authentication($domain, $client_id, $client_secret);\n+This profile page will return all the data we retrieved from the `/userinfo` endpoint and stored in our session:\n \n-// getting an access token with client credentials grant\n-$access_token = $auth0Api->client_credentials([\n-        'audience' => 'urn:test:api',\n-        'scope' => 'do:something read:somethingelse',\n-    ]);\n \n-// getting an access token with password realm grant\n-$access_token = $auth0Api->login([\n-        'username' => 'someone@example.com',\n-        'password' => 'shh',\n-        'realm' => 'Username-Password-Authentication',\n-    ]);\n+```php\n+// Example #2\n+// profile.php\n+use Auth0\\SDK\\Store\\SessionStore;\n+\n+// Get our persistent storage interface to get the stored userinfo.\n+$store = new SessionStore();\n+$userinfo = $store->get('user');\n+\n+if ($userinfo) {\n+    printf(\n+        '<h1>Hi %s!</h1>\n+        <p><img width=\"200\" src=\"%s\"></p>\n+        <p><strong>Last update:</strong> %s</p>\n+        <p><strong>Contact:</strong> %s %s</p>',\n+        strip_tags($userinfo[ 'nickname' ]),\n+        filter_var($userinfo[ 'picture' ], FILTER_SANITIZE_URL),\n+        date('j/m/Y', strtotime($userinfo[ 'updated_at' ])),\n+        filter_var($userinfo[ 'email' ], FILTER_SANITIZE_EMAIL),\n+        $userinfo[ 'email_verified' ] ? '✓' : '✗'\n+    );\n+} else {\n+    echo '<p>Please login to view your profile.</p>';\n+}\n ```\n \n-## Troubleshoot\n+### Logout\n \n-> I am getting `curl error 60: SSL certificate problem: self signed certificate in certificate chain` on Windows\n+In addition to logging in, we also want users to be able to log out. When users log out, they must invalidate their session for the application. For this SDK, that means destroying their persistent user data:\n \n-This is a common issue with latest PHP versions under windows (related to a incompatibility between windows and openssl CAs database).\n+```php\n+// Example #2\n+// logout.php\n+use Auth0\\SDK\\Auth0;\n+use Auth0\\SDK\\API\\Authentication;\n \n-- download this CAs database `https://curl.haxx.se/ca/cacert.pem` to `c:/cacert.pem`\n-- you need to edit your php.ini and add `openssl.cafile=c:/cacert.pem` (it should point to the file you downloaded)\n+$auth0 = new Auth0([\n+    'domain' => getenv('AUTH0_DOMAIN'),\n+    'client_id' => getenv('AUTH0_CLIENT_ID'),\n+    'client_secret' => getenv('AUTH0_CLIENT_SECRET'),\n+    'redirect_uri' => getenv('AUTH0_LOGIN_BASIC_CALLBACK_URL'),\n+]);\n+\n+// Log out of the local application.\n+$auth0->logout();\n+\n+```\n \n-> I am not using composer, my host does not allow using Composer\n+If you're using SSO and want this to also end their session at Auth0, redirect to the Auth0 logout URL after logging out locally:\n \n-This package uses composer for maintaining dependencies. However, if you cannot use composer on your server. Please follow the following steps and upload these dependencies manually.\n+```php\n+// Setup the Authentication class with required credentials.\n+// No API calls are made on instantiation.\n+$auth0_api = new Authentication(getenv('AUTH0_DOMAIN'));\n \n-- Download and install composer on your local environment.\n-- Install auth0-PHP using composer.\n-- Once you have everything working upload your scripts to the host along with the vendor folder.\n+// Get the Auth0 logout URL to end the Auth0 session as well.\n+$auth0_logout = $auth0_api->get_logout_link(\n \n+    // This needs to be saved in the \"Allowed Logout URLs\" field in your Application settings.\n+    getenv('AUTH0_LOGOUT_RETURN_URL'),\n+    // Indicate the specific Application.\n+    getenv('AUTH0_CLIENT_ID')\n+);\n \n-## News\n+header('Location: ' . $auth0_logout);\n+exit;\n+```\n \n-- The version 2.x of the PHP SDK was updated to work with Guzzle 6.1. For compatibility with Guzzle 5, you should use 1.x branch.\n-- The version 1.x of the PHP SDK now works with the Auth API v2 which adds lots of new [features and changes](https://auth0.com/docs/apiv2Changes).\n+More information about the logout process can be found [on our Docs site](https://auth0.com/docs/logout).\n \n-### *NOTICE* Backward compatibility breaks\n+### Client Credentials Grant\n \n-#### 4.0\n+A [Client Credentials grant](https://auth0.com/docs/api-auth/tutorials/client-credentials) gives an application access to an API as long as the application is:\n \n-- Soon to deprecate the following classes:\n-    + Auth0\\SDK\\Auth0Api: use \\Auth0\\SDK\\API\\Management instead\n-    + Auth0\\SDK\\Auth0AuthApi: use \\Auth0\\SDK\\API\\Authentication instead\n-    + Auth0\\SDK\\Auth0JWT: Use \\Auth0\\SDK\\JWTVerifier instead\n+- allowed to perform a Client Credentials grant (advanced settings on the Application settings page)\n+- authorized for the API providing the grant (Applications tab for the API in question)\n \n-#### 3.2\n-- Now the SDK supports RS256 codes, it will decode using the `.well-known/jwks.json` endpoint to fetch the public key\n+Successful authentication for this grant will result in an access token being issued for the API requested. \n \n-#### 3.x\n+An example of requesting an access token for the Management API is below:\n \n-- SDK api changes, now the Auth0 API client is not build of static classes anymore. Usage example:\n ```php\n-$token = \"eyJhbGciO....eyJhdWQiOiI....1ZVDisdL...\";\n-$domain = \"account.auth0.com\";\n-$guzzleOptions = [ ... ];\n+// Example #5\n+use \\Auth0\\SDK\\API\\Authentication;\n+use \\Auth0\\SDK\\Exception\\ApiException;\n+use \\GuzzleHttp\\Exception\\ClientException;\n+\n+$auth0_api = new Authentication(getenv('AUTH0_DOMAIN'));\n+\n+$config = [\n+    // Required for a Client Credentials grant.\n+    // Application must allow this grant type and be authorized for the API requested\n+    'client_secret' => getenv('AUTH0_CLIENT_SECRET'),\n+    'client_id' => getenv('AUTH0_CLIENT_ID'),\n+\n+    // Also required, found in the API settings page.\n+    'audience' => getenv('AUTH0_MANAGEMENT_AUDIENCE'),\n+];\n+\n+try {\n+    $result = $auth0_api->client_credentials($config);\n+    echo '<pre>' . print_r($result, true) . '</pre>';\n+    die();\n+} catch (ClientException $e) {\n+    echo 'Caught: ClientException - ' . $e->getMessage();\n+} catch (ApiException $e) {\n+    echo 'Caught: ApiException - ' . $e->getMessage();\n+}\n+```\n \n-$auth0Api = new \\Auth0\\SDK\\Auth0Api($token, $domain, $guzzleOptions); /* $guzzleOptions is optional */\n+If the grant was successful, you should see the following:\n \n-$usersList = $auth0Api->users->search([ \"q\" => \"email@test.com\" ]);\n+```\n+Array\n+(\n+    [access_token] => eyJ0eXAi...eyJpc3Mi...QoB2c24w\n+    [scope] => read:users read:clients\n+    [expires_in] => 86400\n+    [token_type] => Bearer\n+)\n ```\n \n-#### 2.2\n-- Now the SDK fetches the user using the `tokeninfo` endpoint to be fully compliant with the openid spec\n-- Now the SDK supports RS256 codes, it will decode using the `.well-known/jwks.json` endpoint to fetch the public key\n+See the \"Usage - Management API\" section below for more information on how to use this access token. \n \n-#### 2.x\n+## Usage - Decoding and Verifying JWTs\n \n-- Session storage now returns null (and null is expected by the sdk) if there is no info stored (this change was made since false is a valid value to be stored in session).\n-- Guzzle 6.1 required\n+This SDK also includes an interface to the [Firebase PHP JWT library](https://github.com/firebase/php-jwt), used to decode and verify JSON web tokens (JWT). The `JWTVerifier` class has a single method, `verifyAndDecode()`, which accepts a JWT and either returns a decoded token or throws an error. More information on JWTs and how to build and decode them can be found [here on jwt.io](https://jwt.io/).\n \n-#### 1.x\n+The decoder can work with both HS256 and RS256 tokens. Both types require the algorithm and valid audiences to indicated before processing. Additionally, HS256 tokens require the client secret while RS256 tokens require an authorized issuer. \n \n-- Now, all the SDK is under the namespace `\\Auth0\\SDK`\n-- The exceptions were moved to the namespace `\\Auth0\\SDK\\Exceptions`\n+Here is an example of a small, URL-based JWT decoder:\n \n-### New features\n \n-- The Auth0 class, now provides two methods to access the user metadata, `getUserMetadata` and `getAppMetadata`. For more info, check the [API v2 changes](https://auth0.com/docs/apiv2Changes)\n-- The Auth0 class, now provides a way to update the UserMetadata with the method `updateUserMetadata`. Internally, it uses the [update user endpoint](https://auth0.com/docs/apiv2#!/users/patch_users_by_id), check the method documentation for more info.\n-- The new service `\\Auth0\\SDK\\API\\ApiUsers` provides an easy way to consume the API v2 Users endpoints.\n-- A simple API client (`\\Auth0\\SDK\\API\\ApiClient`) is also available to use.\n-- A JWT generator and decoder is also available (`\\Auth0\\SDK\\Auth0JWT`)\n-- Now provides an interface for the [Authentication API](https://auth0.com/docs/auth-api).\n+```php\n+// Example #4\n+// decode-jwt.php\n+use Auth0\\SDK\\JWTVerifier;\n+use Auth0\\SDK\\Exception\\InvalidTokenException;\n+use Auth0\\SDK\\Exception\\CoreException;\n \n->***Note:*** API V2 restrict the access to the endpoints via scopes. By default, the user token has granted certain scopes that let update the user metadata but not the root attributes nor app_metadata. To update this information and access another endpoints, you need an special token with this scopes granted. For more information about scopes, check [the API v2 docs](https://auth0.com/docs/apiv2Changes#6).\n+// Do we have an ID token?\n+if (empty($_GET[ 'id_token' ])) {\n+    echo '<code>No `id_token` URL parameter!</code> ';\n+    exit;\n+}\n+\n+// Do we have a valid algorithm?\n+if (empty($_GET[ 'token_alg' ]) || ! in_array($_GET[ 'token_alg' ], [ 'HS256', 'RS256' ])) {\n+    echo '<code>Missing or invalid `token_alg` URL parameter!</code> ';\n+    exit;\n+}\n \n-## Examples\n+$config = [\n+    'supported_algs' => [ $_GET[ 'token_alg' ] ],\n+    'client_secret' => getenv('AUTH0_CLIENT_SECRET'),\n+];\n \n-Check the [basic-oauth](https://github.com/auth0/auth0-PHP/tree/master/examples/basic-oauth) example to see a quick demo on how the sdk works.\n-You just need to create a `.env` file with the following information:\n+if ('HS256' === $_GET[ 'token_alg' ]) {\n+    $config['client_secret'] = getenv('AUTH0_CLIENT_SECRET');\n+} else {\n+    $config['authorized_iss'] = [ 'https://' . getenv('AUTH0_DOMAIN') . '/' ];\n+}\n \n+try {\n+    $verifier = new JWTVerifier($config);\n+    $decoded_token = $verifier->verifyAndDecode($_GET[ 'id_token' ]);\n+    echo '<pre>' . print_r($decoded_token, true) . '</pre>';\n+} catch (InvalidTokenException $e) {\n+    echo 'Caught: InvalidTokenException - ' . $e->getMessage();\n+} catch (CoreException $e) {\n+    echo 'Caught: CoreException - ' . $e->getMessage();\n+} catch (\\Exception $e) {\n+    echo 'Caught: Exception - ' . $e->getMessage();\n+}\n ```\n-AUTH0_CLIENT_SECRET=YOUR_APP_SECRET\n-AUTH0_CLIENT_ID=YOU_APP_CLIENT\n-AUTH0_DOMAIN=YOUR_DOMAIN.auth0.com\n-AUTH0_CALLBACK_URL=http://localhost:3000/index.php\n-AUTH0_APPTOKEN=A_VALID_APPTOKEN_WITH_CREATE_USER_SCOPE\n+\n+Additional parameters for the `JWTVerifier` configuration array are:\n+\n+- **cache**: Receives an instance of `Auth0\\SDK\\Helpers\\Cache\\CacheHandler` (Supported `FileSystemCacheHandler` and `NoCacheHandler`). Defaults to `NoCacheHandler` (RS256 only).\n+- **guzzle_options**: Configuration propagated to Guzzle when fetching the JWKs (RS256 only). These options are [documented here](http://docs.guzzlephp.org/en/stable/request-options.html).\n+- **secret\\_base64\\_encoded**: When `true`, it will decode the secret used to verify the token signature. This is only used for HS256 tokens and defaults to `true`. Your Application settings will say whether the Client Secret provided is encoded or not. \n+\n+## Usage - Management API\n+\n+This SDK also provides a wrapper for the Management API, which is used to perform operations on your Auth0 tenant. Using this API, you can:\n+\n+- Search for and create users\n+- Create and update Applications\n+- Retrieve log entries\n+- Manage rules \n+\n+... and much more. See our [documentation](https://auth0.com/docs/api/management/v2) for information on what's possible and the examples below for how to authenticate and access this API. \n+\n+### Authentication\n+\n+In order to use the Management API, you must authenticate one of two ways:\n+\n+- For temporary access or testing, you can [manually generate an API token](https://auth0.com/docs/api/management/v2/tokens#get-a-token-manually) and save it in your `.env` file\n+- For extended access, you can create and execute and Client Credentials grant (detailed above) when access is required\n+\n+Regardless of the method, the token generated must have the scopes required for the operations your app wants to execute. Consult the [API documentation](https://auth0.com/docs/api/management/v2) for the scopes required for the specific endpoint you're trying to access.\n+\n+To grant the scopes needed: \n+\n+1. Go to [APIs](https://manage.auth0.com/#/apis) > Auth0 Management API > **Machine to Machine Applications** tab.\n+2. Find your Application and authorize it.\n+3. Click the arrow to expand the row and select the scopes required.\n+\n+Now you can authenticate one of the two ways above and use that token to perform operations:\n+\n+```php\n+use Auth0\\SDK\\API\\Management;\n+\n+$access_token = getenv('AUTH0_MANAGEMENT_API_TOKEN');\n+if ( empty( $access_token ) ) {\n+\t// See \"Client Credentials Grant\" above\n+\t$access_token = get_access_token();\n+}\n+$mgmt_api = new Management( $access_token, getenv('AUTH0_DOMAIN') );\n ```\n \n-You will get your app client and secret from your Auth0 app you had created.\n-The auth0 domain, is the one you pick when you created your auth0 account.\n-You need to set this callback url in your app allowed callbacks.\n-The app token is used in the 'create user' page and needs `create:users` scope. To create one, you need to use the token generator in the [API V2 documentation page](https://auth0.com/docs/apiv2)\n+The `Management` class stores access to endpoints as properties of its instances. The best way to see what endpoints are covered is to read through the `\\Auth0\\SDK\\API\\Management::__construct()` method. ","path":"README.md","position":553,"original_position":553,"commit_id":"f10484dc61954956db247eb052b8b15e9d859e3e","original_commit_id":"f10484dc61954956db247eb052b8b15e9d859e3e","user":{"login":"lbalmaceda","id":3900123,"avatar_url":"https://avatars3.githubusercontent.com/u/3900123?v=4","gravatar_id":"","url":"https://api.github.com/users/lbalmaceda","html_url":"https://github.com/lbalmaceda","followers_url":"https://api.github.com/users/lbalmaceda/followers","following_url":"https://api.github.com/users/lbalmaceda/following{/other_user}","gists_url":"https://api.github.com/users/lbalmaceda/gists{/gist_id}","starred_url":"https://api.github.com/users/lbalmaceda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lbalmaceda/subscriptions","organizations_url":"https://api.github.com/users/lbalmaceda/orgs","repos_url":"https://api.github.com/users/lbalmaceda/repos","events_url":"https://api.github.com/users/lbalmaceda/events{/privacy}","received_events_url":"https://api.github.com/users/lbalmaceda/received_events","type":"User","site_admin":false},"body":"I'm not saying you're lazy for not listing them, but a short list would probably be better. Check how I'm doing that in [java](https://github.com/auth0/auth0-java#management-api). This comment is tied to the \"official API documentation\" one above","created_at":"2018-05-03T19:26:30Z","updated_at":"2018-05-03T19:31:16Z","html_url":"https://github.com/auth0/auth0-PHP/pull/253#discussion_r185911185","pull_request_url":"https://api.github.com/repos/auth0/auth0-PHP/pulls/253","author_association":"NONE","_links":{"self":{"href":"https://api.github.com/repos/auth0/auth0-PHP/pulls/comments/185911185"},"html":{"href":"https://github.com/auth0/auth0-PHP/pull/253#discussion_r185911185"},"pull_request":{"href":"https://api.github.com/repos/auth0/auth0-PHP/pulls/253"}}},"pull_request":{"url":"https://api.github.com/repos/auth0/auth0-PHP/pulls/253","id":185483283,"html_url":"https://github.com/auth0/auth0-PHP/pull/253","diff_url":"https://github.com/auth0/auth0-PHP/pull/253.diff","patch_url":"https://github.com/auth0/auth0-PHP/pull/253.patch","issue_url":"https://api.github.com/repos/auth0/auth0-PHP/issues/253","number":253,"state":"open","locked":false,"title":"Rewrite README; add news and notes to CHANGELOG","user":{"login":"joshcanhelp","id":855223,"avatar_url":"https://avatars2.githubusercontent.com/u/855223?v=4","gravatar_id":"","url":"https://api.github.com/users/joshcanhelp","html_url":"https://github.com/joshcanhelp","followers_url":"https://api.github.com/users/joshcanhelp/followers","following_url":"https://api.github.com/users/joshcanhelp/following{/other_user}","gists_url":"https://api.github.com/users/joshcanhelp/gists{/gist_id}","starred_url":"https://api.github.com/users/joshcanhelp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joshcanhelp/subscriptions","organizations_url":"https://api.github.com/users/joshcanhelp/orgs","repos_url":"https://api.github.com/users/joshcanhelp/repos","events_url":"https://api.github.com/users/joshcanhelp/events{/privacy}","received_events_url":"https://api.github.com/users/joshcanhelp/received_events","type":"User","site_admin":false},"body":"Complete re-write of the main README file for this repo. Highlights:\r\n\r\n- Better, more complete installation steps\r\n- Better, more complete examples for basic tasks\r\n- Removal of deprecated or removed methods\r\n- Moved \"news\" and notes for unmaintained branches into the CHANGELOG\r\n\r\nFixes #248, #217  ","created_at":"2018-05-02T15:53:18Z","updated_at":"2018-05-03T19:31:16Z","closed_at":null,"merged_at":null,"merge_commit_sha":"651beeb85ffc56f564c76736960a241e0003e688","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":632198273,"url":"https://api.github.com/repos/auth0/auth0-PHP/labels/CH:%20Fixed","name":"CH: Fixed","color":"5319e7","default":false}],"milestone":{"url":"https://api.github.com/repos/auth0/auth0-PHP/milestones/6","html_url":"https://github.com/auth0/auth0-PHP/milestone/6","labels_url":"https://api.github.com/repos/auth0/auth0-PHP/milestones/6/labels","id":3166465,"number":6,"title":"v5-Next","description":"","creator":{"login":"joshcanhelp","id":855223,"avatar_url":"https://avatars2.githubusercontent.com/u/855223?v=4","gravatar_id":"","url":"https://api.github.com/users/joshcanhelp","html_url":"https://github.com/joshcanhelp","followers_url":"https://api.github.com/users/joshcanhelp/followers","following_url":"https://api.github.com/users/joshcanhelp/following{/other_user}","gists_url":"https://api.github.com/users/joshcanhelp/gists{/gist_id}","starred_url":"https://api.github.com/users/joshcanhelp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joshcanhelp/subscriptions","organizations_url":"https://api.github.com/users/joshcanhelp/orgs","repos_url":"https://api.github.com/users/joshcanhelp/repos","events_url":"https://api.github.com/users/joshcanhelp/events{/privacy}","received_events_url":"https://api.github.com/users/joshcanhelp/received_events","type":"User","site_admin":false},"open_issues":5,"closed_issues":1,"state":"open","created_at":"2018-03-06T17:26:23Z","updated_at":"2018-05-02T16:34:04Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/auth0/auth0-PHP/pulls/253/commits","review_comments_url":"https://api.github.com/repos/auth0/auth0-PHP/pulls/253/comments","review_comment_url":"https://api.github.com/repos/auth0/auth0-PHP/pulls/comments{/number}","comments_url":"https://api.github.com/repos/auth0/auth0-PHP/issues/253/comments","statuses_url":"https://api.github.com/repos/auth0/auth0-PHP/statuses/f10484dc61954956db247eb052b8b15e9d859e3e","head":{"label":"auth0:fix-readme","ref":"fix-readme","sha":"f10484dc61954956db247eb052b8b15e9d859e3e","user":{"login":"auth0","id":2824157,"avatar_url":"https://avatars1.githubusercontent.com/u/2824157?v=4","gravatar_id":"","url":"https://api.github.com/users/auth0","html_url":"https://github.com/auth0","followers_url":"https://api.github.com/users/auth0/followers","following_url":"https://api.github.com/users/auth0/following{/other_user}","gists_url":"https://api.github.com/users/auth0/gists{/gist_id}","starred_url":"https://api.github.com/users/auth0/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/auth0/subscriptions","organizations_url":"https://api.github.com/users/auth0/orgs","repos_url":"https://api.github.com/users/auth0/repos","events_url":"https://api.github.com/users/auth0/events{/privacy}","received_events_url":"https://api.github.com/users/auth0/received_events","type":"Organization","site_admin":false},"repo":{"id":13683710,"name":"auth0-PHP","full_name":"auth0/auth0-PHP","owner":{"login":"auth0","id":2824157,"avatar_url":"https://avatars1.githubusercontent.com/u/2824157?v=4","gravatar_id":"","url":"https://api.github.com/users/auth0","html_url":"https://github.com/auth0","followers_url":"https://api.github.com/users/auth0/followers","following_url":"https://api.github.com/users/auth0/following{/other_user}","gists_url":"https://api.github.com/users/auth0/gists{/gist_id}","starred_url":"https://api.github.com/users/auth0/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/auth0/subscriptions","organizations_url":"https://api.github.com/users/auth0/orgs","repos_url":"https://api.github.com/users/auth0/repos","events_url":"https://api.github.com/users/auth0/events{/privacy}","received_events_url":"https://api.github.com/users/auth0/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/auth0/auth0-PHP","description":"Auth0-PHP SDK","fork":false,"url":"https://api.github.com/repos/auth0/auth0-PHP","forks_url":"https://api.github.com/repos/auth0/auth0-PHP/forks","keys_url":"https://api.github.com/repos/auth0/auth0-PHP/keys{/key_id}","collaborators_url":"https://api.github.com/repos/auth0/auth0-PHP/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/auth0/auth0-PHP/teams","hooks_url":"https://api.github.com/repos/auth0/auth0-PHP/hooks","issue_events_url":"https://api.github.com/repos/auth0/auth0-PHP/issues/events{/number}","events_url":"https://api.github.com/repos/auth0/auth0-PHP/events","assignees_url":"https://api.github.com/repos/auth0/auth0-PHP/assignees{/user}","branches_url":"https://api.github.com/repos/auth0/auth0-PHP/branches{/branch}","tags_url":"https://api.github.com/repos/auth0/auth0-PHP/tags","blobs_url":"https://api.github.com/repos/auth0/auth0-PHP/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/auth0/auth0-PHP/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/auth0/auth0-PHP/git/refs{/sha}","trees_url":"https://api.github.com/repos/auth0/auth0-PHP/git/trees{/sha}","statuses_url":"https://api.github.com/repos/auth0/auth0-PHP/statuses/{sha}","languages_url":"https://api.github.com/repos/auth0/auth0-PHP/languages","stargazers_url":"https://api.github.com/repos/auth0/auth0-PHP/stargazers","contributors_url":"https://api.github.com/repos/auth0/auth0-PHP/contributors","subscribers_url":"https://api.github.com/repos/auth0/auth0-PHP/subscribers","subscription_url":"https://api.github.com/repos/auth0/auth0-PHP/subscription","commits_url":"https://api.github.com/repos/auth0/auth0-PHP/commits{/sha}","git_commits_url":"https://api.github.com/repos/auth0/auth0-PHP/git/commits{/sha}","comments_url":"https://api.github.com/repos/auth0/auth0-PHP/comments{/number}","issue_comment_url":"https://api.github.com/repos/auth0/auth0-PHP/issues/comments{/number}","contents_url":"https://api.github.com/repos/auth0/auth0-PHP/contents/{+path}","compare_url":"https://api.github.com/repos/auth0/auth0-PHP/compare/{base}...{head}","merges_url":"https://api.github.com/repos/auth0/auth0-PHP/merges","archive_url":"https://api.github.com/repos/auth0/auth0-PHP/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/auth0/auth0-PHP/downloads","issues_url":"https://api.github.com/repos/auth0/auth0-PHP/issues{/number}","pulls_url":"https://api.github.com/repos/auth0/auth0-PHP/pulls{/number}","milestones_url":"https://api.github.com/repos/auth0/auth0-PHP/milestones{/number}","notifications_url":"https://api.github.com/repos/auth0/auth0-PHP/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/auth0/auth0-PHP/labels{/name}","releases_url":"https://api.github.com/repos/auth0/auth0-PHP/releases{/id}","deployments_url":"https://api.github.com/repos/auth0/auth0-PHP/deployments","created_at":"2013-10-18T16:51:11Z","updated_at":"2018-04-24T21:50:24Z","pushed_at":"2018-05-02T22:00:51Z","git_url":"git://github.com/auth0/auth0-PHP.git","ssh_url":"git@github.com:auth0/auth0-PHP.git","clone_url":"https://github.com/auth0/auth0-PHP.git","svn_url":"https://github.com/auth0/auth0-PHP","homepage":null,"size":616,"stargazers_count":118,"watchers_count":118,"language":"PHP","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":87,"mirror_url":null,"archived":false,"open_issues_count":14,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit"},"forks":87,"open_issues":14,"watchers":118,"default_branch":"master"}},"base":{"label":"auth0:master","ref":"master","sha":"c15dbacaf6198cb421c6630d61ef9869778d43d3","user":{"login":"auth0","id":2824157,"avatar_url":"https://avatars1.githubusercontent.com/u/2824157?v=4","gravatar_id":"","url":"https://api.github.com/users/auth0","html_url":"https://github.com/auth0","followers_url":"https://api.github.com/users/auth0/followers","following_url":"https://api.github.com/users/auth0/following{/other_user}","gists_url":"https://api.github.com/users/auth0/gists{/gist_id}","starred_url":"https://api.github.com/users/auth0/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/auth0/subscriptions","organizations_url":"https://api.github.com/users/auth0/orgs","repos_url":"https://api.github.com/users/auth0/repos","events_url":"https://api.github.com/users/auth0/events{/privacy}","received_events_url":"https://api.github.com/users/auth0/received_events","type":"Organization","site_admin":false},"repo":{"id":13683710,"name":"auth0-PHP","full_name":"auth0/auth0-PHP","owner":{"login":"auth0","id":2824157,"avatar_url":"https://avatars1.githubusercontent.com/u/2824157?v=4","gravatar_id":"","url":"https://api.github.com/users/auth0","html_url":"https://github.com/auth0","followers_url":"https://api.github.com/users/auth0/followers","following_url":"https://api.github.com/users/auth0/following{/other_user}","gists_url":"https://api.github.com/users/auth0/gists{/gist_id}","starred_url":"https://api.github.com/users/auth0/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/auth0/subscriptions","organizations_url":"https://api.github.com/users/auth0/orgs","repos_url":"https://api.github.com/users/auth0/repos","events_url":"https://api.github.com/users/auth0/events{/privacy}","received_events_url":"https://api.github.com/users/auth0/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/auth0/auth0-PHP","description":"Auth0-PHP SDK","fork":false,"url":"https://api.github.com/repos/auth0/auth0-PHP","forks_url":"https://api.github.com/repos/auth0/auth0-PHP/forks","keys_url":"https://api.github.com/repos/auth0/auth0-PHP/keys{/key_id}","collaborators_url":"https://api.github.com/repos/auth0/auth0-PHP/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/auth0/auth0-PHP/teams","hooks_url":"https://api.github.com/repos/auth0/auth0-PHP/hooks","issue_events_url":"https://api.github.com/repos/auth0/auth0-PHP/issues/events{/number}","events_url":"https://api.github.com/repos/auth0/auth0-PHP/events","assignees_url":"https://api.github.com/repos/auth0/auth0-PHP/assignees{/user}","branches_url":"https://api.github.com/repos/auth0/auth0-PHP/branches{/branch}","tags_url":"https://api.github.com/repos/auth0/auth0-PHP/tags","blobs_url":"https://api.github.com/repos/auth0/auth0-PHP/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/auth0/auth0-PHP/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/auth0/auth0-PHP/git/refs{/sha}","trees_url":"https://api.github.com/repos/auth0/auth0-PHP/git/trees{/sha}","statuses_url":"https://api.github.com/repos/auth0/auth0-PHP/statuses/{sha}","languages_url":"https://api.github.com/repos/auth0/auth0-PHP/languages","stargazers_url":"https://api.github.com/repos/auth0/auth0-PHP/stargazers","contributors_url":"https://api.github.com/repos/auth0/auth0-PHP/contributors","subscribers_url":"https://api.github.com/repos/auth0/auth0-PHP/subscribers","subscription_url":"https://api.github.com/repos/auth0/auth0-PHP/subscription","commits_url":"https://api.github.com/repos/auth0/auth0-PHP/commits{/sha}","git_commits_url":"https://api.github.com/repos/auth0/auth0-PHP/git/commits{/sha}","comments_url":"https://api.github.com/repos/auth0/auth0-PHP/comments{/number}","issue_comment_url":"https://api.github.com/repos/auth0/auth0-PHP/issues/comments{/number}","contents_url":"https://api.github.com/repos/auth0/auth0-PHP/contents/{+path}","compare_url":"https://api.github.com/repos/auth0/auth0-PHP/compare/{base}...{head}","merges_url":"https://api.github.com/repos/auth0/auth0-PHP/merges","archive_url":"https://api.github.com/repos/auth0/auth0-PHP/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/auth0/auth0-PHP/downloads","issues_url":"https://api.github.com/repos/auth0/auth0-PHP/issues{/number}","pulls_url":"https://api.github.com/repos/auth0/auth0-PHP/pulls{/number}","milestones_url":"https://api.github.com/repos/auth0/auth0-PHP/milestones{/number}","notifications_url":"https://api.github.com/repos/auth0/auth0-PHP/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/auth0/auth0-PHP/labels{/name}","releases_url":"https://api.github.com/repos/auth0/auth0-PHP/releases{/id}","deployments_url":"https://api.github.com/repos/auth0/auth0-PHP/deployments","created_at":"2013-10-18T16:51:11Z","updated_at":"2018-04-24T21:50:24Z","pushed_at":"2018-05-02T22:00:51Z","git_url":"git://github.com/auth0/auth0-PHP.git","ssh_url":"git@github.com:auth0/auth0-PHP.git","clone_url":"https://github.com/auth0/auth0-PHP.git","svn_url":"https://github.com/auth0/auth0-PHP","homepage":null,"size":616,"stargazers_count":118,"watchers_count":118,"language":"PHP","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":87,"mirror_url":null,"archived":false,"open_issues_count":14,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit"},"forks":87,"open_issues":14,"watchers":118,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/auth0/auth0-PHP/pulls/253"},"html":{"href":"https://github.com/auth0/auth0-PHP/pull/253"},"issue":{"href":"https://api.github.com/repos/auth0/auth0-PHP/issues/253"},"comments":{"href":"https://api.github.com/repos/auth0/auth0-PHP/issues/253/comments"},"review_comments":{"href":"https://api.github.com/repos/auth0/auth0-PHP/pulls/253/comments"},"review_comment":{"href":"https://api.github.com/repos/auth0/auth0-PHP/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/auth0/auth0-PHP/pulls/253/commits"},"statuses":{"href":"https://api.github.com/repos/auth0/auth0-PHP/statuses/f10484dc61954956db247eb052b8b15e9d859e3e"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"lbalmaceda"}}