[
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    types: [opened, synchronize, reopened]\njobs:\n  sonarcloud:\n    name: SonarCloud\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis\n      - name: SonarCloud Scan\n        uses: SonarSource/sonarcloud-github-action@master\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}  # Needed to get PR information, if any\n          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "composer.lock\n/vendor\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: php\n\nsudo: false\n\ngit:\n  depth: 2\n\nmatrix:\n  include:\n    - php: 7.0\n    - php: 7.1\n    - php: 7.2\n    - php: nightly\n  fast_finish: true\n\ncache:\n  directories:\n    - $HOME/.composer/cache\n\nbefore_script:\n  - phpenv config-rm xdebug.ini || true\n  - travis_retry composer self-update\n  - travis_retry composer install --no-interaction\n\nscript:\n  - composer test\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nContributions are **welcome** and will be fully **credited**.\n\nWe accept contributions via Pull Requests on [Github](https://github.com/codecasts/laravel-jwt).\n\n\n## Pull Requests\n\n- Follow the **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)**.\n\n- **Add tests!** - Your patch won't be accepted if it doesn't have tests.\n\n- **Document any change in behaviour** - Make sure the `readme.md` and any other relevant documentation are kept up-to-date.\n\n- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.\n\n- **Create feature branches** - Don't ask us to pull from your master branch.\n\n- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.\n\n- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting.\n\n- **Branch** - This is a **GIT FLOW** enabled repository, so please send your pull requests to our `develop` branch.\n\n## Running Tests\n\n``` bash\n$ composer test\n```\n\n**Happy coding**!\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "MIT License\n\nCopyright (c) 2017 Diego Hernandes <diego@hernandev.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"codecasts/laravel-jwt\",\n    \"description\": \"Dead simple JWT Auth Provider for Laravel 5.4+\",\n    \"type\": \"library\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Diego Hernandes\",\n            \"email\": \"diego@hernandev.com\"\n        }\n    ],\n    \"autoload\": {\n        \"psr-4\": {\n            \"Codecasts\\\\Auth\\\\JWT\\\\\": \"src/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Tests\\\\\": \"tests/\"\n        }\n    },\n    \"minimum-stability\": \"stable\",\n    \"require\": {\n        \"php\": \">=7.0.0\",\n        \"ext-openssl\": \"*\",\n        \"lcobucci/jwt\": \"^3.2\",\n        \"illuminate/support\": \">=5.4.0\"\n    },\n    \"require-dev\": {\n        \"orchestra/testbench\": \"^3.4\",\n        \"phpunit/phpunit\": \"^6.1\",\n        \"mockery/mockery\": \"^0.9.9\"\n    },\n    \"extra\": {\n        \"laravel\": {\n            \"providers\": [\n                \"Codecasts\\\\Auth\\\\JWT\\\\ServiceProvider\"\n            ]\n        }\n    }\n}\n"
  },
  {
    "path": "config/jwt.php",
    "content": "<?php\n\n    /*\n    |--------------------------------------------------------------------------\n    | GENERAL WARNING. DO NOT USE THIS PACKAGE WITHOUT READING THIS.\n    |--------------------------------------------------------------------------\n    |\n    | It's 2017. JWT are a (not so much) new and simple way of authenticating your\n    | users either you're building a SPA + API or Mobile + API app.\n    |\n    | It's great you took interest in this package, but you should take real care\n    | about the following things:\n    |\n    | As I was saying. It's 2017. JWT SHOULD NOT BE USED on a API WITHOUT HTTPS.\n    | By HTTP, I mean TLS 1.1+.\n    | SSL 3.0 and lower are proven insecure actually a couple of years ago.\n    |\n    | With that in mind, enjoy this. It was made with love with minimalism in mind.\n    */\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | JWT Secret\n    |--------------------------------------------------------------------------\n    |\n    | This package uses HMAC-SHA265 as default signature mechanism.\n    | HMAC-256 is pretty secure and straightforward when using a 32 bytes long key.\n    | Since this package aims to be really simple, the crypt algorithm and key length\n    | will be hardcoded instead of configurable.\n    |\n    | This will be like this by design, it will provide strong security for any API\n    | while preventing people from making a mess and turning JWT less secure.\n    |\n    | NOTICE: ONLY USE KEYS GENERATED BY THE COMMAND\n    |\n    | php artisan jwt:generate\n    |\n    | If you don't, don't blame me latter.\n    |\n    | P.S. Don't blame me in any case :).\n    */\n\n    'secret'   => env('JWT_SECRET', null),\n\n    /*\n    |--------------------------------------------------------------------------\n    | JWT Time to live (TTL)\n    |--------------------------------------------------------------------------\n    |\n    | Use an Integer value in minutes.\n    |\n    | This will set how long will take for a key to be considered expired.\n    | In other words, this is the amount of time, in minutes, that will be\n    | added to the current time that the token is being issue and set\n    | ont the 'exp' claim.\n    |\n    */\n    'ttl'  => 60,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Expired Token Refresh Limit\n    |--------------------------------------------------------------------------\n    |\n    | Use an Integer value in minutes.\n    |\n    | This will set how long after the expiration date a token can be refreshed.\n    | You can set it to 0 if you DO NOT want expired tokens to refreshed.\n    |\n    | The default limit of 7200 (minutes) takes in account mobile apps where the\n    | logged used may take a few days before using your \"app\" again.\n    |\n    | In those cases, the token would have been expired but a new one could still\n    | be issued, unless the limit configured here has already passed.\n    |\n    | If you're considering a not secure client platform, short values here reduces\n    | the odds of a leaked token be used to generate a new one.\n    |\n    */\n\n    'refresh_limit' => 7200,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Auto Guard Binding By Middleware Match\n    |--------------------------------------------------------------------------\n    |\n    | Useful when your application has more than 1 guard, and the JWT powered one\n    | is not the default.\n    |\n    | If your application is a API only, you can safely set this to false.\n    |\n    | Setting it to false without having JWT guard as default will make\n    | mandatory using the suffix :guardName when using the 'auth' middleware.\n    |\n    */\n\n    'middleware_match' => true,\n\n];"
  },
  {
    "path": "phpunit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit backupGlobals=\"false\"\n         backupStaticAttributes=\"false\"\n         bootstrap=\"vendor/autoload.php\"\n         colors=\"true\"\n         convertErrorsToExceptions=\"true\"\n         convertNoticesToExceptions=\"true\"\n         convertWarningsToExceptions=\"true\"\n         processIsolation=\"false\"\n         stopOnFailure=\"true\"\n         syntaxCheck=\"false\">\n    <testsuites>\n        <testsuite name=\"LaravelJwt Test Suite\">\n            <directory>tests/</directory>\n        </testsuite>\n    </testsuites>\n    <filter>\n        <whitelist>\n            <directory suffix=\".php\">src/</directory>\n        </whitelist>\n    </filter>\n</phpunit>\n"
  },
  {
    "path": "readme.md",
    "content": "\n![Readme Art](http://imageshack.com/a/img922/4489/tftxQ1.png)\n\n# Laravel JWT\n\n[![Latest Stable Version](https://poser.pugx.org/codecasts/laravel-jwt/v/stable)](https://packagist.org/packages/codecasts/laravel-jwt)\n[![Total Downloads](https://poser.pugx.org/codecasts/laravel-jwt/downloads)](https://packagist.org/packages/codecasts/laravel-jwt)\n[![License](https://poser.pugx.org/codecasts/laravel-jwt/license)](https://packagist.org/packages/codecasts/laravel-jwt)\n\nThis package provides out-of-the-box API authentication using JWT for Laravel.\n\n## Installation.\n\nYou can install this package by running:\n\n```bash\ncomposer require codecasts/laravel-jwt\n```\n\n## Setup.\n\nIn order to setup this package into your application, minimal configuration\nis actually needed.\n\n### 1) Service Provider.\n\nRegister this package's Service Provider by adding it to the `providers`\nsection of your `config/app.php` file:\n\n> You may skip this step on Laravel 5.5 due to the [auto-discovery package feature](https://laravel.com/docs/5.5/packages#package-discovery).\n\n```php\n   'providers' => [\n\n       // ... other providers omitted\n\n       Codecasts\\Auth\\JWT\\ServiceProvider::class,\n\n   ],\n```\n\n### 2) Configuration file.\n\nPublish the configuration file (`config/jwt.php`) by running the\nfollowing command after registering the Service Provider.\n\n```bash\nphp artisan vendor:publish --provider=\"Codecasts\\Auth\\JWT\\ServiceProvider\"\n```\n\n### 3) Generate a Secret.\n\nIn order for this package to works, you will need a separate secret\n(do not use the application key).\n\nThis package provides a command that can be used for generating a strong key.\n\nGet a new key by running:\n\n```bash\nphp artisan jwt:generate\n```\n\nThen, copy the generated key contents into your `.env` file.\n\n**NOTICE**: The key generation process will not automatically\nset it inside your `.env` file, do it manually.\n\n### 4) Setup Guard\n\nIn order to automatically authenticate your routes using `JWT` tokens,\nyou need to change the guard driver to `jwt`\n\nInside `config/auth.php` set the corresponding guard group you want to protect:\n\nIf you have the default guard group named `api`, your `auth.php`\nshould be like this:\n\n```php\n  'guards' => [\n        // ... other guards omitted.\n\n        'api' => [\n            'driver'   => 'jwt', // this is the line you need to change.\n            'provider' => 'users',\n        ],\n    ],\n```\n\nThat's it, we are all ready to use it.\n\n\n\n## Usage.\n\nThis package aims to be dead simple to use.\n\nThe following templates can be used to setup your existing\nauthentication controllers and resources.\n\n**NOTICE**: Full working examples of use for this package\nwill be added on this package when it reaches it's 1.0 version.\n\n### Protecting Routes.\n\nThis package is fully integrated with Laravel Authentication.\n\nThe default configuration (`config/jwt.php`) brings a sensitive value that\nis very useful when your application is not completely an API: **`middleware_match`**\n\nBy not completely an API, I mean, the JWT guard is not the default one.\n\nIn those cases, in order to use the `auth` middleware, the config key\n**`middleware_match`** **MUST** be set to true.\n\nThis configuration key allows non protected routes to work properly.\n\nNotice that this option will match middleware group names with guard names.\n\n**In this case, the 'api' middleware group will always use the `api` guard.**\n\n**Also, the 'web' middleware group will always use the `web` guard**\n\nIf you do not use this value, you will need to use suffixes when referencing the\n`auth` middleware, like `auth:api`.\n\n\n### Issuing and Renewing Tokens.\n\nFor issuing tokens, no special class is actually needed,\nyou can just expect create a Guard current implementation from the IoC and work from there.\n\nCheck out the examples.\n\n\n**On the following examples, all Guard instances are injected from `Illuminate\\Contracts\\Auth\\Guard`**\n\n**On the following examples, all Request instances are injected from  `Illuminate\\Http\\Request`**\n\n#### Token from User Instance.\n\nThis method should be used when you just registered a user and any other\nspecial cases.\n\n```php\n\npublic function tokenFromUser(Guard $auth)\n{\n    // generating a token from a given user.\n    $user = SomeUserModel::find(12);\n\n    // logs in the user\n    $auth->login($user);\n\n    // get and return a new token\n    $token = $auth->issue();\n\n    return $token;\n}\n\n```\n\n#### Token from User Credentials.\n\nThis method should be used when you just registered a user and any other\nspecial cases.\n\n```php\n\npublic function tokenFromCredentials(Guard $auth, Request $request)\n{\n    // get some credentials\n    $credentials = $request->only(['email', 'password']);\n\n    if ($auth->attempt($credentials)) {\n       return $token = $auth->issue();\n    }\n\n    return ['Invalid Credentials'];\n}\n\n```\n\n#### Refreshing Tokens.\n\nTokens can be refreshed in 2 different ways: Auto detect or manual.\n\nIf you do not pass any argument into the refresh method, the Guard will\nlook for either a **`Authorization`** header or a **`token`** field on the\nrequest's body.\n\n```php\n\npublic function refreshToken(Guard $auth)\n{\n    // auto detecting token from request.\n    $token = $auth->refresh();\n\n    // manually passing the token to be refreshed.\n    $token = $auth->refresh($oldToken);\n\n    return $token;\n}\n```\n\n### Custom Claims.\n\nOf course, there are support for custom claims.\n\nYou can set them in two ways.\n\n#### By explicitly passing them.\n\n```php\n\n$customClaims = [\n    'custom1' => 'value1',\n    'custom2' => 'value2',\n];\n\n// when issuing\n$auth->issue($customClaims);\n\n// when refreshing\n// custom claims are the second parameter as the first one is the\n// old token\n$auth->refresh(null, $customClaims);\n\n```\n\n#### By Authenticatable method.\n\nIf all your users will have the same custom claims, you can setup a default\ncustom claims method on your User's model (or any other Authenticatable you're using):\n\nIf the method `customJWTClaims()` is present on the model being issue the token against,\nthis claims will be automatically included.\n\n```php\n\nclass User extends Model implements Authenticatable\n{\n    public function customJWTClaims()\n    {\n        return [\n            'email' => $this->email,\n            'name'  => $this->name,\n        ];\n    }\n}\n```\n\n## Contributing\n\nPlease see [CONTRIBUTING](CONTRIBUTING.md) for details.\n"
  },
  {
    "path": "sonar-project.properties",
    "content": "sonar.projectKey=codecasts_laravel-jwt\nsonar.organization=codecasts\n\n# This is the name and version displayed in the SonarCloud UI.\n#sonar.projectName=laravel-jwt\n#sonar.projectVersion=1.0\n\n# Path is relative to the sonar-project.properties file. Replace \"\\\" by \"/\" on Windows.\n#sonar.sources=.\n\n# Encoding of the source code. Default is default system encoding\n#sonar.sourceEncoding=UTF-8\n"
  },
  {
    "path": "src/Auth/Guard.php",
    "content": "<?php\n\nnamespace Codecasts\\Auth\\JWT\\Auth;\n\nuse Illuminate\\Auth\\Events\\Attempting;\nuse Illuminate\\Auth\\Events\\Failed;\nuse Illuminate\\Auth\\Events\\Login;\nuse Illuminate\\Auth\\GuardHelpers;\nuse Illuminate\\Contracts\\Auth\\Authenticatable;\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Illuminate\\Support\\Str;\nuse Codecasts\\Auth\\JWT\\Contracts\\Auth\\Guard as GuardContract;\nuse Lcobucci\\JWT\\Token;\n\n/**\n * JWT Guard class.\n *\n * This class is responsible for actually authenticating requests that\n * comes with a token (or denying those without a token or with a\n * invalid one).\n */\nclass Guard implements GuardContract\n{\n    // this trait bootstrap some common guard methods\n    // so we just need to implement a few ones.\n    use GuardHelpers;\n\n    /**\n     * @var \\Illuminate\\Contracts\\Foundation\\Application\n     */\n    protected $app;\n\n    /**\n     * Guard / Provider name.\n     *\n     * @var string\n     */\n    protected $name;\n\n    /**\n     * The currently authenticated user.\n     *\n     * @var \\Illuminate\\Contracts\\Auth\\Authenticatable\n     */\n    protected $user;\n\n    /**\n     * The user provider implementation.\n     *\n     * @var \\Illuminate\\Contracts\\Auth\\UserProvider\n     */\n    protected $provider;\n\n\n    /**\n     * The token manager implementation.\n     *\n     * @var \\Codecasts\\Auth\\JWT\\Contracts\\Token\\Manager\n     */\n    protected $manager;\n\n    /**\n     * Used to allow checks just after logout.\n     *\n     * In a JWT scenario, logged out means there was an explicit action\n     * to log out the user and the token has been blacklisted.\n     *\n     * @var bool\n     */\n    protected $loggedOut = false;\n\n    /**\n     * The event dispatcher instance.\n     *\n     * @var \\Illuminate\\Contracts\\Events\\Dispatcher\n     */\n    protected $events;\n\n    /**\n     * The current Request;\n     *\n     * @var \\Symfony\\Component\\HttpFoundation\\Request\n     */\n    protected $request;\n\n    /**\n     * The user we last attempted to retrieve.\n     *\n     * @var \\Illuminate\\Contracts\\Auth\\Authenticatable\n     */\n    protected $lastAttempted;\n\n    /**\n     * The detected JWT token.\n     *\n     * @var Token|null\n     */\n    protected $token = null;\n\n    /**\n     * JWT Guard constructor.\n     *\n     * @param \\Illuminate\\Contracts\\Foundation\\Application $app\n     * @param string $name\n     * @param \\Illuminate\\Contracts\\Auth\\UserProvider $provider\n     * @param \\Codecasts\\Auth\\JWT\\Contracts\\Token\\Manager $manager\n     */\n    public function __construct($app, $name, $provider, $manager)\n    {\n        // assign constructor arguments into instance scope.\n        $this->app = $app;\n        $this->name = $name;\n        $this->provider = $provider;\n        $this->manager = $manager;\n    }\n\n    /**\n     * Fire the attempt event with the arguments.\n     *\n     * @param  array  $credentials\n     * @return void\n     */\n    protected function fireAttemptEvent(array $credentials)\n    {\n        if (isset($this->events)) {\n            $this->events->dispatch(new Attempting(\n                $credentials, false\n            ));\n        }\n    }\n\n    /**\n     * Fire the failed authentication attempt event with the given arguments.\n     *\n     * @param  \\Illuminate\\Contracts\\Auth\\Authenticatable|null  $user\n     * @param  array  $credentials\n     * @return void\n     */\n    protected function fireFailedEvent($user, array $credentials)\n    {\n        if (isset($this->events)) {\n            $this->events->dispatch(new Failed($user, $credentials));\n        }\n    }\n\n    /**\n     * Fire the login event if the dispatcher is set.\n     *\n     * @param  \\Illuminate\\Contracts\\Auth\\Authenticatable  $user\n     *\n     * @return void\n     */\n    protected function fireLoginEvent($user)\n    {\n        if (isset($this->events)) {\n            $this->events->dispatch(new Login($user, false));\n        }\n    }\n\n    /**\n     * Validate a user's credentials.\n     *\n     * @param  array  $credentials\n     * @return bool\n     */\n    public function validate(array $credentials = [])\n    {\n        $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);\n\n        return $this->hasValidCredentials($user, $credentials);\n    }\n\n    /**\n     * Attempt to authenticate a user using the given credentials.\n     *\n     * @param  array $credentials\n     * @return bool\n     */\n    public function attempt(array $credentials = [])\n    {\n        $this->fireAttemptEvent($credentials);\n\n        $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);\n\n        // If an implementation of UserInterface was returned, we'll ask the provider\n        // to validate the user against the given credentials, and if they are in\n        // fact valid we'll log the users into the application and return true.\n        if ($this->hasValidCredentials($user, $credentials)) {\n            $this->login($user);\n\n            return true;\n        }\n\n        // If the authentication attempt fails we will fire an event so that the user\n        // may be notified of any suspicious attempts to access their account from\n        // an unrecognized user. A developer may listen to this event as needed.\n        $this->fireFailedEvent($user, $credentials);\n\n        return false;\n    }\n\n    /**\n     * Determine if the user matches the credentials.\n     *\n     * @param  mixed  $user\n     * @param  array  $credentials\n     * @return bool\n     */\n    protected function hasValidCredentials($user, $credentials)\n    {\n        return ! is_null($user) && $this->provider->validateCredentials($user, $credentials);\n    }\n\n    /**\n     * Login a given user. It means, generate a new token for a user.\n     *\n     * @param Authenticatable $user\n     * @return mixed\n     */\n    public function login(Authenticatable $user)\n    {\n        // If we have an event dispatcher instance set we will fire an event so that\n        // any listeners will hook into the authentication events and run actions\n        // based on the login and logout events fired from the guard instances.\n        $this->fireLoginEvent($user);\n\n        $this->setUser($user);\n    }\n\n    /**\n     * Parse the request looking for the authorization header.\n     *\n     * @return null|string\n     */\n    protected function getTokenFromHeader()\n    {\n        // if there is no authorization header present.\n        if (!$this->getRequest()->headers->has('Authorization')) {\n            // abort by returning null.\n            return null;\n        }\n\n        // gets the full header string.\n        $header = $this->getRequest()->headers->get('Authorization');\n\n        // returns the token without the 'Bearer ' prefix.\n        return Str::replaceFirst('Bearer ', '', $header);\n    }\n\n    /**\n     * Parse the request looking a token as parameter.\n     *\n     * @return null|string\n     */\n    protected function getTokenFromParameter()\n    {\n        if (!$this->getRequest()->has('token')) {\n            // abort by returning null.\n            return null;\n        }\n\n        //  return the request token.\n        return $this->getRequest()->get('token', null);\n    }\n\n    /**\n     * @return Token|null\n     */\n    protected function detectedToken()\n    {\n        // retrieve the token from request.\n        $detectedToken = $this->getTokenFromHeader() ?? $this->getTokenFromParameter();\n\n        if ($detectedToken) {\n            // update the currently used token\n            $this->token = $this->manager()->parseToken($detectedToken);\n        }\n\n        // return current token in use\n        return $this->token;\n    }\n\n    /**\n     * Retrieves the user by it's token.\n     *\n     * @param Token $token\n     * @return Authenticatable|null\n     */\n    protected function findUserByToken(Token $token)\n    {\n        // retrieves the user ID from the token.\n        $id = $token->getClaim('sub');\n\n        // use the users provider to find the token subject (user)\n        // but it's id (subject)\n        return $this->provider->retrieveById($id);\n    }\n\n    /**\n     * Get / Detect the currently authenticated user.\n     *\n     * @return \\Illuminate\\Contracts\\Auth\\Authenticatable|null\n     */\n    public function user()\n    {\n        // if the user was explicitly marked as logged out.\n        if ($this->loggedOut) {\n            // just return null.\n            return null;\n        }\n\n        // if the user is already set.\n        if ($this->user) {\n            return $this->user;\n        }\n\n        // detects a token presence.\n        $token = $this->detectedToken();\n\n        // if the received token is not actually valid.\n        if (!$token || !$this->manager->validToken($token)) {\n            // also return null since the token\n            // signature could not be determined.\n            return null;\n        }\n\n        // if the token has expired.\n        if ($this->manager->expired($token)) {\n            // you got right?\n            return null;\n        }\n\n        // try to find the user which the token belongs to.\n        $user = $this->findUserByToken($token);\n\n        // if the user has not been found.\n        if (!$user) {\n            // abort!\n            return null;\n        }\n\n        // set the current user on the scope.\n        $this->setUser($user);\n\n        // return the scope user.\n        return $this->user;\n    }\n\n    /**\n     * Log the user out of the application.\n     *\n     * @return void\n     */\n    public function logout()\n    {\n        $user = $this->user();\n\n        // blacklist the user token.\n\n        $this->loggedOut = true;\n    }\n\n    /**\n     * Returns the guard instance of the token manager.\n     *\n     * @return \\Codecasts\\Auth\\JWT\\Contracts\\Token\\Manager\n     */\n    public function manager()\n    {\n        return $this->manager;\n    }\n\n    /**\n     * Issue a token for the current authenticated user.\n     *\n     * @param array $customClaims\n     * @return bool|string\n     */\n    public function issue(array $customClaims = [])\n    {\n        // ensure there is a user logged in.\n        if (!$this->user) {\n            return false;\n        }\n\n        // try to issue a new token and return.\n        try {\n            return $this->manager()->issue($this->user, $customClaims);\n        } catch (\\Exception $e) {\n            // catch any exceptions that the token issuing may trigger.\n            return false;\n        }\n    }\n\n    /**\n     * Refresh a given token.\n     *\n     * @param string $token\n     * @param array  $customClaims\n     * @return bool|string\n     */\n    public function refresh(string $token = null, array $customClaims = [])\n    {\n        // detect token if none was passed.\n        $token = $token ?? $this->detectedToken();\n\n        // if no token was detected.\n        if (!$token) {\n            return false;\n        }\n\n        // if the token cannot be refreshed.\n        if (!$this->manager()->canBeRenewed($token)) {\n            // abort by returning false.\n            return false;\n        }\n\n        // try to locate the user which the token belongs to.\n        $user = $this->findUserByToken($token);\n\n        // if not user could be found.\n        if (!$user) {\n            return false;\n        }\n\n        // set the user instance.\n        $this->user = $user;\n\n        // try to issue a new token and refresh\n        try {\n            return $this->manager()->issue($user, $customClaims);\n        } catch (\\Exception $e) {\n            return false;\n        }\n    }\n\n    /**\n     * Get the event dispatcher instance.\n     *\n     * @return \\Illuminate\\Contracts\\Events\\Dispatcher\n     */\n    public function getDispatcher()\n    {\n        return $this->events;\n    }\n\n    /**\n     * Set the event dispatcher instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Events\\Dispatcher  $events\n     * @return void\n     */\n    public function setDispatcher(Dispatcher $events)\n    {\n        $this->events = $events;\n    }\n\n    /**\n     * Get the current request instance.\n     *\n     * @return \\Symfony\\Component\\HttpFoundation\\Request\n     */\n    public function getRequest()\n    {\n        return $this->request ?: $this->app->request;\n    }\n\n    /**\n     * Set the current request instance.\n     *\n     * @param  \\Symfony\\Component\\HttpFoundation\\Request  $request\n     * @return $this\n     */\n    public function setRequest(Request $request)\n    {\n        $this->request = $request;\n\n        return $this;\n    }\n\n    /**\n     * The detected JWT token.\n     *\n     * @return string\n     */\n    public function getToken()\n    {\n        return $this->token;\n    }\n\n}"
  },
  {
    "path": "src/Auth/ServiceProvider.php",
    "content": "<?php\n\nnamespace Codecasts\\Auth\\JWT\\Auth;\n\nuse Illuminate\\Contracts\\Auth\\UserProvider;\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Illuminate\\Foundation\\Support\\Providers\\AuthServiceProvider;\nuse Codecasts\\Auth\\JWT\\Contracts\\Token\\Manager as TokenManager;\nuse Illuminate\\Auth\\AuthManager;\n\n/**\n * Service provider to register the 'jwt' auth guard.\n */\nclass ServiceProvider extends AuthServiceProvider\n{\n    /**\n     * Laravel auth manager that will be needed to register the guard.\n     *\n     * @var AuthManager\n     */\n    protected $authManager = null;\n\n    /**\n     * Register Guard.\n     */\n    public function register()\n    {\n        // gets the auth factory instance and register on provider attribute.\n        $this->authManager = $this->app->make(AuthManager::class);\n\n        // register auth policies.\n        $this->registerPolicies();\n\n        // define a \"jwt\" guard.\n        $this->authManager->extend('jwt', function ($app, $name, array $config) {\n            // gets a instance of the token manager\n            $tokenManager = $this->getTokenManager();\n\n            // gets a instance of the user provider\n            $userProvider = $this->getUserProvider($config['provider']);\n\n            // creates a new guard instance passing a provider and a token manager\n            $guard = new Guard($app, $name, $userProvider, $tokenManager);\n\n            // set a event dispatcher on the guard.\n            $guard->setDispatcher(resolve(Dispatcher::class));\n\n            // returns the guard instance.\n            return new Guard($app, $name, $userProvider, $tokenManager);\n        });\n    }\n\n    /**\n     * Get's the configured user provider instance.\n     *\n     * @param $alias\n     * @return UserProvider\n     */\n    protected function getUserProvider($alias)\n    {\n        return $this->authManager->createUserProvider($alias);\n    }\n\n    /**\n     * Get's a instance of the token manager.\n     *\n     * @return \\Codecasts\\Auth\\JWT\\Contracts\\Token\\Manager\n     */\n    protected function getTokenManager()\n    {\n        return $this->app->make(TokenManager::class);\n    }\n}\n"
  },
  {
    "path": "src/Console/KeyGenerateCommand.php",
    "content": "<?php\n\nnamespace Codecasts\\Auth\\JWT\\Console;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Console\\ConfirmableTrait;\nuse Symfony\\Component\\Console\\Helper\\FormatterHelper;\n\n/**\n * Class GenerateKey.\n *\n * Command that helps generating a strong key to be used as HMAC-SHA256 key.\n */\nclass KeyGenerateCommand extends Command\n{\n    use ConfirmableTrait;\n\n    /**\n     * The name and signature of the console command.\n     *\n     * @var string\n     */\n    protected $signature = 'jwt:generate\n            {--show : Display the key instead of modifying files}\n            {--force : Force the operation to run when in production}';\n\n    /**\n     * Make it 5.4 compatible.\n     */\n    public function fire()\n    {\n        $this->handle();\n    }\n\n    /**\n     * Execute the command that will generate and print a key.\n     */\n    public function handle()\n    {\n        // call the action to generate a new key.\n        $key = $this->generateRandomKey();\n\n        if ($this->option('show')) {\n            // print the success block.\n            $this->printBlock([\n                'JWT Key Generated!',\n                'Please Update your .env file manually with the following key:',\n            ], 'bg=green;fg=black', true);\n\n            // print the key block.\n            return $this->printBlock([\n                \"JWT_SECRET={$key}\",\n            ], 'bg=yellow;fg=black');\n        }\n\n        // Next, we will replace the application key in the environment file so it is\n        // automatically setup for this developer. This key gets generated using a\n        // secure random byte generator and is later base64 encoded for storage.\n        if (!$this->setKeyInEnvironmentFile($key)) {\n            return;\n        }\n\n        $this->laravel['config']['jwt.secret'] = $key;\n\n        // print the key block.\n        $this->printBlock([\n            \"JWT_SECRET={$key}\",\n        ], 'bg=yellow;fg=black');\n    }\n\n    /**\n     * Set the application key in the environment file.\n     *\n     * @param string $key\n     *\n     * @return bool\n     */\n    protected function setKeyInEnvironmentFile($key)\n    {\n        $currentKey = $this->laravel['config']['jwt.secret'];\n\n        if (0 !== strlen($currentKey) && (!$this->confirmToProceed())) {\n            return false;\n        }\n\n        $this->writeNewEnvironmentFileWith($key);\n\n        return true;\n    }\n\n    /**\n     * Write a new environment file with the given key.\n     *\n     * @param string $key\n     */\n    protected function writeNewEnvironmentFileWith($key)\n    {\n        file_put_contents($this->laravel->environmentFilePath(), preg_replace(\n                $this->keyReplacementPattern(),\n                'JWT_SECRET='.$key,\n                file_get_contents($this->laravel->environmentFilePath())\n            ));\n    }\n\n    /**\n     * Generates a random, 32 bytes long, base64 encoded key.\n     *\n     * @return string\n     */\n    protected function generateRandomKey()\n    {\n        return 'base64:'.base64_encode(random_bytes(32));\n    }\n\n    /**\n     * Prints a text block into console output.\n     *\n     * @param array $lines\n     * @param $style\n     * @param bool $firstBlock\n     */\n    protected function printBlock(array $lines, $style, $firstBlock = false)\n    {\n        /** @var FormatterHelper $formatter */\n        $formatter = $this->getHelper('formatter');\n\n        // just to satisfy my obsessive needs.\n        if ($firstBlock) {\n            // prints an empty line at the begging of output.\n            $this->line('');\n        }\n\n        // merge argument lines with an empty line before and after.\n        $spacedLines = array_merge([''], array_merge($lines, ['']));\n        // generate a text block.\n        $block = $formatter->formatBlock($spacedLines, $style);\n\n        // print it.\n        $this->line($block);\n\n        // empty ending line.\n        $this->line('');\n    }\n\n    /**\n     * Get a regex pattern that will match env APP_KEY with any random key.\n     *\n     * @return string\n     */\n    protected function keyReplacementPattern()\n    {\n        $escaped = preg_quote('='.$this->laravel['config']['jwt.secret'], '/');\n\n        return \"/^JWT_SECRET{$escaped}/m\";\n    }\n}\n"
  },
  {
    "path": "src/Contracts/Auth/Guard.php",
    "content": "<?php\n\nnamespace Codecasts\\Auth\\JWT\\Contracts\\Auth;\n\nuse Illuminate\\Contracts\\Auth\\Authenticatable;\nuse Illuminate\\Contracts\\Auth\\Guard as LaravelGuard;\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Codecasts\\Auth\\JWT\\Contracts\\Token\\Manager;\nuse Symfony\\Component\\HttpFoundation\\Request;\n\ninterface Guard extends LaravelGuard\n{\n    /**\n     * JWT Guard constructor.\n     *\n     * @param \\Illuminate\\Contracts\\Foundation\\Application $app\n     * @param string $name\n     * @param \\Illuminate\\Contracts\\Auth\\UserProvider $provider\n     * @param \\Codecasts\\Auth\\JWT\\Contracts\\Token\\Manager $manager\n     */\n    public function __construct($app, $name, $provider, $manager);\n\n    /**\n     * @param array $credentials\n     * @return mixed\n     */\n    public function validate(array $credentials = []);\n\n    /**\n     * Attempt to authenticate a user using the given credentials.\n     *\n     * @param  array  $credentials\n     * @return bool\n     */\n    public function attempt(array $credentials = []);\n\n    /**\n     * Log a user into the application.\n     *\n     * @param  \\Illuminate\\Contracts\\Auth\\Authenticatable  $user\n     * @return void\n     */\n    public function login(Authenticatable $user);\n\n    /**\n     * Log the user out of the application.\n     *\n     * @return void\n     */\n    public function logout();\n\n    /**\n     * Returns the guard instance of the token manager.\n     *\n     * @return Manager\n     */\n    public function manager();\n\n    /**\n     * Refresh a given token.\n     *\n     * @param string $token\n     * @param array  $customClaims\n     * @return bool|string\n     */\n    public function refresh(string $token = null, array $customClaims = []);\n\n    /**\n     * Issue a token for the current authenticated user.\n     *\n     * @param array $customClaims\n     * @return bool|string\n     */\n    public function issue(array $customClaims = []);\n\n    /**\n     * Get the event dispatcher instance.\n     *\n     * @return \\Illuminate\\Contracts\\Events\\Dispatcher\n     */\n    public function getDispatcher();\n\n    /**\n     * Set the event dispatcher instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Events\\Dispatcher  $events\n     * @return void\n     */\n    public function setDispatcher(Dispatcher $events);\n\n    /**\n     * Get the current request instance.\n     *\n     * @return \\Symfony\\Component\\HttpFoundation\\Request\n     */\n    public function getRequest();\n\n    /**\n     * Set the current request instance.\n     *\n     * @param  \\Symfony\\Component\\HttpFoundation\\Request  $request\n     * @return $this\n     */\n    public function setRequest(Request $request);\n}"
  },
  {
    "path": "src/Contracts/Token/Manager.php",
    "content": "<?php\n\nnamespace Codecasts\\Auth\\JWT\\Contracts\\Token;\n\nuse \\Illuminate\\Cache\\Repository as Cache;\nuse \\Illuminate\\Config\\Repository as Config;\nuse Illuminate\\Contracts\\Auth\\Authenticatable;\nuse Lcobucci\\JWT\\Token;\n\ninterface Manager\n{\n    /**\n     * Token Manager constructor.\n     *\n     * @param \\Illuminate\\Config\\Repository  $config\n     * @param \\Illuminate\\Cache\\Repository   $cache\n     */\n    public function __construct(Config $config, Cache $cache);\n\n    /**\n     * Setup the secret that will be used to sign keys.\n     */\n    public function setupSecret();\n\n    /**\n     * @param Authenticatable $user\n     * @param array $customClaims\n     *\n     * @return string\n     */\n    public function issue(Authenticatable $user, array $customClaims = []);\n\n    /**\n     * Method for parsing a token from a string.\n     *\n     * @param string $tokenString\n     *\n     * @return Token\n     */\n    public function parseToken(string $tokenString);\n\n    /**\n     * Detects if a given token is valid or not.\n     *\n     * @param Token $token\n     *\n     * @return bool\n     */\n    public function validToken(Token $token);\n\n    /**\n     * Detects if a given token is Invalid.\n     *\n     * @param Token $token\n     * @return bool\n     */\n    public function invalidToken(Token $token);\n\n    /**\n     * Is the token Expired?\n     *\n     * @param Token $token\n     * @return bool\n     */\n    public function expired(Token $token);\n\n    /**\n     * Is the token Expired?\n     *\n     * @param Token $token\n     * @return bool\n     */\n    public function canBeRenewed(Token $token);\n}"
  },
  {
    "path": "src/ServiceProvider.php",
    "content": "<?php\n\nnamespace Codecasts\\Auth\\JWT;\n\nuse Illuminate\\Contracts\\Config\\Repository;\nuse Illuminate\\Routing\\Events\\RouteMatched;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\ServiceProvider as LaravelServiceProvider;\nuse Codecasts\\Auth\\JWT\\Auth\\Guard;\nuse Codecasts\\Auth\\JWT\\Console\\KeyGenerateCommand;\nuse Codecasts\\Auth\\JWT\\Contracts;\nuse Codecasts\\Auth\\JWT\\Token\\Manager;\nuse Codecasts\\Auth\\JWT\\Auth\\ServiceProvider as AuthServiceProvider;\n\n/**\n * Codecasts JWT Auth for Laravel 5.4\n *\n * Main Service provider.\n */\nclass ServiceProvider extends LaravelServiceProvider\n{\n    /**\n     * Yes, the base class already has $defer as false.\n     * But in case the Laravel API changes that in the future,\n     * this attribute makes sure that this provider cannot be deferred.\n     *\n     * @var bool\n     */\n    protected $defer = false;\n\n    /**\n     * Boots the Service provider.\n     */\n    public function boot()\n    {\n        // declare the configuration files available for publishing.\n        $this->publishes([\n            __DIR__.'/../config/jwt.php' => config_path('jwt.php')\n        ]);\n\n        // case enabled, setups a guard match by middleware group name.\n        $this->setupGuardMiddlewareMatch();\n    }\n\n\n    public function register()\n    {\n        // register contract/concrete bindings.\n        $this->registerBindings();\n\n        // register commands.\n        $this->registerCommands();\n\n        // register the \"auth\" service provider.\n        // this is needed in order because that service\n        // provider needs to inherit from the Laravel\n        // default service provider, which register policies\n        // and other resources that are not possible (at least harder)\n        // to do in a common service provider.\n        $this->app->register(AuthServiceProvider::class);\n    }\n\n    /**\n     * Binds Contracts (interfaces) and Concretes (implementations) together.\n     */\n    protected function registerBindings()\n    {\n        // bind the manager class.\n        $this->app->bind(Contracts\\Token\\Manager::class, Manager::class);\n\n        // bind the guard class.\n        $this->app->bind(Contracts\\Auth\\Guard::class, Guard::class);\n    }\n\n    /**\n     * Register console commands this package provides.\n     */\n    protected function registerCommands()\n    {\n        $this->commands([\n            // \"jwt:generate\" command (generates keys).\n            KeyGenerateCommand::class,\n        ]);\n    }\n\n    /**\n     * Setup the current guard to be matched by route middleware name.\n     */\n    protected function setupGuardMiddlewareMatch()\n    {\n        // should the middleware group match the guard name?\n        $middlewareMatch = $this->app['config']->get('jwt.middleware_match', true);\n\n        if ($middlewareMatch) {\n            // when the route is actually matched...\n            $this->app['router']->matched(function (RouteMatched $event) {\n\n                // get the route middleware group.\n                $middlewareGroup = Arr::first((array) $event->route->middleware());\n\n                // if there is a group detected and  there is a guard that matches the middleware\n                // group name...\n                if ($middlewareGroup && !!$this->app['auth']->guard($middlewareGroup)) {\n                    // setup the matching guard as default.\n                    $this->app['auth']->setDefaultDriver($middlewareGroup);\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Token/Manager.php",
    "content": "<?php\n\nnamespace Codecasts\\Auth\\JWT\\Token;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Contracts\\Auth\\Authenticatable;\nuse Illuminate\\Config\\Repository as Config;\nuse Illuminate\\Cache\\Repository as Cache;\nuse Illuminate\\Support\\Str;\nuse Codecasts\\Auth\\JWT\\Contracts\\Token\\Manager as ManagerContract;\nuse Lcobucci\\JWT\\Builder;\nuse Lcobucci\\JWT\\Parser;\nuse Lcobucci\\JWT\\Signer\\Hmac\\Sha256;\nuse Lcobucci\\JWT\\Token;\n\n/**\n * JWT Token Manager.\n */\nclass Manager implements ManagerContract\n{\n    /**\n     * @var \\Illuminate\\Config\\Repository\n     */\n    protected $config;\n\n    /**\n     * @var \\Illuminate\\Cache\\Repository\n     */\n    protected $cache;\n\n    /**\n     * JWT Issuer (API Hostname).\n     *\n     * @var String\n     */\n    protected $issuer;\n\n    /**\n     * Secret that will be used to sign tokens.\n     *\n     * @var string\n     */\n    protected $secret = null;\n\n    /**\n     * Token time to live (TTL, in minutes).\n     *\n     * @var int\n     */\n    protected $ttl = 60;\n\n    /**\n     * Refresh after expired limit (in minutes).\n     *\n     * @var int\n     */\n    protected $refreshLimit = 7200;\n\n    /**\n     * JWT Builder.\n     *\n     * @var \\Lcobucci\\JWT\\Builder\n     */\n    protected $builderClass = Builder::class;\n\n    /**\n     * JWT Parser Class.\n     *\n     * @var \\Lcobucci\\JWT\\Parser\n     */\n    protected $parserClass = Parser::class;\n\n    /**\n     * JWT HMAC-SHA256 Signer.\n     *\n     * @var \\Lcobucci\\JWT\\Signer\\Hmac\\Sha256\n     */\n    protected $signerClass = Sha256::class;\n\n    /**\n     * Token Manager constructor.\n     *\n     * @param \\Illuminate\\Config\\Repository  $config\n     * @param \\Illuminate\\Cache\\Repository   $cache\n     */\n    public function __construct(Config $config, Cache $cache)\n    {\n        // setup repositories.\n        $this->config = $config; //config repository.\n        $this->cache = $cache;   // cache repository.\n\n        // setup the secret that will be used to sign keys.\n        $this->setupSecret();\n\n        // setup other config resources.\n        $this->setupConfig();\n    }\n\n    /**\n     * Setup the secret that will be used to sign keys.\n     */\n    public function setupSecret()\n    {\n        // gets the key from config.\n        $secret = $this->config->get('jwt.secret');\n\n        // if the secret is in a base64 format, unwrap it's value\n        if (Str::startsWith($secret, 'base64:')) {\n            // remove the 'base64:' part and decode the value.\n            $secret = base64_decode(substr($secret, 7));\n        }\n\n        // set the secret on the local scope.\n        $this->secret = $secret;\n\n        // if the secret is not valid,\n        // throw an exception to avoid continuing.\n        if (!$this->validSecret()) {\n            throw new \\Exception('Invalid Secret (not present or too short). Use php artisan jwt:generate to create a valid key.');\n        }\n    }\n\n    /**\n     * Determines if the current secret is valid and secure enough.\n     * Of course it will only check for size since there's no way\n     * (that I know of) of check if a value is really random.\n     *\n     * @return bool\n     */\n    protected function validSecret()\n    {\n        // this method is intentionally broken in two pieces\n        // so the logic will be loud and clear.\n\n        // is the secret empty?\n        if (empty($this->secret)) {\n            return false;\n        }\n\n        // created a hex representation of the secret.\n        $hexRepresentation = bin2hex($this->secret);\n\n        // check for the secret's hex representation length...\n        // hex size is deterministic, it's a way of counting bytes from binary\n        // ( SORT OF)\n        // in any case, the length will double of the binary random generated secret.\n        // 16 bytes secret will have a hex of length 32\n        // 32 bytes secret will have a hex of length 64\n        // 64 bytes secret will have a hex of length 128\n        // you get it right?\n        if ((Str::length($hexRepresentation) / 2) < 16) {\n            // the minimum secret size should be 16\n            // so return false in case the secret\n            // is shorter than that.\n            return false;\n        }\n\n        // after all this checks, declare the secret valid (finally).\n        return true;\n    }\n\n    /**\n     * Setup JWT configuration.\n     */\n    protected function setupConfig()\n    {\n        // setup time to live (in minutes), defaults to 60.\n        $this->ttl = $this->config->get('jwt.ttl', 60);\n\n        // setup refresh limit (in minutes), defaults to 7200 (5 days)\n        $this->refreshLimit = $this->config->get('jwt.refresh_limit', 7200);\n\n        // set the token issuer (domain name).\n        $this->issuer = url('');\n    }\n\n    /**\n     * Returns a new Signer instance.\n     *\n     * @return Sha256\n     */\n    protected function signer()\n    {\n        return app()->make($this->signerClass);\n    }\n\n    /**\n     * Returns a new Builder instance.\n     *\n     * @return Builder\n     */\n    protected function builder()\n    {\n        return app()->make($this->builderClass);\n    }\n\n    /**\n     * Returns a new Parser instance.\n     *\n     * @return Parser\n     */\n    protected function parser()\n    {\n        return app()->make($this->parserClass);\n    }\n\n    /**\n     * Create a carbon object with current time and date.\n     * @return Carbon\n     */\n    protected function now()\n    {\n        return Carbon::now('UTC');\n    }\n\n    /**\n     * Generates a random short ID to be used as the token id.\n     *\n     * This id is actually used only for blacklisting the tokens, not need for\n     * additional security.\n     *\n     * @return string\n     */\n    protected function generateId()\n    {\n        return Str::random(16);\n    }\n\n    /**\n     * @param Authenticatable $user\n     * @param array $additionalCustomClaims\n     *\n     * @return string\n     */\n    public function issue(Authenticatable $user, array $additionalCustomClaims = [])\n    {\n        // gets a new builder instance.\n        $builder = $this->builder();\n\n        // set the issued\n        $builder->setIssuer($this->issuer);\n\n        // set the subject.\n        $builder->setSubject($user->getAuthIdentifier());\n\n        // generate a unique id for the token, and set it to replicate as a header.\n        $builder->setId($this->generateId(), true);\n\n        // detect what time is it.\n        $now = $this->now();\n\n        // set issue date.\n        $builder->setIssuedAt($now->timestamp);\n\n        // set the token cannot be used before now.\n        $builder->setNotBefore($now->timestamp);\n\n        // calculate and set the expiration date for the token.\n        $expiresAt = (clone $now)->addMinutes($this->ttl);\n        $builder->setExpiration($expiresAt->timestamp);\n\n        // created a custom claim that informs the limit time\n        // for the token to be renewed.\n        // the refresh limit is based on ttl + limit (grace period).\n        $refreshLimit = (clone $now)->addMinutes($this->ttl + $this->refreshLimit);\n        $builder->set('rli', $refreshLimit->timestamp);\n\n        // loop through custom claims.\n        foreach($additionalCustomClaims as $claim => $value) {\n            // set custom claim.\n            $builder->set($claim, $value);\n        }\n\n        // set user object default custom claims.\n        if (method_exists($user, 'customJWTClaims')) {\n            // call the methods.\n            try {\n                // call the custom claims method.\n                $customClaims = (array) $user->customJWTClaims();\n\n                // if the custom claims method returns a array.\n                foreach($customClaims as $claim => $value) {\n                    $builder->set($claim, $value);\n                }\n            } catch(\\Exception $e) {\n                // just continue since the custom claims should\n                // not prevent the token of being issued.\n            }\n        }\n\n        // get the signer.\n        $signer = $this->signer();\n\n        // sign the configure token.\n        $builder->sign($signer, $this->secret);\n\n        // gets the actual signed token as string.\n        $token = (string) $builder->getToken();\n\n        // returns the token.\n        return $token;\n    }\n\n    /**\n     * Verify the signature of a given token object.\n     *\n     * @param Token $token\n     * @return bool\n     */\n    protected function verify(Token $token)\n    {\n        // the verification is made against the secret key.\n        // this will not check of expiration, only for signature checking.\n        return $token->verify($this->signer(), $this->secret);\n    }\n\n    /**\n     * Method for parsing a token from a string.\n     *\n     * @param string $tokenString\n     *\n     * @return Token\n     */\n    public function parseToken(string $tokenString)\n    {\n        // try to parse a token string.\n        try {\n            return $this->parser()->parse($tokenString);\n        } catch (\\Exception $e) {\n            // if it was not possible to, return null.\n            return null;\n        }\n    }\n\n    /**\n     * Detects if a given token is valid or not.\n     *\n     * @param Token $token\n     *\n     * @return bool\n     */\n    public function validToken(Token $token)\n    {\n        return $this->verify($token);\n    }\n\n    /**\n     * Detects if a given token is Invalid.\n     *\n     * @param Token $token\n     * @return bool\n     */\n    public function invalidToken(Token $token)\n    {\n        return !$this->validToken($token);\n    }\n\n    /**\n     * Is the token Expired?\n     *\n     * @param Token $token\n     * @return bool\n     */\n    public function expired(Token $token)\n    {\n        return $token->isExpired();\n    }\n\n    /**\n     * Is the token Expired?\n     *\n     * @param Token $token\n     * @return bool\n     */\n    public function canBeRenewed(Token $token)\n    {\n        if(!$token->isExpired()) {\n            return true;\n        }\n\n        // get the renewal limit from token.\n        $renewalLimitTimestamp = $token->getClaim('rli', null);\n\n        // if no renewal limit exists, it means\n        // that it should not be renewed.\n        if (!$renewalLimitTimestamp) {\n            return false;\n        }\n\n        // created a UTC carbon object using the renewal limit.\n        $limit = Carbon::createFromTimestampUTC($renewalLimitTimestamp);\n\n        // get a UTC carbon object that represents now.\n        $now = $this->now();\n\n        // return true if now if before the limit.\n        return $now->lessThanOrEqualTo($limit);\n    }\n}\n"
  },
  {
    "path": "tests/Auth/GuardTest.php",
    "content": "<?php\n\nnamespace Tests\\Auth\\Guard;\n\nuse Tests\\TestCase;\n\nclass GuardTest extends TestCase\n{\n\n}\n"
  },
  {
    "path": "tests/TestCase.php",
    "content": "<?php\n\nnamespace Tests;\n\nuse Codecasts\\Auth\\JWT\\ServiceProvider;\n\nclass TestCase extends \\Orchestra\\Testbench\\TestCase\n{\n    public function getPackageProviders()\n    {\n        return [ServiceProvider::class, AuthService::class];\n    }\n}\n"
  }
]